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