]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/llvm/lib/Target/BPF/BPFMISimplifyPatchable.cpp
MFC r355940:
[FreeBSD/FreeBSD.git] / contrib / llvm-project / llvm / lib / Target / BPF / BPFMISimplifyPatchable.cpp
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 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
20 //
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
28 //
29 //===----------------------------------------------------------------------===//
30
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"
37
38 using namespace llvm;
39
40 #define DEBUG_TYPE "bpf-mi-simplify-patchable"
41
42 namespace {
43
44 struct BPFMISimplifyPatchable : public MachineFunctionPass {
45
46   static char ID;
47   const BPFInstrInfo *TII;
48   MachineFunction *MF;
49
50   BPFMISimplifyPatchable() : MachineFunctionPass(ID) {
51     initializeBPFMISimplifyPatchablePass(*PassRegistry::getPassRegistry());
52   }
53
54 private:
55   // Initialize class variables.
56   void initialize(MachineFunction &MFParm);
57
58   bool removeLD(void);
59
60 public:
61   // Main entry point for this pass.
62   bool runOnMachineFunction(MachineFunction &MF) override {
63     if (!skipFunction(MF.getFunction())) {
64       initialize(MF);
65     }
66     return removeLD();
67   }
68 };
69
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");
75 }
76
77 /// Remove unneeded Load instructions.
78 bool BPFMISimplifyPatchable::removeLD() {
79   MachineRegisterInfo *MRI = &MF->getRegInfo();
80   MachineInstr *ToErase = nullptr;
81   bool Changed = false;
82
83   for (MachineBasicBlock &MBB : *MF) {
84     for (MachineInstr &MI : MBB) {
85       if (ToErase) {
86         ToErase->eraseFromParent();
87         ToErase = nullptr;
88       }
89
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;
96
97       if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg())
98         continue;
99
100       if (!MI.getOperand(2).isImm() || MI.getOperand(2).getImm())
101         continue;
102
103       unsigned DstReg = MI.getOperand(0).getReg();
104       unsigned SrcReg = MI.getOperand(1).getReg();
105       int64_t ImmVal = MI.getOperand(2).getImm();
106
107       MachineInstr *DefInst = MRI->getUniqueVRegDef(SrcReg);
108       if (!DefInst)
109         continue;
110
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";
132             }
133           }
134         }
135       }
136
137       if (!IsCandidate)
138         continue;
139
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);
145       }
146
147       ToErase = &MI;
148       Changed = true;
149     }
150   }
151
152   return Changed;
153 }
154
155 } // namespace
156
157 INITIALIZE_PASS(BPFMISimplifyPatchable, DEBUG_TYPE,
158                 "BPF PreEmit SimplifyPatchable", false, false)
159
160 char BPFMISimplifyPatchable::ID = 0;
161 FunctionPass *llvm::createBPFMISimplifyPatchablePass() {
162   return new BPFMISimplifyPatchable();
163 }