1e4c8c807SAlexei Starovoitov //===-- BPFInstrInfo.cpp - BPF Instruction Information ----------*- C++ -*-===//
2e4c8c807SAlexei Starovoitov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e4c8c807SAlexei Starovoitov //
7e4c8c807SAlexei Starovoitov //===----------------------------------------------------------------------===//
8e4c8c807SAlexei Starovoitov //
9e4c8c807SAlexei Starovoitov // This file contains the BPF implementation of the TargetInstrInfo class.
10e4c8c807SAlexei Starovoitov //
11e4c8c807SAlexei Starovoitov //===----------------------------------------------------------------------===//
12e4c8c807SAlexei Starovoitov 
13e4c8c807SAlexei Starovoitov #include "BPFInstrInfo.h"
146bda14b3SChandler Carruth #include "BPF.h"
15e4c8c807SAlexei Starovoitov #include "llvm/ADT/SmallVector.h"
164282c404SEugene Zelenko #include "llvm/CodeGen/MachineBasicBlock.h"
174282c404SEugene Zelenko #include "llvm/CodeGen/MachineInstrBuilder.h"
184282c404SEugene Zelenko #include "llvm/IR/DebugLoc.h"
194282c404SEugene Zelenko #include "llvm/Support/ErrorHandling.h"
204282c404SEugene Zelenko #include <cassert>
214282c404SEugene Zelenko #include <iterator>
22e4c8c807SAlexei Starovoitov 
23e4c8c807SAlexei Starovoitov #define GET_INSTRINFO_CTOR_DTOR
24e4c8c807SAlexei Starovoitov #include "BPFGenInstrInfo.inc"
25e4c8c807SAlexei Starovoitov 
26e4c8c807SAlexei Starovoitov using namespace llvm;
27e4c8c807SAlexei Starovoitov 
BPFInstrInfo()28e4c8c807SAlexei Starovoitov BPFInstrInfo::BPFInstrInfo()
29e4c8c807SAlexei Starovoitov     : BPFGenInstrInfo(BPF::ADJCALLSTACKDOWN, BPF::ADJCALLSTACKUP) {}
30e4c8c807SAlexei Starovoitov 
copyPhysReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,const DebugLoc & DL,MCRegister DestReg,MCRegister SrcReg,bool KillSrc) const31e4c8c807SAlexei Starovoitov void BPFInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
32bdc4956bSBenjamin Kramer                                MachineBasicBlock::iterator I,
33e6c9a9afSMatt Arsenault                                const DebugLoc &DL, MCRegister DestReg,
34e6c9a9afSMatt Arsenault                                MCRegister SrcReg, bool KillSrc) const {
35e4c8c807SAlexei Starovoitov   if (BPF::GPRRegClass.contains(DestReg, SrcReg))
36e4c8c807SAlexei Starovoitov     BuildMI(MBB, I, DL, get(BPF::MOV_rr), DestReg)
37e4c8c807SAlexei Starovoitov         .addReg(SrcReg, getKillRegState(KillSrc));
38fcd1e0f6SYonghong Song   else if (BPF::GPR32RegClass.contains(DestReg, SrcReg))
39fcd1e0f6SYonghong Song     BuildMI(MBB, I, DL, get(BPF::MOV_rr_32), DestReg)
40fcd1e0f6SYonghong Song         .addReg(SrcReg, getKillRegState(KillSrc));
41e4c8c807SAlexei Starovoitov   else
42e4c8c807SAlexei Starovoitov     llvm_unreachable("Impossible reg-to-reg copy");
43e4c8c807SAlexei Starovoitov }
44e4c8c807SAlexei Starovoitov 
expandMEMCPY(MachineBasicBlock::iterator MI) const4571d81e5cSYonghong Song void BPFInstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const {
460c476111SDaniel Sanders   Register DstReg = MI->getOperand(0).getReg();
470c476111SDaniel Sanders   Register SrcReg = MI->getOperand(1).getReg();
4871d81e5cSYonghong Song   uint64_t CopyLen = MI->getOperand(2).getImm();
4971d81e5cSYonghong Song   uint64_t Alignment = MI->getOperand(3).getImm();
500c476111SDaniel Sanders   Register ScratchReg = MI->getOperand(4).getReg();
5171d81e5cSYonghong Song   MachineBasicBlock *BB = MI->getParent();
5271d81e5cSYonghong Song   DebugLoc dl = MI->getDebugLoc();
5371d81e5cSYonghong Song   unsigned LdOpc, StOpc;
5471d81e5cSYonghong Song 
5571d81e5cSYonghong Song   switch (Alignment) {
5671d81e5cSYonghong Song   case 1:
5771d81e5cSYonghong Song     LdOpc = BPF::LDB;
5871d81e5cSYonghong Song     StOpc = BPF::STB;
5971d81e5cSYonghong Song     break;
6071d81e5cSYonghong Song   case 2:
6171d81e5cSYonghong Song     LdOpc = BPF::LDH;
6271d81e5cSYonghong Song     StOpc = BPF::STH;
6371d81e5cSYonghong Song     break;
6471d81e5cSYonghong Song   case 4:
6571d81e5cSYonghong Song     LdOpc = BPF::LDW;
6671d81e5cSYonghong Song     StOpc = BPF::STW;
6771d81e5cSYonghong Song     break;
6871d81e5cSYonghong Song   case 8:
6971d81e5cSYonghong Song     LdOpc = BPF::LDD;
7071d81e5cSYonghong Song     StOpc = BPF::STD;
7171d81e5cSYonghong Song     break;
7271d81e5cSYonghong Song   default:
7371d81e5cSYonghong Song     llvm_unreachable("unsupported memcpy alignment");
7471d81e5cSYonghong Song   }
7571d81e5cSYonghong Song 
7671d81e5cSYonghong Song   unsigned IterationNum = CopyLen >> Log2_64(Alignment);
7771d81e5cSYonghong Song   for(unsigned I = 0; I < IterationNum; ++I) {
7871d81e5cSYonghong Song     BuildMI(*BB, MI, dl, get(LdOpc))
7904ccfda0SYonghong Song             .addReg(ScratchReg, RegState::Define).addReg(SrcReg)
8004ccfda0SYonghong Song             .addImm(I * Alignment);
8171d81e5cSYonghong Song     BuildMI(*BB, MI, dl, get(StOpc))
8204ccfda0SYonghong Song             .addReg(ScratchReg, RegState::Kill).addReg(DstReg)
8304ccfda0SYonghong Song             .addImm(I * Alignment);
8471d81e5cSYonghong Song   }
8571d81e5cSYonghong Song 
8671d81e5cSYonghong Song   unsigned BytesLeft = CopyLen & (Alignment - 1);
8771d81e5cSYonghong Song   unsigned Offset = IterationNum * Alignment;
8871d81e5cSYonghong Song   bool Hanging4Byte = BytesLeft & 0x4;
8971d81e5cSYonghong Song   bool Hanging2Byte = BytesLeft & 0x2;
9071d81e5cSYonghong Song   bool Hanging1Byte = BytesLeft & 0x1;
9171d81e5cSYonghong Song   if (Hanging4Byte) {
9271d81e5cSYonghong Song     BuildMI(*BB, MI, dl, get(BPF::LDW))
9304ccfda0SYonghong Song             .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset);
9471d81e5cSYonghong Song     BuildMI(*BB, MI, dl, get(BPF::STW))
9504ccfda0SYonghong Song             .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset);
9671d81e5cSYonghong Song     Offset += 4;
9771d81e5cSYonghong Song   }
9871d81e5cSYonghong Song   if (Hanging2Byte) {
9971d81e5cSYonghong Song     BuildMI(*BB, MI, dl, get(BPF::LDH))
10004ccfda0SYonghong Song             .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset);
10171d81e5cSYonghong Song     BuildMI(*BB, MI, dl, get(BPF::STH))
10204ccfda0SYonghong Song             .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset);
10371d81e5cSYonghong Song     Offset += 2;
10471d81e5cSYonghong Song   }
10571d81e5cSYonghong Song   if (Hanging1Byte) {
10671d81e5cSYonghong Song     BuildMI(*BB, MI, dl, get(BPF::LDB))
10704ccfda0SYonghong Song             .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset);
10871d81e5cSYonghong Song     BuildMI(*BB, MI, dl, get(BPF::STB))
10904ccfda0SYonghong Song             .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset);
11071d81e5cSYonghong Song   }
11171d81e5cSYonghong Song 
11271d81e5cSYonghong Song   BB->erase(MI);
11371d81e5cSYonghong Song }
11471d81e5cSYonghong Song 
expandPostRAPseudo(MachineInstr & MI) const11571d81e5cSYonghong Song bool BPFInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
11671d81e5cSYonghong Song   if (MI.getOpcode() == BPF::MEMCPY) {
11771d81e5cSYonghong Song     expandMEMCPY(MI);
11871d81e5cSYonghong Song     return true;
11971d81e5cSYonghong Song   }
12071d81e5cSYonghong Song 
12171d81e5cSYonghong Song   return false;
12271d81e5cSYonghong Song }
12371d81e5cSYonghong Song 
storeRegToStackSlot(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,Register SrcReg,bool IsKill,int FI,const TargetRegisterClass * RC,const TargetRegisterInfo * TRI) const124e4c8c807SAlexei Starovoitov void BPFInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
125e4c8c807SAlexei Starovoitov                                        MachineBasicBlock::iterator I,
1265c8ba508SSimon Moll                                        Register SrcReg, bool IsKill, int FI,
127e4c8c807SAlexei Starovoitov                                        const TargetRegisterClass *RC,
128e4c8c807SAlexei Starovoitov                                        const TargetRegisterInfo *TRI) const {
129e4c8c807SAlexei Starovoitov   DebugLoc DL;
130e4c8c807SAlexei Starovoitov   if (I != MBB.end())
131e4c8c807SAlexei Starovoitov     DL = I->getDebugLoc();
132e4c8c807SAlexei Starovoitov 
133e4c8c807SAlexei Starovoitov   if (RC == &BPF::GPRRegClass)
134e4c8c807SAlexei Starovoitov     BuildMI(MBB, I, DL, get(BPF::STD))
135e4c8c807SAlexei Starovoitov         .addReg(SrcReg, getKillRegState(IsKill))
136e4c8c807SAlexei Starovoitov         .addFrameIndex(FI)
137e4c8c807SAlexei Starovoitov         .addImm(0);
138fcd1e0f6SYonghong Song   else if (RC == &BPF::GPR32RegClass)
139fcd1e0f6SYonghong Song     BuildMI(MBB, I, DL, get(BPF::STW32))
140fcd1e0f6SYonghong Song         .addReg(SrcReg, getKillRegState(IsKill))
141fcd1e0f6SYonghong Song         .addFrameIndex(FI)
142fcd1e0f6SYonghong Song         .addImm(0);
143e4c8c807SAlexei Starovoitov   else
144e4c8c807SAlexei Starovoitov     llvm_unreachable("Can't store this register to stack slot");
145e4c8c807SAlexei Starovoitov }
146e4c8c807SAlexei Starovoitov 
loadRegFromStackSlot(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,Register DestReg,int FI,const TargetRegisterClass * RC,const TargetRegisterInfo * TRI) const147e4c8c807SAlexei Starovoitov void BPFInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
148e4c8c807SAlexei Starovoitov                                         MachineBasicBlock::iterator I,
1495c8ba508SSimon Moll                                         Register DestReg, int FI,
150e4c8c807SAlexei Starovoitov                                         const TargetRegisterClass *RC,
151e4c8c807SAlexei Starovoitov                                         const TargetRegisterInfo *TRI) const {
152e4c8c807SAlexei Starovoitov   DebugLoc DL;
153e4c8c807SAlexei Starovoitov   if (I != MBB.end())
154e4c8c807SAlexei Starovoitov     DL = I->getDebugLoc();
155e4c8c807SAlexei Starovoitov 
156e4c8c807SAlexei Starovoitov   if (RC == &BPF::GPRRegClass)
157e4c8c807SAlexei Starovoitov     BuildMI(MBB, I, DL, get(BPF::LDD), DestReg).addFrameIndex(FI).addImm(0);
158fcd1e0f6SYonghong Song   else if (RC == &BPF::GPR32RegClass)
159fcd1e0f6SYonghong Song     BuildMI(MBB, I, DL, get(BPF::LDW32), DestReg).addFrameIndex(FI).addImm(0);
160e4c8c807SAlexei Starovoitov   else
161e4c8c807SAlexei Starovoitov     llvm_unreachable("Can't load this register from stack slot");
162e4c8c807SAlexei Starovoitov }
163e4c8c807SAlexei Starovoitov 
analyzeBranch(MachineBasicBlock & MBB,MachineBasicBlock * & TBB,MachineBasicBlock * & FBB,SmallVectorImpl<MachineOperand> & Cond,bool AllowModify) const16471c30a14SJacques Pienaar bool BPFInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
165e4c8c807SAlexei Starovoitov                                  MachineBasicBlock *&TBB,
166e4c8c807SAlexei Starovoitov                                  MachineBasicBlock *&FBB,
167e4c8c807SAlexei Starovoitov                                  SmallVectorImpl<MachineOperand> &Cond,
168e4c8c807SAlexei Starovoitov                                  bool AllowModify) const {
169e4c8c807SAlexei Starovoitov   // Start from the bottom of the block and work up, examining the
170e4c8c807SAlexei Starovoitov   // terminator instructions.
171e4c8c807SAlexei Starovoitov   MachineBasicBlock::iterator I = MBB.end();
172e4c8c807SAlexei Starovoitov   while (I != MBB.begin()) {
173e4c8c807SAlexei Starovoitov     --I;
174801bf7ebSShiva Chen     if (I->isDebugInstr())
175e4c8c807SAlexei Starovoitov       continue;
176e4c8c807SAlexei Starovoitov 
177e4c8c807SAlexei Starovoitov     // Working from the bottom, when we see a non-terminator
178e4c8c807SAlexei Starovoitov     // instruction, we're done.
1796307eb55SDuncan P. N. Exon Smith     if (!isUnpredicatedTerminator(*I))
180e4c8c807SAlexei Starovoitov       break;
181e4c8c807SAlexei Starovoitov 
182e4c8c807SAlexei Starovoitov     // A terminator that isn't a branch can't easily be handled
183e4c8c807SAlexei Starovoitov     // by this analysis.
184e4c8c807SAlexei Starovoitov     if (!I->isBranch())
185e4c8c807SAlexei Starovoitov       return true;
186e4c8c807SAlexei Starovoitov 
187e4c8c807SAlexei Starovoitov     // Handle unconditional branches.
188e4c8c807SAlexei Starovoitov     if (I->getOpcode() == BPF::JMP) {
189e4c8c807SAlexei Starovoitov       if (!AllowModify) {
190e4c8c807SAlexei Starovoitov         TBB = I->getOperand(0).getMBB();
191e4c8c807SAlexei Starovoitov         continue;
192e4c8c807SAlexei Starovoitov       }
193e4c8c807SAlexei Starovoitov 
194e4c8c807SAlexei Starovoitov       // If the block has any instructions after a J, delete them.
195*9a8e65deSKazu Hirata       MBB.erase(std::next(I), MBB.end());
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 
insertBranch(MachineBasicBlock & MBB,MachineBasicBlock * TBB,MachineBasicBlock * FBB,ArrayRef<MachineOperand> Cond,const DebugLoc & DL,int * BytesAdded) const218e8e0f5caSMatt 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 
removeBranch(MachineBasicBlock & MBB,int * BytesRemoved) const2391b9fc8edSMatt 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