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