xref: /freebsd/contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrInfo.cpp (revision 6ba2210ee039f2f12878c217bcf058e9c8b26b29)
1 //===-- BPFInstrInfo.cpp - BPF Instruction Information ----------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains the BPF implementation of the TargetInstrInfo class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "BPFInstrInfo.h"
14 #include "BPF.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/CodeGen/MachineBasicBlock.h"
17 #include "llvm/CodeGen/MachineInstrBuilder.h"
18 #include "llvm/IR/DebugLoc.h"
19 #include "llvm/Support/ErrorHandling.h"
20 #include <cassert>
21 #include <iterator>
22 
23 #define GET_INSTRINFO_CTOR_DTOR
24 #include "BPFGenInstrInfo.inc"
25 
26 using namespace llvm;
27 
28 BPFInstrInfo::BPFInstrInfo()
29     : BPFGenInstrInfo(BPF::ADJCALLSTACKDOWN, BPF::ADJCALLSTACKUP) {}
30 
31 void BPFInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
32                                MachineBasicBlock::iterator I,
33                                const DebugLoc &DL, MCRegister DestReg,
34                                MCRegister SrcReg, bool KillSrc) const {
35   if (BPF::GPRRegClass.contains(DestReg, SrcReg))
36     BuildMI(MBB, I, DL, get(BPF::MOV_rr), DestReg)
37         .addReg(SrcReg, getKillRegState(KillSrc));
38   else if (BPF::GPR32RegClass.contains(DestReg, SrcReg))
39     BuildMI(MBB, I, DL, get(BPF::MOV_rr_32), DestReg)
40         .addReg(SrcReg, getKillRegState(KillSrc));
41   else
42     llvm_unreachable("Impossible reg-to-reg copy");
43 }
44 
45 void BPFInstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const {
46   Register DstReg = MI->getOperand(0).getReg();
47   Register SrcReg = MI->getOperand(1).getReg();
48   uint64_t CopyLen = MI->getOperand(2).getImm();
49   uint64_t Alignment = MI->getOperand(3).getImm();
50   Register ScratchReg = MI->getOperand(4).getReg();
51   MachineBasicBlock *BB = MI->getParent();
52   DebugLoc dl = MI->getDebugLoc();
53   unsigned LdOpc, StOpc;
54 
55   switch (Alignment) {
56   case 1:
57     LdOpc = BPF::LDB;
58     StOpc = BPF::STB;
59     break;
60   case 2:
61     LdOpc = BPF::LDH;
62     StOpc = BPF::STH;
63     break;
64   case 4:
65     LdOpc = BPF::LDW;
66     StOpc = BPF::STW;
67     break;
68   case 8:
69     LdOpc = BPF::LDD;
70     StOpc = BPF::STD;
71     break;
72   default:
73     llvm_unreachable("unsupported memcpy alignment");
74   }
75 
76   unsigned IterationNum = CopyLen >> Log2_64(Alignment);
77   for(unsigned I = 0; I < IterationNum; ++I) {
78     BuildMI(*BB, MI, dl, get(LdOpc))
79             .addReg(ScratchReg, RegState::Define).addReg(SrcReg)
80             .addImm(I * Alignment);
81     BuildMI(*BB, MI, dl, get(StOpc))
82             .addReg(ScratchReg, RegState::Kill).addReg(DstReg)
83             .addImm(I * Alignment);
84   }
85 
86   unsigned BytesLeft = CopyLen & (Alignment - 1);
87   unsigned Offset = IterationNum * Alignment;
88   bool Hanging4Byte = BytesLeft & 0x4;
89   bool Hanging2Byte = BytesLeft & 0x2;
90   bool Hanging1Byte = BytesLeft & 0x1;
91   if (Hanging4Byte) {
92     BuildMI(*BB, MI, dl, get(BPF::LDW))
93             .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset);
94     BuildMI(*BB, MI, dl, get(BPF::STW))
95             .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset);
96     Offset += 4;
97   }
98   if (Hanging2Byte) {
99     BuildMI(*BB, MI, dl, get(BPF::LDH))
100             .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset);
101     BuildMI(*BB, MI, dl, get(BPF::STH))
102             .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset);
103     Offset += 2;
104   }
105   if (Hanging1Byte) {
106     BuildMI(*BB, MI, dl, get(BPF::LDB))
107             .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset);
108     BuildMI(*BB, MI, dl, get(BPF::STB))
109             .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset);
110   }
111 
112   BB->erase(MI);
113 }
114 
115 bool BPFInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
116   if (MI.getOpcode() == BPF::MEMCPY) {
117     expandMEMCPY(MI);
118     return true;
119   }
120 
121   return false;
122 }
123 
124 void BPFInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
125                                        MachineBasicBlock::iterator I,
126                                        Register SrcReg, bool IsKill, int FI,
127                                        const TargetRegisterClass *RC,
128                                        const TargetRegisterInfo *TRI) const {
129   DebugLoc DL;
130   if (I != MBB.end())
131     DL = I->getDebugLoc();
132 
133   if (RC == &BPF::GPRRegClass)
134     BuildMI(MBB, I, DL, get(BPF::STD))
135         .addReg(SrcReg, getKillRegState(IsKill))
136         .addFrameIndex(FI)
137         .addImm(0);
138   else if (RC == &BPF::GPR32RegClass)
139     BuildMI(MBB, I, DL, get(BPF::STW32))
140         .addReg(SrcReg, getKillRegState(IsKill))
141         .addFrameIndex(FI)
142         .addImm(0);
143   else
144     llvm_unreachable("Can't store this register to stack slot");
145 }
146 
147 void BPFInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
148                                         MachineBasicBlock::iterator I,
149                                         Register DestReg, int FI,
150                                         const TargetRegisterClass *RC,
151                                         const TargetRegisterInfo *TRI) const {
152   DebugLoc DL;
153   if (I != MBB.end())
154     DL = I->getDebugLoc();
155 
156   if (RC == &BPF::GPRRegClass)
157     BuildMI(MBB, I, DL, get(BPF::LDD), DestReg).addFrameIndex(FI).addImm(0);
158   else if (RC == &BPF::GPR32RegClass)
159     BuildMI(MBB, I, DL, get(BPF::LDW32), DestReg).addFrameIndex(FI).addImm(0);
160   else
161     llvm_unreachable("Can't load this register from stack slot");
162 }
163 
164 bool BPFInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
165                                  MachineBasicBlock *&TBB,
166                                  MachineBasicBlock *&FBB,
167                                  SmallVectorImpl<MachineOperand> &Cond,
168                                  bool AllowModify) const {
169   // Start from the bottom of the block and work up, examining the
170   // terminator instructions.
171   MachineBasicBlock::iterator I = MBB.end();
172   while (I != MBB.begin()) {
173     --I;
174     if (I->isDebugInstr())
175       continue;
176 
177     // Working from the bottom, when we see a non-terminator
178     // instruction, we're done.
179     if (!isUnpredicatedTerminator(*I))
180       break;
181 
182     // A terminator that isn't a branch can't easily be handled
183     // by this analysis.
184     if (!I->isBranch())
185       return true;
186 
187     // Handle unconditional branches.
188     if (I->getOpcode() == BPF::JMP) {
189       if (!AllowModify) {
190         TBB = I->getOperand(0).getMBB();
191         continue;
192       }
193 
194       // If the block has any instructions after a J, delete them.
195       while (std::next(I) != MBB.end())
196         std::next(I)->eraseFromParent();
197       Cond.clear();
198       FBB = nullptr;
199 
200       // Delete the J if it's equivalent to a fall-through.
201       if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) {
202         TBB = nullptr;
203         I->eraseFromParent();
204         I = MBB.end();
205         continue;
206       }
207 
208       // TBB is used to indicate the unconditinal destination.
209       TBB = I->getOperand(0).getMBB();
210       continue;
211     }
212     // Cannot handle conditional branches
213     return true;
214   }
215 
216   return false;
217 }
218 
219 unsigned BPFInstrInfo::insertBranch(MachineBasicBlock &MBB,
220                                     MachineBasicBlock *TBB,
221                                     MachineBasicBlock *FBB,
222                                     ArrayRef<MachineOperand> Cond,
223                                     const DebugLoc &DL,
224                                     int *BytesAdded) const {
225   assert(!BytesAdded && "code size not handled");
226 
227   // Shouldn't be a fall through.
228   assert(TBB && "insertBranch must not be told to insert a fallthrough");
229 
230   if (Cond.empty()) {
231     // Unconditional branch
232     assert(!FBB && "Unconditional branch with multiple successors!");
233     BuildMI(&MBB, DL, get(BPF::JMP)).addMBB(TBB);
234     return 1;
235   }
236 
237   llvm_unreachable("Unexpected conditional branch");
238 }
239 
240 unsigned BPFInstrInfo::removeBranch(MachineBasicBlock &MBB,
241                                     int *BytesRemoved) const {
242   assert(!BytesRemoved && "code size not handled");
243 
244   MachineBasicBlock::iterator I = MBB.end();
245   unsigned Count = 0;
246 
247   while (I != MBB.begin()) {
248     --I;
249     if (I->isDebugInstr())
250       continue;
251     if (I->getOpcode() != BPF::JMP)
252       break;
253     // Remove the branch.
254     I->eraseFromParent();
255     I = MBB.end();
256     ++Count;
257   }
258 
259   return Count;
260 }
261