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 // This pass also removes the intermediate load generated in IR pass for 26 // __builtin_btf_type_id() intrinsic. 27 // 28 //===----------------------------------------------------------------------===// 29 30 #include "BPF.h" 31 #include "BPFCORE.h" 32 #include "BPFInstrInfo.h" 33 #include "BPFTargetMachine.h" 34 #include "llvm/CodeGen/MachineInstrBuilder.h" 35 #include "llvm/CodeGen/MachineRegisterInfo.h" 36 #include "llvm/Support/Debug.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(); 59 void processCandidate(MachineRegisterInfo *MRI, MachineBasicBlock &MBB, 60 MachineInstr &MI, Register &SrcReg, Register &DstReg, 61 const GlobalValue *GVal, bool IsAma); 62 void processDstReg(MachineRegisterInfo *MRI, Register &DstReg, 63 Register &SrcReg, const GlobalValue *GVal, 64 bool doSrcRegProp, bool IsAma); 65 void processInst(MachineRegisterInfo *MRI, MachineInstr *Inst, 66 MachineOperand *RelocOp, const GlobalValue *GVal); 67 void checkADDrr(MachineRegisterInfo *MRI, MachineOperand *RelocOp, 68 const GlobalValue *GVal); 69 void checkShift(MachineRegisterInfo *MRI, MachineBasicBlock &MBB, 70 MachineOperand *RelocOp, const GlobalValue *GVal, 71 unsigned Opcode); 72 73 public: 74 // Main entry point for this pass. 75 bool runOnMachineFunction(MachineFunction &MF) override { 76 if (skipFunction(MF.getFunction())) 77 return false; 78 79 initialize(MF); 80 return removeLD(); 81 } 82 }; 83 84 // Initialize class variables. 85 void BPFMISimplifyPatchable::initialize(MachineFunction &MFParm) { 86 MF = &MFParm; 87 TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo(); 88 LLVM_DEBUG(dbgs() << "*** BPF simplify patchable insts pass ***\n\n"); 89 } 90 91 void BPFMISimplifyPatchable::checkADDrr(MachineRegisterInfo *MRI, 92 MachineOperand *RelocOp, const GlobalValue *GVal) { 93 const MachineInstr *Inst = RelocOp->getParent(); 94 const MachineOperand *Op1 = &Inst->getOperand(1); 95 const MachineOperand *Op2 = &Inst->getOperand(2); 96 const MachineOperand *BaseOp = (RelocOp == Op1) ? Op2 : Op1; 97 98 // Go through all uses of %1 as in %1 = ADD_rr %2, %3 99 const MachineOperand Op0 = Inst->getOperand(0); 100 for (MachineOperand &MO : 101 llvm::make_early_inc_range(MRI->use_operands(Op0.getReg()))) { 102 // The candidate needs to have a unique definition. 103 if (!MRI->getUniqueVRegDef(MO.getReg())) 104 continue; 105 106 MachineInstr *DefInst = MO.getParent(); 107 unsigned Opcode = DefInst->getOpcode(); 108 unsigned COREOp; 109 if (Opcode == BPF::LDB || Opcode == BPF::LDH || Opcode == BPF::LDW || 110 Opcode == BPF::LDD || Opcode == BPF::STB || Opcode == BPF::STH || 111 Opcode == BPF::STW || Opcode == BPF::STD) 112 COREOp = BPF::CORE_MEM; 113 else if (Opcode == BPF::LDB32 || Opcode == BPF::LDH32 || 114 Opcode == BPF::LDW32 || Opcode == BPF::STB32 || 115 Opcode == BPF::STH32 || Opcode == BPF::STW32) 116 COREOp = BPF::CORE_ALU32_MEM; 117 else 118 continue; 119 120 // It must be a form of %2 = *(type *)(%1 + 0) or *(type *)(%1 + 0) = %2. 121 const MachineOperand &ImmOp = DefInst->getOperand(2); 122 if (!ImmOp.isImm() || ImmOp.getImm() != 0) 123 continue; 124 125 // Reject the form: 126 // %1 = ADD_rr %2, %3 127 // *(type *)(%2 + 0) = %1 128 if (Opcode == BPF::STB || Opcode == BPF::STH || Opcode == BPF::STW || 129 Opcode == BPF::STD || Opcode == BPF::STB32 || Opcode == BPF::STH32 || 130 Opcode == BPF::STW32) { 131 const MachineOperand &Opnd = DefInst->getOperand(0); 132 if (Opnd.isReg() && Opnd.getReg() == MO.getReg()) 133 continue; 134 } 135 136 BuildMI(*DefInst->getParent(), *DefInst, DefInst->getDebugLoc(), TII->get(COREOp)) 137 .add(DefInst->getOperand(0)).addImm(Opcode).add(*BaseOp) 138 .addGlobalAddress(GVal); 139 DefInst->eraseFromParent(); 140 } 141 } 142 143 void BPFMISimplifyPatchable::checkShift(MachineRegisterInfo *MRI, 144 MachineBasicBlock &MBB, MachineOperand *RelocOp, const GlobalValue *GVal, 145 unsigned Opcode) { 146 // Relocation operand should be the operand #2. 147 MachineInstr *Inst = RelocOp->getParent(); 148 if (RelocOp != &Inst->getOperand(2)) 149 return; 150 151 BuildMI(MBB, *Inst, Inst->getDebugLoc(), TII->get(BPF::CORE_SHIFT)) 152 .add(Inst->getOperand(0)).addImm(Opcode) 153 .add(Inst->getOperand(1)).addGlobalAddress(GVal); 154 Inst->eraseFromParent(); 155 } 156 157 void BPFMISimplifyPatchable::processCandidate(MachineRegisterInfo *MRI, 158 MachineBasicBlock &MBB, MachineInstr &MI, Register &SrcReg, 159 Register &DstReg, const GlobalValue *GVal, bool IsAma) { 160 if (MRI->getRegClass(DstReg) == &BPF::GPR32RegClass) { 161 if (IsAma) { 162 // We can optimize such a pattern: 163 // %1:gpr = LD_imm64 @"llvm.s:0:4$0:2" 164 // %2:gpr32 = LDW32 %1:gpr, 0 165 // %3:gpr = SUBREG_TO_REG 0, %2:gpr32, %subreg.sub_32 166 // %4:gpr = ADD_rr %0:gpr, %3:gpr 167 // or similar patterns below for non-alu32 case. 168 auto Begin = MRI->use_begin(DstReg), End = MRI->use_end(); 169 decltype(End) NextI; 170 for (auto I = Begin; I != End; I = NextI) { 171 NextI = std::next(I); 172 if (!MRI->getUniqueVRegDef(I->getReg())) 173 continue; 174 175 unsigned Opcode = I->getParent()->getOpcode(); 176 if (Opcode == BPF::SUBREG_TO_REG) { 177 Register TmpReg = I->getParent()->getOperand(0).getReg(); 178 processDstReg(MRI, TmpReg, DstReg, GVal, false, IsAma); 179 } 180 } 181 } 182 183 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(BPF::COPY), DstReg) 184 .addReg(SrcReg, 0, BPF::sub_32); 185 return; 186 } 187 188 // All uses of DstReg replaced by SrcReg 189 processDstReg(MRI, DstReg, SrcReg, GVal, true, IsAma); 190 } 191 192 void BPFMISimplifyPatchable::processDstReg(MachineRegisterInfo *MRI, 193 Register &DstReg, Register &SrcReg, const GlobalValue *GVal, 194 bool doSrcRegProp, bool IsAma) { 195 auto Begin = MRI->use_begin(DstReg), End = MRI->use_end(); 196 decltype(End) NextI; 197 for (auto I = Begin; I != End; I = NextI) { 198 NextI = std::next(I); 199 if (doSrcRegProp) 200 I->setReg(SrcReg); 201 202 // The candidate needs to have a unique definition. 203 if (IsAma && MRI->getUniqueVRegDef(I->getReg())) 204 processInst(MRI, I->getParent(), &*I, GVal); 205 } 206 } 207 208 // Check to see whether we could do some optimization 209 // to attach relocation to downstream dependent instructions. 210 // Two kinds of patterns are recognized below: 211 // Pattern 1: 212 // %1 = LD_imm64 @"llvm.b:0:4$0:1" <== patch_imm = 4 213 // %2 = LDD %1, 0 <== this insn will be removed 214 // %3 = ADD_rr %0, %2 215 // %4 = LDW[32] %3, 0 OR STW[32] %4, %3, 0 216 // The `%4 = ...` will be transformed to 217 // CORE_[ALU32_]MEM(%4, mem_opcode, %0, @"llvm.b:0:4$0:1") 218 // and later on, BTF emit phase will translate to 219 // %4 = LDW[32] %0, 4 STW[32] %4, %0, 4 220 // and attach a relocation to it. 221 // Pattern 2: 222 // %15 = LD_imm64 @"llvm.t:5:63$0:2" <== relocation type 5 223 // %16 = LDD %15, 0 <== this insn will be removed 224 // %17 = SRA_rr %14, %16 225 // The `%17 = ...` will be transformed to 226 // %17 = CORE_SHIFT(SRA_ri, %14, @"llvm.t:5:63$0:2") 227 // and later on, BTF emit phase will translate to 228 // %r4 = SRA_ri %r4, 63 229 void BPFMISimplifyPatchable::processInst(MachineRegisterInfo *MRI, 230 MachineInstr *Inst, MachineOperand *RelocOp, const GlobalValue *GVal) { 231 unsigned Opcode = Inst->getOpcode(); 232 if (Opcode == BPF::ADD_rr) 233 checkADDrr(MRI, RelocOp, GVal); 234 else if (Opcode == BPF::SLL_rr) 235 checkShift(MRI, *Inst->getParent(), RelocOp, GVal, BPF::SLL_ri); 236 else if (Opcode == BPF::SRA_rr) 237 checkShift(MRI, *Inst->getParent(), RelocOp, GVal, BPF::SRA_ri); 238 else if (Opcode == BPF::SRL_rr) 239 checkShift(MRI, *Inst->getParent(), RelocOp, GVal, BPF::SRL_ri); 240 } 241 242 /// Remove unneeded Load instructions. 243 bool BPFMISimplifyPatchable::removeLD() { 244 MachineRegisterInfo *MRI = &MF->getRegInfo(); 245 MachineInstr *ToErase = nullptr; 246 bool Changed = false; 247 248 for (MachineBasicBlock &MBB : *MF) { 249 for (MachineInstr &MI : MBB) { 250 if (ToErase) { 251 ToErase->eraseFromParent(); 252 ToErase = nullptr; 253 } 254 255 // Ensure the register format is LOAD <reg>, <reg>, 0 256 if (MI.getOpcode() != BPF::LDD && MI.getOpcode() != BPF::LDW && 257 MI.getOpcode() != BPF::LDH && MI.getOpcode() != BPF::LDB && 258 MI.getOpcode() != BPF::LDW32 && MI.getOpcode() != BPF::LDH32 && 259 MI.getOpcode() != BPF::LDB32) 260 continue; 261 262 if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg()) 263 continue; 264 265 if (!MI.getOperand(2).isImm() || MI.getOperand(2).getImm()) 266 continue; 267 268 Register DstReg = MI.getOperand(0).getReg(); 269 Register SrcReg = MI.getOperand(1).getReg(); 270 271 MachineInstr *DefInst = MRI->getUniqueVRegDef(SrcReg); 272 if (!DefInst) 273 continue; 274 275 if (DefInst->getOpcode() != BPF::LD_imm64) 276 continue; 277 278 const MachineOperand &MO = DefInst->getOperand(1); 279 if (!MO.isGlobal()) 280 continue; 281 282 const GlobalValue *GVal = MO.getGlobal(); 283 auto *GVar = dyn_cast<GlobalVariable>(GVal); 284 if (!GVar) 285 continue; 286 287 // Global variables representing structure offset or type id. 288 bool IsAma = false; 289 if (GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) 290 IsAma = true; 291 else if (!GVar->hasAttribute(BPFCoreSharedInfo::TypeIdAttr)) 292 continue; 293 294 processCandidate(MRI, MBB, MI, SrcReg, DstReg, GVal, IsAma); 295 296 ToErase = &MI; 297 Changed = true; 298 } 299 } 300 301 return Changed; 302 } 303 304 } // namespace 305 306 INITIALIZE_PASS(BPFMISimplifyPatchable, DEBUG_TYPE, 307 "BPF PreEmit SimplifyPatchable", false, false) 308 309 char BPFMISimplifyPatchable::ID = 0; 310 FunctionPass *llvm::createBPFMISimplifyPatchablePass() { 311 return new BPFMISimplifyPatchable(); 312 } 313