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