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 
34 using namespace llvm;
35 
36 #define DEBUG_TYPE "bpf-mi-simplify-patchable"
37 
38 namespace {
39 
40 struct BPFMISimplifyPatchable : public MachineFunctionPass {
41 
42   static char ID;
43   const BPFInstrInfo *TII;
44   MachineFunction *MF;
45 
46   BPFMISimplifyPatchable() : MachineFunctionPass(ID) {
47     initializeBPFMISimplifyPatchablePass(*PassRegistry::getPassRegistry());
48   }
49 
50 private:
51   // Initialize class variables.
52   void initialize(MachineFunction &MFParm);
53 
54   bool removeLD(void);
55 
56 public:
57   // Main entry point for this pass.
58   bool runOnMachineFunction(MachineFunction &MF) override {
59     if (!skipFunction(MF.getFunction())) {
60       initialize(MF);
61     }
62     return removeLD();
63   }
64 };
65 
66 // Initialize class variables.
67 void BPFMISimplifyPatchable::initialize(MachineFunction &MFParm) {
68   MF = &MFParm;
69   TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo();
70   LLVM_DEBUG(dbgs() << "*** BPF simplify patchable insts pass ***\n\n");
71 }
72 
73 /// Remove unneeded Load instructions.
74 bool BPFMISimplifyPatchable::removeLD() {
75   MachineRegisterInfo *MRI = &MF->getRegInfo();
76   MachineInstr *ToErase = nullptr;
77   bool Changed = false;
78 
79   for (MachineBasicBlock &MBB : *MF) {
80     for (MachineInstr &MI : MBB) {
81       if (ToErase) {
82         ToErase->eraseFromParent();
83         ToErase = nullptr;
84       }
85 
86       // Ensure the register format is LOAD <reg>, <reg>, 0
87       if (MI.getOpcode() != BPF::LDD && MI.getOpcode() != BPF::LDW &&
88           MI.getOpcode() != BPF::LDH && MI.getOpcode() != BPF::LDB &&
89           MI.getOpcode() != BPF::LDW32 && MI.getOpcode() != BPF::LDH32 &&
90           MI.getOpcode() != BPF::LDB32)
91         continue;
92 
93       if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg())
94         continue;
95 
96       if (!MI.getOperand(2).isImm() || MI.getOperand(2).getImm())
97         continue;
98 
99       Register DstReg = MI.getOperand(0).getReg();
100       Register SrcReg = MI.getOperand(1).getReg();
101 
102       MachineInstr *DefInst = MRI->getUniqueVRegDef(SrcReg);
103       if (!DefInst)
104         continue;
105 
106       bool IsCandidate = false;
107       if (DefInst->getOpcode() == BPF::LD_imm64) {
108         const MachineOperand &MO = DefInst->getOperand(1);
109         if (MO.isGlobal()) {
110           const GlobalValue *GVal = MO.getGlobal();
111           auto *GVar = dyn_cast<GlobalVariable>(GVal);
112           if (GVar) {
113             // Global variables representing structure offset or
114             // patchable extern globals.
115             if (GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) {
116               assert(MI.getOperand(2).getImm() == 0);
117               IsCandidate = true;
118             }
119           }
120         }
121       }
122 
123       if (!IsCandidate)
124         continue;
125 
126       auto Begin = MRI->use_begin(DstReg), End = MRI->use_end();
127       decltype(End) NextI;
128       for (auto I = Begin; I != End; I = NextI) {
129         NextI = std::next(I);
130         I->setReg(SrcReg);
131       }
132 
133       ToErase = &MI;
134       Changed = true;
135     }
136   }
137 
138   return Changed;
139 }
140 
141 } // namespace
142 
143 INITIALIZE_PASS(BPFMISimplifyPatchable, DEBUG_TYPE,
144                 "BPF PreEmit SimplifyPatchable", false, false)
145 
146 char BPFMISimplifyPatchable::ID = 0;
147 FunctionPass *llvm::createBPFMISimplifyPatchablePass() {
148   return new BPFMISimplifyPatchable();
149 }
150