Recommit r373598 "[yaml2obj/obj2yaml] - Add support for SHT_LLVM_ADDRSIG sections."
[llvm-complete.git] / lib / Target / BPF / BPFMISimplifyPatchable.cpp
blobb363179e25bb0306c1a888712a52944188776f3d
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
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
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
29 //===----------------------------------------------------------------------===//
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"
38 using namespace llvm;
40 #define DEBUG_TYPE "bpf-mi-simplify-patchable"
42 namespace {
44 struct BPFMISimplifyPatchable : public MachineFunctionPass {
46 static char ID;
47 const BPFInstrInfo *TII;
48 MachineFunction *MF;
50 BPFMISimplifyPatchable() : MachineFunctionPass(ID) {
51 initializeBPFMISimplifyPatchablePass(*PassRegistry::getPassRegistry());
54 private:
55 // Initialize class variables.
56 void initialize(MachineFunction &MFParm);
58 bool removeLD(void);
60 public:
61 // Main entry point for this pass.
62 bool runOnMachineFunction(MachineFunction &MF) override {
63 if (!skipFunction(MF.getFunction())) {
64 initialize(MF);
66 return removeLD();
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");
77 /// Remove unneeded Load instructions.
78 bool BPFMISimplifyPatchable::removeLD() {
79 MachineRegisterInfo *MRI = &MF->getRegInfo();
80 MachineInstr *ToErase = nullptr;
81 bool Changed = false;
83 for (MachineBasicBlock &MBB : *MF) {
84 for (MachineInstr &MI : MBB) {
85 if (ToErase) {
86 ToErase->eraseFromParent();
87 ToErase = nullptr;
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;
97 if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg())
98 continue;
100 if (!MI.getOperand(2).isImm() || MI.getOperand(2).getImm())
101 continue;
103 Register DstReg = MI.getOperand(0).getReg();
104 Register SrcReg = MI.getOperand(1).getReg();
105 int64_t ImmVal = MI.getOperand(2).getImm();
107 MachineInstr *DefInst = MRI->getUniqueVRegDef(SrcReg);
108 if (!DefInst)
109 continue;
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";
137 if (!IsCandidate)
138 continue;
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);
147 ToErase = &MI;
148 Changed = true;
152 return Changed;
155 } // namespace
157 INITIALIZE_PASS(BPFMISimplifyPatchable, DEBUG_TYPE,
158 "BPF PreEmit SimplifyPatchable", false, false)
160 char BPFMISimplifyPatchable::ID = 0;
161 FunctionPass *llvm::createBPFMISimplifyPatchablePass() {
162 return new BPFMISimplifyPatchable();