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