1*0b57cec5SDimitry Andric //===----- BPFMISimplifyPatchable.cpp - MI Simplify Patchable Insts -------===// 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 pass targets a subset of instructions like below 10*0b57cec5SDimitry Andric // ld_imm64 r1, @global 11*0b57cec5SDimitry Andric // ldd r2, r1, 0 12*0b57cec5SDimitry Andric // add r3, struct_base_reg, r2 13*0b57cec5SDimitry Andric // 14*0b57cec5SDimitry Andric // Here @global should either present a AMA (abstruct member access) or 15*0b57cec5SDimitry Andric // a patchable extern variable. And these two kinds of accesses 16*0b57cec5SDimitry Andric // are subject to bpf load time patching. After this pass, the 17*0b57cec5SDimitry Andric // code becomes 18*0b57cec5SDimitry Andric // ld_imm64 r1, @global 19*0b57cec5SDimitry Andric // add r3, struct_base_reg, r1 20*0b57cec5SDimitry Andric // 21*0b57cec5SDimitry Andric // Eventually, at BTF output stage, a relocation record will be generated 22*0b57cec5SDimitry Andric // for ld_imm64 which should be replaced later by bpf loader: 23*0b57cec5SDimitry Andric // r1 = <calculated offset> or <to_be_patched_extern_val> 24*0b57cec5SDimitry Andric // add r3, struct_base_reg, r1 25*0b57cec5SDimitry Andric // or 26*0b57cec5SDimitry Andric // ld_imm64 r1, <to_be_patched_extern_val> 27*0b57cec5SDimitry Andric // add r3, struct_base_reg, r1 28*0b57cec5SDimitry Andric // 29*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 30*0b57cec5SDimitry Andric 31*0b57cec5SDimitry Andric #include "BPF.h" 32*0b57cec5SDimitry Andric #include "BPFCORE.h" 33*0b57cec5SDimitry Andric #include "BPFInstrInfo.h" 34*0b57cec5SDimitry Andric #include "BPFTargetMachine.h" 35*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 36*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric using namespace llvm; 39*0b57cec5SDimitry Andric 40*0b57cec5SDimitry Andric #define DEBUG_TYPE "bpf-mi-simplify-patchable" 41*0b57cec5SDimitry Andric 42*0b57cec5SDimitry Andric namespace { 43*0b57cec5SDimitry Andric 44*0b57cec5SDimitry Andric struct BPFMISimplifyPatchable : public MachineFunctionPass { 45*0b57cec5SDimitry Andric 46*0b57cec5SDimitry Andric static char ID; 47*0b57cec5SDimitry Andric const BPFInstrInfo *TII; 48*0b57cec5SDimitry Andric MachineFunction *MF; 49*0b57cec5SDimitry Andric 50*0b57cec5SDimitry Andric BPFMISimplifyPatchable() : MachineFunctionPass(ID) { 51*0b57cec5SDimitry Andric initializeBPFMISimplifyPatchablePass(*PassRegistry::getPassRegistry()); 52*0b57cec5SDimitry Andric } 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric private: 55*0b57cec5SDimitry Andric // Initialize class variables. 56*0b57cec5SDimitry Andric void initialize(MachineFunction &MFParm); 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric bool removeLD(void); 59*0b57cec5SDimitry Andric 60*0b57cec5SDimitry Andric public: 61*0b57cec5SDimitry Andric // Main entry point for this pass. 62*0b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 63*0b57cec5SDimitry Andric if (!skipFunction(MF.getFunction())) { 64*0b57cec5SDimitry Andric initialize(MF); 65*0b57cec5SDimitry Andric } 66*0b57cec5SDimitry Andric return removeLD(); 67*0b57cec5SDimitry Andric } 68*0b57cec5SDimitry Andric }; 69*0b57cec5SDimitry Andric 70*0b57cec5SDimitry Andric // Initialize class variables. 71*0b57cec5SDimitry Andric void BPFMISimplifyPatchable::initialize(MachineFunction &MFParm) { 72*0b57cec5SDimitry Andric MF = &MFParm; 73*0b57cec5SDimitry Andric TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo(); 74*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "*** BPF simplify patchable insts pass ***\n\n"); 75*0b57cec5SDimitry Andric } 76*0b57cec5SDimitry Andric 77*0b57cec5SDimitry Andric /// Remove unneeded Load instructions. 78*0b57cec5SDimitry Andric bool BPFMISimplifyPatchable::removeLD() { 79*0b57cec5SDimitry Andric MachineRegisterInfo *MRI = &MF->getRegInfo(); 80*0b57cec5SDimitry Andric MachineInstr *ToErase = nullptr; 81*0b57cec5SDimitry Andric bool Changed = false; 82*0b57cec5SDimitry Andric 83*0b57cec5SDimitry Andric for (MachineBasicBlock &MBB : *MF) { 84*0b57cec5SDimitry Andric for (MachineInstr &MI : MBB) { 85*0b57cec5SDimitry Andric if (ToErase) { 86*0b57cec5SDimitry Andric ToErase->eraseFromParent(); 87*0b57cec5SDimitry Andric ToErase = nullptr; 88*0b57cec5SDimitry Andric } 89*0b57cec5SDimitry Andric 90*0b57cec5SDimitry Andric // Ensure the register format is LOAD <reg>, <reg>, 0 91*0b57cec5SDimitry Andric if (MI.getOpcode() != BPF::LDD && MI.getOpcode() != BPF::LDW && 92*0b57cec5SDimitry Andric MI.getOpcode() != BPF::LDH && MI.getOpcode() != BPF::LDB && 93*0b57cec5SDimitry Andric MI.getOpcode() != BPF::LDW32 && MI.getOpcode() != BPF::LDH32 && 94*0b57cec5SDimitry Andric MI.getOpcode() != BPF::LDB32) 95*0b57cec5SDimitry Andric continue; 96*0b57cec5SDimitry Andric 97*0b57cec5SDimitry Andric if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg()) 98*0b57cec5SDimitry Andric continue; 99*0b57cec5SDimitry Andric 100*0b57cec5SDimitry Andric if (!MI.getOperand(2).isImm() || MI.getOperand(2).getImm()) 101*0b57cec5SDimitry Andric continue; 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric unsigned DstReg = MI.getOperand(0).getReg(); 104*0b57cec5SDimitry Andric unsigned SrcReg = MI.getOperand(1).getReg(); 105*0b57cec5SDimitry Andric int64_t ImmVal = MI.getOperand(2).getImm(); 106*0b57cec5SDimitry Andric 107*0b57cec5SDimitry Andric MachineInstr *DefInst = MRI->getUniqueVRegDef(SrcReg); 108*0b57cec5SDimitry Andric if (!DefInst) 109*0b57cec5SDimitry Andric continue; 110*0b57cec5SDimitry Andric 111*0b57cec5SDimitry Andric bool IsCandidate = false; 112*0b57cec5SDimitry Andric if (DefInst->getOpcode() == BPF::LD_imm64) { 113*0b57cec5SDimitry Andric const MachineOperand &MO = DefInst->getOperand(1); 114*0b57cec5SDimitry Andric if (MO.isGlobal()) { 115*0b57cec5SDimitry Andric const GlobalValue *GVal = MO.getGlobal(); 116*0b57cec5SDimitry Andric auto *GVar = dyn_cast<GlobalVariable>(GVal); 117*0b57cec5SDimitry Andric if (GVar) { 118*0b57cec5SDimitry Andric // Global variables representing structure offset or 119*0b57cec5SDimitry Andric // patchable extern globals. 120*0b57cec5SDimitry Andric if (GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) { 121*0b57cec5SDimitry Andric assert(ImmVal == 0); 122*0b57cec5SDimitry Andric IsCandidate = true; 123*0b57cec5SDimitry Andric } else if (!GVar->hasInitializer() && GVar->hasExternalLinkage() && 124*0b57cec5SDimitry Andric GVar->getSection() == 125*0b57cec5SDimitry Andric BPFCoreSharedInfo::PatchableExtSecName) { 126*0b57cec5SDimitry Andric if (ImmVal == 0) 127*0b57cec5SDimitry Andric IsCandidate = true; 128*0b57cec5SDimitry Andric else 129*0b57cec5SDimitry Andric errs() << "WARNING: unhandled patchable extern " 130*0b57cec5SDimitry Andric << GVar->getName() << " with load offset " << ImmVal 131*0b57cec5SDimitry Andric << "\n"; 132*0b57cec5SDimitry Andric } 133*0b57cec5SDimitry Andric } 134*0b57cec5SDimitry Andric } 135*0b57cec5SDimitry Andric } 136*0b57cec5SDimitry Andric 137*0b57cec5SDimitry Andric if (!IsCandidate) 138*0b57cec5SDimitry Andric continue; 139*0b57cec5SDimitry Andric 140*0b57cec5SDimitry Andric auto Begin = MRI->use_begin(DstReg), End = MRI->use_end(); 141*0b57cec5SDimitry Andric decltype(End) NextI; 142*0b57cec5SDimitry Andric for (auto I = Begin; I != End; I = NextI) { 143*0b57cec5SDimitry Andric NextI = std::next(I); 144*0b57cec5SDimitry Andric I->setReg(SrcReg); 145*0b57cec5SDimitry Andric } 146*0b57cec5SDimitry Andric 147*0b57cec5SDimitry Andric ToErase = &MI; 148*0b57cec5SDimitry Andric Changed = true; 149*0b57cec5SDimitry Andric } 150*0b57cec5SDimitry Andric } 151*0b57cec5SDimitry Andric 152*0b57cec5SDimitry Andric return Changed; 153*0b57cec5SDimitry Andric } 154*0b57cec5SDimitry Andric 155*0b57cec5SDimitry Andric } // namespace 156*0b57cec5SDimitry Andric 157*0b57cec5SDimitry Andric INITIALIZE_PASS(BPFMISimplifyPatchable, DEBUG_TYPE, 158*0b57cec5SDimitry Andric "BPF PreEmit SimplifyPatchable", false, false) 159*0b57cec5SDimitry Andric 160*0b57cec5SDimitry Andric char BPFMISimplifyPatchable::ID = 0; 161*0b57cec5SDimitry Andric FunctionPass *llvm::createBPFMISimplifyPatchablePass() { 162*0b57cec5SDimitry Andric return new BPFMISimplifyPatchable(); 163*0b57cec5SDimitry Andric } 164