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