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