1 | //===-- BPFTargetMachine.cpp - Define TargetMachine for BPF ---------------===// |
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 | // Implements the info about BPF target spec. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "BPFTargetMachine.h" |
14 | #include "BPF.h" |
15 | #include "BPFTargetTransformInfo.h" |
16 | #include "MCTargetDesc/BPFMCAsmInfo.h" |
17 | #include "TargetInfo/BPFTargetInfo.h" |
18 | #include "llvm/CodeGen/GlobalISel/IRTranslator.h" |
19 | #include "llvm/CodeGen/GlobalISel/InstructionSelect.h" |
20 | #include "llvm/CodeGen/GlobalISel/Legalizer.h" |
21 | #include "llvm/CodeGen/GlobalISel/RegBankSelect.h" |
22 | #include "llvm/CodeGen/Passes.h" |
23 | #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" |
24 | #include "llvm/CodeGen/TargetPassConfig.h" |
25 | #include "llvm/IR/PassManager.h" |
26 | #include "llvm/InitializePasses.h" |
27 | #include "llvm/MC/TargetRegistry.h" |
28 | #include "llvm/Passes/PassBuilder.h" |
29 | #include "llvm/Support/FormattedStream.h" |
30 | #include "llvm/Target/TargetOptions.h" |
31 | #include "llvm/Transforms/Scalar.h" |
32 | #include "llvm/Transforms/Scalar/SimplifyCFG.h" |
33 | #include "llvm/Transforms/Utils/SimplifyCFGOptions.h" |
34 | #include <optional> |
35 | using namespace llvm; |
36 | |
37 | static cl:: |
38 | opt<bool> DisableMIPeephole("disable-bpf-peephole" , cl::Hidden, |
39 | cl::desc("Disable machine peepholes for BPF" )); |
40 | |
41 | extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFTarget() { |
42 | // Register the target. |
43 | RegisterTargetMachine<BPFTargetMachine> X(getTheBPFleTarget()); |
44 | RegisterTargetMachine<BPFTargetMachine> Y(getTheBPFbeTarget()); |
45 | RegisterTargetMachine<BPFTargetMachine> Z(getTheBPFTarget()); |
46 | |
47 | PassRegistry &PR = *PassRegistry::getPassRegistry(); |
48 | initializeGlobalISel(PR); |
49 | initializeBPFCheckAndAdjustIRPass(PR); |
50 | initializeBPFMIPeepholePass(PR); |
51 | initializeBPFDAGToDAGISelPass(PR); |
52 | } |
53 | |
54 | // DataLayout: little or big endian |
55 | static std::string computeDataLayout(const Triple &TT) { |
56 | if (TT.getArch() == Triple::bpfeb) |
57 | return "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128" ; |
58 | else |
59 | return "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128" ; |
60 | } |
61 | |
62 | static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) { |
63 | return RM.value_or(u: Reloc::PIC_); |
64 | } |
65 | |
66 | BPFTargetMachine::BPFTargetMachine(const Target &T, const Triple &TT, |
67 | StringRef CPU, StringRef FS, |
68 | const TargetOptions &Options, |
69 | std::optional<Reloc::Model> RM, |
70 | std::optional<CodeModel::Model> CM, |
71 | CodeGenOptLevel OL, bool JIT) |
72 | : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options, |
73 | getEffectiveRelocModel(RM), |
74 | getEffectiveCodeModel(CM, Default: CodeModel::Small), OL), |
75 | TLOF(std::make_unique<TargetLoweringObjectFileELF>()), |
76 | Subtarget(TT, std::string(CPU), std::string(FS), *this) { |
77 | initAsmInfo(); |
78 | |
79 | BPFMCAsmInfo *MAI = |
80 | static_cast<BPFMCAsmInfo *>(const_cast<MCAsmInfo *>(AsmInfo.get())); |
81 | MAI->setDwarfUsesRelocationsAcrossSections(!Subtarget.getUseDwarfRIS()); |
82 | } |
83 | |
84 | namespace { |
85 | // BPF Code Generator Pass Configuration Options. |
86 | class BPFPassConfig : public TargetPassConfig { |
87 | public: |
88 | BPFPassConfig(BPFTargetMachine &TM, PassManagerBase &PM) |
89 | : TargetPassConfig(TM, PM) {} |
90 | |
91 | BPFTargetMachine &getBPFTargetMachine() const { |
92 | return getTM<BPFTargetMachine>(); |
93 | } |
94 | |
95 | void addIRPasses() override; |
96 | bool addInstSelector() override; |
97 | void addMachineSSAOptimization() override; |
98 | void addPreEmitPass() override; |
99 | |
100 | bool addIRTranslator() override; |
101 | bool addLegalizeMachineIR() override; |
102 | bool addRegBankSelect() override; |
103 | bool addGlobalInstructionSelect() override; |
104 | }; |
105 | } |
106 | |
107 | TargetPassConfig *BPFTargetMachine::createPassConfig(PassManagerBase &PM) { |
108 | return new BPFPassConfig(*this, PM); |
109 | } |
110 | |
111 | static Expected<bool> parseBPFPreserveStaticOffsetOptions(StringRef Params) { |
112 | return PassBuilder::parseSinglePassOption(Params, OptionName: "allow-partial" , |
113 | PassName: "BPFPreserveStaticOffsetPass" ); |
114 | } |
115 | |
116 | void BPFTargetMachine::registerPassBuilderCallbacks( |
117 | PassBuilder &PB, bool PopulateClassToPassNames) { |
118 | #define GET_PASS_REGISTRY "BPFPassRegistry.def" |
119 | #include "llvm/Passes/TargetPassRegistry.inc" |
120 | |
121 | PB.registerPipelineStartEPCallback( |
122 | C: [=](ModulePassManager &MPM, OptimizationLevel) { |
123 | FunctionPassManager FPM; |
124 | FPM.addPass(Pass: BPFPreserveStaticOffsetPass(true)); |
125 | FPM.addPass(Pass: BPFAbstractMemberAccessPass(this)); |
126 | FPM.addPass(Pass: BPFPreserveDITypePass()); |
127 | FPM.addPass(Pass: BPFIRPeepholePass()); |
128 | MPM.addPass(Pass: createModuleToFunctionPassAdaptor(Pass: std::move(FPM))); |
129 | }); |
130 | PB.registerPeepholeEPCallback(C: [=](FunctionPassManager &FPM, |
131 | OptimizationLevel Level) { |
132 | FPM.addPass(Pass: SimplifyCFGPass(SimplifyCFGOptions().hoistCommonInsts(B: true))); |
133 | FPM.addPass(Pass: BPFASpaceCastSimplifyPass()); |
134 | }); |
135 | PB.registerScalarOptimizerLateEPCallback( |
136 | C: [=](FunctionPassManager &FPM, OptimizationLevel Level) { |
137 | // Run this after loop unrolling but before |
138 | // SimplifyCFGPass(... .sinkCommonInsts(true)) |
139 | FPM.addPass(Pass: BPFPreserveStaticOffsetPass(false)); |
140 | }); |
141 | PB.registerPipelineEarlySimplificationEPCallback( |
142 | C: [=](ModulePassManager &MPM, OptimizationLevel) { |
143 | MPM.addPass(Pass: BPFAdjustOptPass()); |
144 | }); |
145 | } |
146 | |
147 | void BPFPassConfig::addIRPasses() { |
148 | addPass(P: createAtomicExpandLegacyPass()); |
149 | addPass(P: createBPFCheckAndAdjustIR()); |
150 | |
151 | TargetPassConfig::addIRPasses(); |
152 | } |
153 | |
154 | TargetTransformInfo |
155 | BPFTargetMachine::getTargetTransformInfo(const Function &F) const { |
156 | return TargetTransformInfo(BPFTTIImpl(this, F)); |
157 | } |
158 | |
159 | // Install an instruction selector pass using |
160 | // the ISelDag to gen BPF code. |
161 | bool BPFPassConfig::addInstSelector() { |
162 | addPass(P: createBPFISelDag(TM&: getBPFTargetMachine())); |
163 | |
164 | return false; |
165 | } |
166 | |
167 | void BPFPassConfig::addMachineSSAOptimization() { |
168 | addPass(P: createBPFMISimplifyPatchablePass()); |
169 | |
170 | // The default implementation must be called first as we want eBPF |
171 | // Peephole ran at last. |
172 | TargetPassConfig::addMachineSSAOptimization(); |
173 | |
174 | const BPFSubtarget *Subtarget = getBPFTargetMachine().getSubtargetImpl(); |
175 | if (!DisableMIPeephole) { |
176 | if (Subtarget->getHasAlu32()) |
177 | addPass(P: createBPFMIPeepholePass()); |
178 | } |
179 | } |
180 | |
181 | void BPFPassConfig::addPreEmitPass() { |
182 | addPass(P: createBPFMIPreEmitCheckingPass()); |
183 | if (getOptLevel() != CodeGenOptLevel::None) |
184 | if (!DisableMIPeephole) |
185 | addPass(P: createBPFMIPreEmitPeepholePass()); |
186 | } |
187 | |
188 | bool BPFPassConfig::addIRTranslator() { |
189 | addPass(P: new IRTranslator()); |
190 | return false; |
191 | } |
192 | |
193 | bool BPFPassConfig::addLegalizeMachineIR() { |
194 | addPass(P: new Legalizer()); |
195 | return false; |
196 | } |
197 | |
198 | bool BPFPassConfig::addRegBankSelect() { |
199 | addPass(P: new RegBankSelect()); |
200 | return false; |
201 | } |
202 | |
203 | bool BPFPassConfig::addGlobalInstructionSelect() { |
204 | addPass(P: new InstructionSelect(getOptLevel())); |
205 | return false; |
206 | } |
207 | |