xref: /freebsd/contrib/llvm-project/llvm/lib/Target/BPF/BPFMISimplifyPatchable.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===----- BPFMISimplifyPatchable.cpp - MI Simplify Patchable Insts -------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This pass targets a subset of instructions like below
10*0b57cec5SDimitry Andric //    ld_imm64 r1, @global
11*0b57cec5SDimitry Andric //    ldd r2, r1, 0
12*0b57cec5SDimitry Andric //    add r3, struct_base_reg, r2
13*0b57cec5SDimitry Andric //
14*0b57cec5SDimitry Andric // Here @global should either present a AMA (abstruct member access) or
15*0b57cec5SDimitry Andric // a patchable extern variable. And these two kinds of accesses
16*0b57cec5SDimitry Andric // are subject to bpf load time patching. After this pass, the
17*0b57cec5SDimitry Andric // code becomes
18*0b57cec5SDimitry Andric //    ld_imm64 r1, @global
19*0b57cec5SDimitry Andric //    add r3, struct_base_reg, r1
20*0b57cec5SDimitry Andric //
21*0b57cec5SDimitry Andric // Eventually, at BTF output stage, a relocation record will be generated
22*0b57cec5SDimitry Andric // for ld_imm64 which should be replaced later by bpf loader:
23*0b57cec5SDimitry Andric //    r1 = <calculated offset> or <to_be_patched_extern_val>
24*0b57cec5SDimitry Andric //    add r3, struct_base_reg, r1
25*0b57cec5SDimitry Andric // or
26*0b57cec5SDimitry Andric //    ld_imm64 r1, <to_be_patched_extern_val>
27*0b57cec5SDimitry Andric //    add r3, struct_base_reg, r1
28*0b57cec5SDimitry Andric //
29*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
30*0b57cec5SDimitry Andric 
31*0b57cec5SDimitry Andric #include "BPF.h"
32*0b57cec5SDimitry Andric #include "BPFCORE.h"
33*0b57cec5SDimitry Andric #include "BPFInstrInfo.h"
34*0b57cec5SDimitry Andric #include "BPFTargetMachine.h"
35*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
36*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
37*0b57cec5SDimitry Andric 
38*0b57cec5SDimitry Andric using namespace llvm;
39*0b57cec5SDimitry Andric 
40*0b57cec5SDimitry Andric #define DEBUG_TYPE "bpf-mi-simplify-patchable"
41*0b57cec5SDimitry Andric 
42*0b57cec5SDimitry Andric namespace {
43*0b57cec5SDimitry Andric 
44*0b57cec5SDimitry Andric struct BPFMISimplifyPatchable : public MachineFunctionPass {
45*0b57cec5SDimitry Andric 
46*0b57cec5SDimitry Andric   static char ID;
47*0b57cec5SDimitry Andric   const BPFInstrInfo *TII;
48*0b57cec5SDimitry Andric   MachineFunction *MF;
49*0b57cec5SDimitry Andric 
50*0b57cec5SDimitry Andric   BPFMISimplifyPatchable() : MachineFunctionPass(ID) {
51*0b57cec5SDimitry Andric     initializeBPFMISimplifyPatchablePass(*PassRegistry::getPassRegistry());
52*0b57cec5SDimitry Andric   }
53*0b57cec5SDimitry Andric 
54*0b57cec5SDimitry Andric private:
55*0b57cec5SDimitry Andric   // Initialize class variables.
56*0b57cec5SDimitry Andric   void initialize(MachineFunction &MFParm);
57*0b57cec5SDimitry Andric 
58*0b57cec5SDimitry Andric   bool removeLD(void);
59*0b57cec5SDimitry Andric 
60*0b57cec5SDimitry Andric public:
61*0b57cec5SDimitry Andric   // Main entry point for this pass.
62*0b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override {
63*0b57cec5SDimitry Andric     if (!skipFunction(MF.getFunction())) {
64*0b57cec5SDimitry Andric       initialize(MF);
65*0b57cec5SDimitry Andric     }
66*0b57cec5SDimitry Andric     return removeLD();
67*0b57cec5SDimitry Andric   }
68*0b57cec5SDimitry Andric };
69*0b57cec5SDimitry Andric 
70*0b57cec5SDimitry Andric // Initialize class variables.
71*0b57cec5SDimitry Andric void BPFMISimplifyPatchable::initialize(MachineFunction &MFParm) {
72*0b57cec5SDimitry Andric   MF = &MFParm;
73*0b57cec5SDimitry Andric   TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo();
74*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "*** BPF simplify patchable insts pass ***\n\n");
75*0b57cec5SDimitry Andric }
76*0b57cec5SDimitry Andric 
77*0b57cec5SDimitry Andric /// Remove unneeded Load instructions.
78*0b57cec5SDimitry Andric bool BPFMISimplifyPatchable::removeLD() {
79*0b57cec5SDimitry Andric   MachineRegisterInfo *MRI = &MF->getRegInfo();
80*0b57cec5SDimitry Andric   MachineInstr *ToErase = nullptr;
81*0b57cec5SDimitry Andric   bool Changed = false;
82*0b57cec5SDimitry Andric 
83*0b57cec5SDimitry Andric   for (MachineBasicBlock &MBB : *MF) {
84*0b57cec5SDimitry Andric     for (MachineInstr &MI : MBB) {
85*0b57cec5SDimitry Andric       if (ToErase) {
86*0b57cec5SDimitry Andric         ToErase->eraseFromParent();
87*0b57cec5SDimitry Andric         ToErase = nullptr;
88*0b57cec5SDimitry Andric       }
89*0b57cec5SDimitry Andric 
90*0b57cec5SDimitry Andric       // Ensure the register format is LOAD <reg>, <reg>, 0
91*0b57cec5SDimitry Andric       if (MI.getOpcode() != BPF::LDD && MI.getOpcode() != BPF::LDW &&
92*0b57cec5SDimitry Andric           MI.getOpcode() != BPF::LDH && MI.getOpcode() != BPF::LDB &&
93*0b57cec5SDimitry Andric           MI.getOpcode() != BPF::LDW32 && MI.getOpcode() != BPF::LDH32 &&
94*0b57cec5SDimitry Andric           MI.getOpcode() != BPF::LDB32)
95*0b57cec5SDimitry Andric         continue;
96*0b57cec5SDimitry Andric 
97*0b57cec5SDimitry Andric       if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg())
98*0b57cec5SDimitry Andric         continue;
99*0b57cec5SDimitry Andric 
100*0b57cec5SDimitry Andric       if (!MI.getOperand(2).isImm() || MI.getOperand(2).getImm())
101*0b57cec5SDimitry Andric         continue;
102*0b57cec5SDimitry Andric 
103*0b57cec5SDimitry Andric       unsigned DstReg = MI.getOperand(0).getReg();
104*0b57cec5SDimitry Andric       unsigned SrcReg = MI.getOperand(1).getReg();
105*0b57cec5SDimitry Andric       int64_t ImmVal = MI.getOperand(2).getImm();
106*0b57cec5SDimitry Andric 
107*0b57cec5SDimitry Andric       MachineInstr *DefInst = MRI->getUniqueVRegDef(SrcReg);
108*0b57cec5SDimitry Andric       if (!DefInst)
109*0b57cec5SDimitry Andric         continue;
110*0b57cec5SDimitry Andric 
111*0b57cec5SDimitry Andric       bool IsCandidate = false;
112*0b57cec5SDimitry Andric       if (DefInst->getOpcode() == BPF::LD_imm64) {
113*0b57cec5SDimitry Andric         const MachineOperand &MO = DefInst->getOperand(1);
114*0b57cec5SDimitry Andric         if (MO.isGlobal()) {
115*0b57cec5SDimitry Andric           const GlobalValue *GVal = MO.getGlobal();
116*0b57cec5SDimitry Andric           auto *GVar = dyn_cast<GlobalVariable>(GVal);
117*0b57cec5SDimitry Andric           if (GVar) {
118*0b57cec5SDimitry Andric             // Global variables representing structure offset or
119*0b57cec5SDimitry Andric             // patchable extern globals.
120*0b57cec5SDimitry Andric             if (GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) {
121*0b57cec5SDimitry Andric               assert(ImmVal == 0);
122*0b57cec5SDimitry Andric               IsCandidate = true;
123*0b57cec5SDimitry Andric             } else if (!GVar->hasInitializer() && GVar->hasExternalLinkage() &&
124*0b57cec5SDimitry Andric                        GVar->getSection() ==
125*0b57cec5SDimitry Andric                            BPFCoreSharedInfo::PatchableExtSecName) {
126*0b57cec5SDimitry Andric               if (ImmVal == 0)
127*0b57cec5SDimitry Andric                 IsCandidate = true;
128*0b57cec5SDimitry Andric               else
129*0b57cec5SDimitry Andric                 errs() << "WARNING: unhandled patchable extern "
130*0b57cec5SDimitry Andric                        << GVar->getName() << " with load offset " << ImmVal
131*0b57cec5SDimitry Andric                        << "\n";
132*0b57cec5SDimitry Andric             }
133*0b57cec5SDimitry Andric           }
134*0b57cec5SDimitry Andric         }
135*0b57cec5SDimitry Andric       }
136*0b57cec5SDimitry Andric 
137*0b57cec5SDimitry Andric       if (!IsCandidate)
138*0b57cec5SDimitry Andric         continue;
139*0b57cec5SDimitry Andric 
140*0b57cec5SDimitry Andric       auto Begin = MRI->use_begin(DstReg), End = MRI->use_end();
141*0b57cec5SDimitry Andric       decltype(End) NextI;
142*0b57cec5SDimitry Andric       for (auto I = Begin; I != End; I = NextI) {
143*0b57cec5SDimitry Andric         NextI = std::next(I);
144*0b57cec5SDimitry Andric         I->setReg(SrcReg);
145*0b57cec5SDimitry Andric       }
146*0b57cec5SDimitry Andric 
147*0b57cec5SDimitry Andric       ToErase = &MI;
148*0b57cec5SDimitry Andric       Changed = true;
149*0b57cec5SDimitry Andric     }
150*0b57cec5SDimitry Andric   }
151*0b57cec5SDimitry Andric 
152*0b57cec5SDimitry Andric   return Changed;
153*0b57cec5SDimitry Andric }
154*0b57cec5SDimitry Andric 
155*0b57cec5SDimitry Andric } // namespace
156*0b57cec5SDimitry Andric 
157*0b57cec5SDimitry Andric INITIALIZE_PASS(BPFMISimplifyPatchable, DEBUG_TYPE,
158*0b57cec5SDimitry Andric                 "BPF PreEmit SimplifyPatchable", false, false)
159*0b57cec5SDimitry Andric 
160*0b57cec5SDimitry Andric char BPFMISimplifyPatchable::ID = 0;
161*0b57cec5SDimitry Andric FunctionPass *llvm::createBPFMISimplifyPatchablePass() {
162*0b57cec5SDimitry Andric   return new BPFMISimplifyPatchable();
163*0b57cec5SDimitry Andric }
164