xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/BPF/BPFTargetMachine.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- BPFTargetMachine.cpp - Define TargetMachine for BPF ---------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Implements the info about BPF target spec.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "BPFTargetMachine.h"
140b57cec5SDimitry Andric #include "BPF.h"
1523408297SDimitry Andric #include "BPFTargetTransformInfo.h"
160b57cec5SDimitry Andric #include "MCTargetDesc/BPFMCAsmInfo.h"
170b57cec5SDimitry Andric #include "TargetInfo/BPFTargetInfo.h"
185f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/IRTranslator.h"
195f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
205f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/Legalizer.h"
215f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/RegBankSelect.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
25e8d8bef9SDimitry Andric #include "llvm/IR/PassManager.h"
265f757f3fSDimitry Andric #include "llvm/InitializePasses.h"
27349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
28e8d8bef9SDimitry Andric #include "llvm/Passes/PassBuilder.h"
290b57cec5SDimitry Andric #include "llvm/Support/FormattedStream.h"
300b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h"
31e8d8bef9SDimitry Andric #include "llvm/Transforms/Scalar.h"
32e8d8bef9SDimitry Andric #include "llvm/Transforms/Scalar/SimplifyCFG.h"
33e8d8bef9SDimitry Andric #include "llvm/Transforms/Utils/SimplifyCFGOptions.h"
34bdd1243dSDimitry Andric #include <optional>
350b57cec5SDimitry Andric using namespace llvm;
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric static cl::
380b57cec5SDimitry Andric opt<bool> DisableMIPeephole("disable-bpf-peephole", cl::Hidden,
390b57cec5SDimitry Andric                             cl::desc("Disable machine peepholes for BPF"));
400b57cec5SDimitry Andric 
41480093f4SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFTarget() {
420b57cec5SDimitry Andric   // Register the target.
430b57cec5SDimitry Andric   RegisterTargetMachine<BPFTargetMachine> X(getTheBPFleTarget());
440b57cec5SDimitry Andric   RegisterTargetMachine<BPFTargetMachine> Y(getTheBPFbeTarget());
450b57cec5SDimitry Andric   RegisterTargetMachine<BPFTargetMachine> Z(getTheBPFTarget());
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   PassRegistry &PR = *PassRegistry::getPassRegistry();
485f757f3fSDimitry Andric   initializeGlobalISel(PR);
49e8d8bef9SDimitry Andric   initializeBPFCheckAndAdjustIRPass(PR);
500b57cec5SDimitry Andric   initializeBPFMIPeepholePass(PR);
51*0fca6ea1SDimitry Andric   initializeBPFDAGToDAGISelLegacyPass(PR);
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric // DataLayout: little or big endian
550b57cec5SDimitry Andric static std::string computeDataLayout(const Triple &TT) {
560b57cec5SDimitry Andric   if (TT.getArch() == Triple::bpfeb)
575ffd83dbSDimitry Andric     return "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128";
580b57cec5SDimitry Andric   else
595ffd83dbSDimitry Andric     return "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128";
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric 
62bdd1243dSDimitry Andric static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) {
6381ad6265SDimitry Andric   return RM.value_or(Reloc::PIC_);
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric BPFTargetMachine::BPFTargetMachine(const Target &T, const Triple &TT,
670b57cec5SDimitry Andric                                    StringRef CPU, StringRef FS,
680b57cec5SDimitry Andric                                    const TargetOptions &Options,
69bdd1243dSDimitry Andric                                    std::optional<Reloc::Model> RM,
70bdd1243dSDimitry Andric                                    std::optional<CodeModel::Model> CM,
715f757f3fSDimitry Andric                                    CodeGenOptLevel OL, bool JIT)
720b57cec5SDimitry Andric     : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options,
730b57cec5SDimitry Andric                         getEffectiveRelocModel(RM),
740b57cec5SDimitry Andric                         getEffectiveCodeModel(CM, CodeModel::Small), OL),
758bcb0991SDimitry Andric       TLOF(std::make_unique<TargetLoweringObjectFileELF>()),
765ffd83dbSDimitry Andric       Subtarget(TT, std::string(CPU), std::string(FS), *this) {
770b57cec5SDimitry Andric   initAsmInfo();
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric   BPFMCAsmInfo *MAI =
800b57cec5SDimitry Andric       static_cast<BPFMCAsmInfo *>(const_cast<MCAsmInfo *>(AsmInfo.get()));
810b57cec5SDimitry Andric   MAI->setDwarfUsesRelocationsAcrossSections(!Subtarget.getUseDwarfRIS());
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric namespace {
850b57cec5SDimitry Andric // BPF Code Generator Pass Configuration Options.
860b57cec5SDimitry Andric class BPFPassConfig : public TargetPassConfig {
870b57cec5SDimitry Andric public:
880b57cec5SDimitry Andric   BPFPassConfig(BPFTargetMachine &TM, PassManagerBase &PM)
890b57cec5SDimitry Andric       : TargetPassConfig(TM, PM) {}
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   BPFTargetMachine &getBPFTargetMachine() const {
920b57cec5SDimitry Andric     return getTM<BPFTargetMachine>();
930b57cec5SDimitry Andric   }
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   void addIRPasses() override;
960b57cec5SDimitry Andric   bool addInstSelector() override;
970b57cec5SDimitry Andric   void addMachineSSAOptimization() override;
980b57cec5SDimitry Andric   void addPreEmitPass() override;
995f757f3fSDimitry Andric 
1005f757f3fSDimitry Andric   bool addIRTranslator() override;
1015f757f3fSDimitry Andric   bool addLegalizeMachineIR() override;
1025f757f3fSDimitry Andric   bool addRegBankSelect() override;
1035f757f3fSDimitry Andric   bool addGlobalInstructionSelect() override;
1040b57cec5SDimitry Andric };
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric TargetPassConfig *BPFTargetMachine::createPassConfig(PassManagerBase &PM) {
1080b57cec5SDimitry Andric   return new BPFPassConfig(*this, PM);
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric 
111*0fca6ea1SDimitry Andric static Expected<bool> parseBPFPreserveStaticOffsetOptions(StringRef Params) {
112*0fca6ea1SDimitry Andric   return PassBuilder::parseSinglePassOption(Params, "allow-partial",
113*0fca6ea1SDimitry Andric                                             "BPFPreserveStaticOffsetPass");
11406c3fb27SDimitry Andric }
115*0fca6ea1SDimitry Andric 
116*0fca6ea1SDimitry Andric void BPFTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
117*0fca6ea1SDimitry Andric #define GET_PASS_REGISTRY "BPFPassRegistry.def"
118*0fca6ea1SDimitry Andric #include "llvm/Passes/TargetPassRegistry.inc"
119*0fca6ea1SDimitry Andric 
120e8d8bef9SDimitry Andric   PB.registerPipelineStartEPCallback(
121349cc55cSDimitry Andric       [=](ModulePassManager &MPM, OptimizationLevel) {
122fe6060f1SDimitry Andric         FunctionPassManager FPM;
1235f757f3fSDimitry Andric         FPM.addPass(BPFPreserveStaticOffsetPass(true));
124e8d8bef9SDimitry Andric         FPM.addPass(BPFAbstractMemberAccessPass(this));
125e8d8bef9SDimitry Andric         FPM.addPass(BPFPreserveDITypePass());
126349cc55cSDimitry Andric         FPM.addPass(BPFIRPeepholePass());
127e8d8bef9SDimitry Andric         MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
128e8d8bef9SDimitry Andric       });
129e8d8bef9SDimitry Andric   PB.registerPeepholeEPCallback([=](FunctionPassManager &FPM,
130349cc55cSDimitry Andric                                     OptimizationLevel Level) {
131e8d8bef9SDimitry Andric     FPM.addPass(SimplifyCFGPass(SimplifyCFGOptions().hoistCommonInsts(true)));
132*0fca6ea1SDimitry Andric     FPM.addPass(BPFASpaceCastSimplifyPass());
133e8d8bef9SDimitry Andric   });
1345f757f3fSDimitry Andric   PB.registerScalarOptimizerLateEPCallback(
1355f757f3fSDimitry Andric       [=](FunctionPassManager &FPM, OptimizationLevel Level) {
1365f757f3fSDimitry Andric         // Run this after loop unrolling but before
1375f757f3fSDimitry Andric         // SimplifyCFGPass(... .sinkCommonInsts(true))
1385f757f3fSDimitry Andric         FPM.addPass(BPFPreserveStaticOffsetPass(false));
1395f757f3fSDimitry Andric       });
140e8d8bef9SDimitry Andric   PB.registerPipelineEarlySimplificationEPCallback(
141349cc55cSDimitry Andric       [=](ModulePassManager &MPM, OptimizationLevel) {
142e8d8bef9SDimitry Andric         MPM.addPass(BPFAdjustOptPass());
143e8d8bef9SDimitry Andric       });
144e8d8bef9SDimitry Andric }
145e8d8bef9SDimitry Andric 
1460b57cec5SDimitry Andric void BPFPassConfig::addIRPasses() {
147*0fca6ea1SDimitry Andric   addPass(createAtomicExpandLegacyPass());
148e8d8bef9SDimitry Andric   addPass(createBPFCheckAndAdjustIR());
1491db9f3b2SDimitry Andric 
1500b57cec5SDimitry Andric   TargetPassConfig::addIRPasses();
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric 
15323408297SDimitry Andric TargetTransformInfo
15481ad6265SDimitry Andric BPFTargetMachine::getTargetTransformInfo(const Function &F) const {
15523408297SDimitry Andric   return TargetTransformInfo(BPFTTIImpl(this, F));
15623408297SDimitry Andric }
15723408297SDimitry Andric 
1580b57cec5SDimitry Andric // Install an instruction selector pass using
1590b57cec5SDimitry Andric // the ISelDag to gen BPF code.
1600b57cec5SDimitry Andric bool BPFPassConfig::addInstSelector() {
1610b57cec5SDimitry Andric   addPass(createBPFISelDag(getBPFTargetMachine()));
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric   return false;
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric void BPFPassConfig::addMachineSSAOptimization() {
1670b57cec5SDimitry Andric   addPass(createBPFMISimplifyPatchablePass());
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric   // The default implementation must be called first as we want eBPF
1700b57cec5SDimitry Andric   // Peephole ran at last.
1710b57cec5SDimitry Andric   TargetPassConfig::addMachineSSAOptimization();
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   const BPFSubtarget *Subtarget = getBPFTargetMachine().getSubtargetImpl();
1748bcb0991SDimitry Andric   if (!DisableMIPeephole) {
1758bcb0991SDimitry Andric     if (Subtarget->getHasAlu32())
1760b57cec5SDimitry Andric       addPass(createBPFMIPeepholePass());
1778bcb0991SDimitry Andric   }
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric void BPFPassConfig::addPreEmitPass() {
1810b57cec5SDimitry Andric   addPass(createBPFMIPreEmitCheckingPass());
1825f757f3fSDimitry Andric   if (getOptLevel() != CodeGenOptLevel::None)
1838bcb0991SDimitry Andric     if (!DisableMIPeephole)
1840b57cec5SDimitry Andric       addPass(createBPFMIPreEmitPeepholePass());
1850b57cec5SDimitry Andric }
1865f757f3fSDimitry Andric 
1875f757f3fSDimitry Andric bool BPFPassConfig::addIRTranslator() {
1885f757f3fSDimitry Andric   addPass(new IRTranslator());
1895f757f3fSDimitry Andric   return false;
1905f757f3fSDimitry Andric }
1915f757f3fSDimitry Andric 
1925f757f3fSDimitry Andric bool BPFPassConfig::addLegalizeMachineIR() {
1935f757f3fSDimitry Andric   addPass(new Legalizer());
1945f757f3fSDimitry Andric   return false;
1955f757f3fSDimitry Andric }
1965f757f3fSDimitry Andric 
1975f757f3fSDimitry Andric bool BPFPassConfig::addRegBankSelect() {
1985f757f3fSDimitry Andric   addPass(new RegBankSelect());
1995f757f3fSDimitry Andric   return false;
2005f757f3fSDimitry Andric }
2015f757f3fSDimitry Andric 
2025f757f3fSDimitry Andric bool BPFPassConfig::addGlobalInstructionSelect() {
2035f757f3fSDimitry Andric   addPass(new InstructionSelect(getOptLevel()));
2045f757f3fSDimitry Andric   return false;
2055f757f3fSDimitry Andric }
206