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