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