10b57cec5SDimitry Andric //===----- BPFMISimplifyPatchable.cpp - MI Simplify Patchable Insts -------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This pass targets a subset of instructions like below 100b57cec5SDimitry Andric // ld_imm64 r1, @global 110b57cec5SDimitry Andric // ldd r2, r1, 0 120b57cec5SDimitry Andric // add r3, struct_base_reg, r2 130b57cec5SDimitry Andric // 14*8bcb0991SDimitry Andric // Here @global should represent an AMA (abstruct member access). 15*8bcb0991SDimitry Andric // Such an access is subject to bpf load time patching. After this pass, the 160b57cec5SDimitry Andric // code becomes 170b57cec5SDimitry Andric // ld_imm64 r1, @global 180b57cec5SDimitry Andric // add r3, struct_base_reg, r1 190b57cec5SDimitry Andric // 200b57cec5SDimitry Andric // Eventually, at BTF output stage, a relocation record will be generated 210b57cec5SDimitry Andric // for ld_imm64 which should be replaced later by bpf loader: 22*8bcb0991SDimitry Andric // r1 = <calculated field_info> 230b57cec5SDimitry Andric // add r3, struct_base_reg, r1 240b57cec5SDimitry Andric // 250b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric #include "BPF.h" 280b57cec5SDimitry Andric #include "BPFCORE.h" 290b57cec5SDimitry Andric #include "BPFInstrInfo.h" 300b57cec5SDimitry Andric #include "BPFTargetMachine.h" 310b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 320b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 33*8bcb0991SDimitry Andric #include "llvm/Support/Debug.h" 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric using namespace llvm; 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric #define DEBUG_TYPE "bpf-mi-simplify-patchable" 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric namespace { 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric struct BPFMISimplifyPatchable : public MachineFunctionPass { 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric static char ID; 440b57cec5SDimitry Andric const BPFInstrInfo *TII; 450b57cec5SDimitry Andric MachineFunction *MF; 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric BPFMISimplifyPatchable() : MachineFunctionPass(ID) { 480b57cec5SDimitry Andric initializeBPFMISimplifyPatchablePass(*PassRegistry::getPassRegistry()); 490b57cec5SDimitry Andric } 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric private: 520b57cec5SDimitry Andric // Initialize class variables. 530b57cec5SDimitry Andric void initialize(MachineFunction &MFParm); 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric bool removeLD(void); 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric public: 580b57cec5SDimitry Andric // Main entry point for this pass. 590b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 600b57cec5SDimitry Andric if (!skipFunction(MF.getFunction())) { 610b57cec5SDimitry Andric initialize(MF); 620b57cec5SDimitry Andric } 630b57cec5SDimitry Andric return removeLD(); 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric }; 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric // Initialize class variables. 680b57cec5SDimitry Andric void BPFMISimplifyPatchable::initialize(MachineFunction &MFParm) { 690b57cec5SDimitry Andric MF = &MFParm; 700b57cec5SDimitry Andric TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo(); 710b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "*** BPF simplify patchable insts pass ***\n\n"); 720b57cec5SDimitry Andric } 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric /// Remove unneeded Load instructions. 750b57cec5SDimitry Andric bool BPFMISimplifyPatchable::removeLD() { 760b57cec5SDimitry Andric MachineRegisterInfo *MRI = &MF->getRegInfo(); 770b57cec5SDimitry Andric MachineInstr *ToErase = nullptr; 780b57cec5SDimitry Andric bool Changed = false; 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric for (MachineBasicBlock &MBB : *MF) { 810b57cec5SDimitry Andric for (MachineInstr &MI : MBB) { 820b57cec5SDimitry Andric if (ToErase) { 830b57cec5SDimitry Andric ToErase->eraseFromParent(); 840b57cec5SDimitry Andric ToErase = nullptr; 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric // Ensure the register format is LOAD <reg>, <reg>, 0 880b57cec5SDimitry Andric if (MI.getOpcode() != BPF::LDD && MI.getOpcode() != BPF::LDW && 890b57cec5SDimitry Andric MI.getOpcode() != BPF::LDH && MI.getOpcode() != BPF::LDB && 900b57cec5SDimitry Andric MI.getOpcode() != BPF::LDW32 && MI.getOpcode() != BPF::LDH32 && 910b57cec5SDimitry Andric MI.getOpcode() != BPF::LDB32) 920b57cec5SDimitry Andric continue; 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg()) 950b57cec5SDimitry Andric continue; 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric if (!MI.getOperand(2).isImm() || MI.getOperand(2).getImm()) 980b57cec5SDimitry Andric continue; 990b57cec5SDimitry Andric 100*8bcb0991SDimitry Andric Register DstReg = MI.getOperand(0).getReg(); 101*8bcb0991SDimitry Andric Register SrcReg = MI.getOperand(1).getReg(); 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric MachineInstr *DefInst = MRI->getUniqueVRegDef(SrcReg); 1040b57cec5SDimitry Andric if (!DefInst) 1050b57cec5SDimitry Andric continue; 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric bool IsCandidate = false; 1080b57cec5SDimitry Andric if (DefInst->getOpcode() == BPF::LD_imm64) { 1090b57cec5SDimitry Andric const MachineOperand &MO = DefInst->getOperand(1); 1100b57cec5SDimitry Andric if (MO.isGlobal()) { 1110b57cec5SDimitry Andric const GlobalValue *GVal = MO.getGlobal(); 1120b57cec5SDimitry Andric auto *GVar = dyn_cast<GlobalVariable>(GVal); 1130b57cec5SDimitry Andric if (GVar) { 1140b57cec5SDimitry Andric // Global variables representing structure offset or 1150b57cec5SDimitry Andric // patchable extern globals. 1160b57cec5SDimitry Andric if (GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) { 117*8bcb0991SDimitry Andric assert(MI.getOperand(2).getImm() == 0); 1180b57cec5SDimitry Andric IsCandidate = true; 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric if (!IsCandidate) 1250b57cec5SDimitry Andric continue; 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric auto Begin = MRI->use_begin(DstReg), End = MRI->use_end(); 1280b57cec5SDimitry Andric decltype(End) NextI; 1290b57cec5SDimitry Andric for (auto I = Begin; I != End; I = NextI) { 1300b57cec5SDimitry Andric NextI = std::next(I); 1310b57cec5SDimitry Andric I->setReg(SrcReg); 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric ToErase = &MI; 1350b57cec5SDimitry Andric Changed = true; 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric return Changed; 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric } // namespace 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric INITIALIZE_PASS(BPFMISimplifyPatchable, DEBUG_TYPE, 1450b57cec5SDimitry Andric "BPF PreEmit SimplifyPatchable", false, false) 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric char BPFMISimplifyPatchable::ID = 0; 1480b57cec5SDimitry Andric FunctionPass *llvm::createBPFMISimplifyPatchablePass() { 1490b57cec5SDimitry Andric return new BPFMISimplifyPatchable(); 1500b57cec5SDimitry Andric } 151