xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
181ad6265SDimitry Andric //===- SPIRVTargetMachine.cpp - Define TargetMachine for SPIR-V -*- C++ -*-===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // Implements the info about SPIR-V target spec.
1081ad6265SDimitry Andric //
1181ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1281ad6265SDimitry Andric 
1381ad6265SDimitry Andric #include "SPIRVTargetMachine.h"
1481ad6265SDimitry Andric #include "SPIRV.h"
1581ad6265SDimitry Andric #include "SPIRVCallLowering.h"
1681ad6265SDimitry Andric #include "SPIRVGlobalRegistry.h"
1781ad6265SDimitry Andric #include "SPIRVLegalizerInfo.h"
1881ad6265SDimitry Andric #include "SPIRVTargetObjectFile.h"
1981ad6265SDimitry Andric #include "SPIRVTargetTransformInfo.h"
2081ad6265SDimitry Andric #include "TargetInfo/SPIRVTargetInfo.h"
2181ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/IRTranslator.h"
2281ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
2381ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/Legalizer.h"
2481ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/RegBankSelect.h"
2581ad6265SDimitry Andric #include "llvm/CodeGen/Passes.h"
2681ad6265SDimitry Andric #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
2781ad6265SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
2881ad6265SDimitry Andric #include "llvm/InitializePasses.h"
2981ad6265SDimitry Andric #include "llvm/MC/TargetRegistry.h"
3081ad6265SDimitry Andric #include "llvm/Pass.h"
3181ad6265SDimitry Andric #include "llvm/Target/TargetOptions.h"
32bdd1243dSDimitry Andric #include <optional>
3381ad6265SDimitry Andric 
3481ad6265SDimitry Andric using namespace llvm;
3581ad6265SDimitry Andric 
3681ad6265SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTarget() {
3781ad6265SDimitry Andric   // Register the target.
3881ad6265SDimitry Andric   RegisterTargetMachine<SPIRVTargetMachine> X(getTheSPIRV32Target());
3981ad6265SDimitry Andric   RegisterTargetMachine<SPIRVTargetMachine> Y(getTheSPIRV64Target());
40*5f757f3fSDimitry Andric   RegisterTargetMachine<SPIRVTargetMachine> Z(getTheSPIRVLogicalTarget());
4181ad6265SDimitry Andric 
4281ad6265SDimitry Andric   PassRegistry &PR = *PassRegistry::getPassRegistry();
4381ad6265SDimitry Andric   initializeGlobalISel(PR);
4481ad6265SDimitry Andric   initializeSPIRVModuleAnalysisPass(PR);
4581ad6265SDimitry Andric }
4681ad6265SDimitry Andric 
4781ad6265SDimitry Andric static std::string computeDataLayout(const Triple &TT) {
4881ad6265SDimitry Andric   const auto Arch = TT.getArch();
49*5f757f3fSDimitry Andric   // TODO: this probably needs to be revisited:
50*5f757f3fSDimitry Andric   // Logical SPIR-V has no pointer size, so any fixed pointer size would be
51*5f757f3fSDimitry Andric   // wrong. The choice to default to 32 or 64 is just motivated by another
52*5f757f3fSDimitry Andric   // memory model used for graphics: PhysicalStorageBuffer64. But it shouldn't
53*5f757f3fSDimitry Andric   // mean anything.
5481ad6265SDimitry Andric   if (Arch == Triple::spirv32)
5581ad6265SDimitry Andric     return "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"
5681ad6265SDimitry Andric            "v96:128-v192:256-v256:256-v512:512-v1024:1024";
5781ad6265SDimitry Andric   return "e-i64:64-v16:16-v24:32-v32:32-v48:64-"
5881ad6265SDimitry Andric          "v96:128-v192:256-v256:256-v512:512-v1024:1024";
5981ad6265SDimitry Andric }
6081ad6265SDimitry Andric 
61bdd1243dSDimitry Andric static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) {
6281ad6265SDimitry Andric   if (!RM)
6381ad6265SDimitry Andric     return Reloc::PIC_;
6481ad6265SDimitry Andric   return *RM;
6581ad6265SDimitry Andric }
6681ad6265SDimitry Andric 
6781ad6265SDimitry Andric // Pin SPIRVTargetObjectFile's vtables to this file.
6881ad6265SDimitry Andric SPIRVTargetObjectFile::~SPIRVTargetObjectFile() {}
6981ad6265SDimitry Andric 
7081ad6265SDimitry Andric SPIRVTargetMachine::SPIRVTargetMachine(const Target &T, const Triple &TT,
7181ad6265SDimitry Andric                                        StringRef CPU, StringRef FS,
7281ad6265SDimitry Andric                                        const TargetOptions &Options,
73bdd1243dSDimitry Andric                                        std::optional<Reloc::Model> RM,
74bdd1243dSDimitry Andric                                        std::optional<CodeModel::Model> CM,
75*5f757f3fSDimitry Andric                                        CodeGenOptLevel OL, bool JIT)
7681ad6265SDimitry Andric     : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options,
7781ad6265SDimitry Andric                         getEffectiveRelocModel(RM),
7881ad6265SDimitry Andric                         getEffectiveCodeModel(CM, CodeModel::Small), OL),
79bdd1243dSDimitry Andric       TLOF(std::make_unique<SPIRVTargetObjectFile>()),
8081ad6265SDimitry Andric       Subtarget(TT, CPU.str(), FS.str(), *this) {
8181ad6265SDimitry Andric   initAsmInfo();
8281ad6265SDimitry Andric   setGlobalISel(true);
8381ad6265SDimitry Andric   setFastISel(false);
8481ad6265SDimitry Andric   setO0WantsFastISel(false);
8581ad6265SDimitry Andric   setRequiresStructuredCFG(false);
8681ad6265SDimitry Andric }
8781ad6265SDimitry Andric 
8881ad6265SDimitry Andric namespace {
8981ad6265SDimitry Andric // SPIR-V Code Generator Pass Configuration Options.
9081ad6265SDimitry Andric class SPIRVPassConfig : public TargetPassConfig {
9181ad6265SDimitry Andric public:
9281ad6265SDimitry Andric   SPIRVPassConfig(SPIRVTargetMachine &TM, PassManagerBase &PM)
93*5f757f3fSDimitry Andric       : TargetPassConfig(TM, PM), TM(TM) {}
9481ad6265SDimitry Andric 
9581ad6265SDimitry Andric   SPIRVTargetMachine &getSPIRVTargetMachine() const {
9681ad6265SDimitry Andric     return getTM<SPIRVTargetMachine>();
9781ad6265SDimitry Andric   }
9881ad6265SDimitry Andric   void addIRPasses() override;
9981ad6265SDimitry Andric   void addISelPrepare() override;
10081ad6265SDimitry Andric 
10181ad6265SDimitry Andric   bool addIRTranslator() override;
10281ad6265SDimitry Andric   void addPreLegalizeMachineIR() override;
10381ad6265SDimitry Andric   bool addLegalizeMachineIR() override;
10481ad6265SDimitry Andric   bool addRegBankSelect() override;
10581ad6265SDimitry Andric   bool addGlobalInstructionSelect() override;
10681ad6265SDimitry Andric 
10781ad6265SDimitry Andric   FunctionPass *createTargetRegisterAllocator(bool) override;
10881ad6265SDimitry Andric   void addFastRegAlloc() override {}
10981ad6265SDimitry Andric   void addOptimizedRegAlloc() override {}
11081ad6265SDimitry Andric 
11181ad6265SDimitry Andric   void addPostRegAlloc() override;
112*5f757f3fSDimitry Andric 
113*5f757f3fSDimitry Andric private:
114*5f757f3fSDimitry Andric   const SPIRVTargetMachine &TM;
11581ad6265SDimitry Andric };
11681ad6265SDimitry Andric } // namespace
11781ad6265SDimitry Andric 
11881ad6265SDimitry Andric // We do not use physical registers, and maintain virtual registers throughout
11981ad6265SDimitry Andric // the entire pipeline, so return nullptr to disable register allocation.
12081ad6265SDimitry Andric FunctionPass *SPIRVPassConfig::createTargetRegisterAllocator(bool) {
12181ad6265SDimitry Andric   return nullptr;
12281ad6265SDimitry Andric }
12381ad6265SDimitry Andric 
12481ad6265SDimitry Andric // Disable passes that break from assuming no virtual registers exist.
12581ad6265SDimitry Andric void SPIRVPassConfig::addPostRegAlloc() {
12681ad6265SDimitry Andric   // Do not work with vregs instead of physical regs.
12781ad6265SDimitry Andric   disablePass(&MachineCopyPropagationID);
12881ad6265SDimitry Andric   disablePass(&PostRAMachineSinkingID);
12981ad6265SDimitry Andric   disablePass(&PostRASchedulerID);
13081ad6265SDimitry Andric   disablePass(&FuncletLayoutID);
13181ad6265SDimitry Andric   disablePass(&StackMapLivenessID);
13281ad6265SDimitry Andric   disablePass(&PatchableFunctionID);
13381ad6265SDimitry Andric   disablePass(&ShrinkWrapID);
13481ad6265SDimitry Andric   disablePass(&LiveDebugValuesID);
135bdd1243dSDimitry Andric   disablePass(&MachineLateInstrsCleanupID);
13681ad6265SDimitry Andric 
13781ad6265SDimitry Andric   // Do not work with OpPhi.
13881ad6265SDimitry Andric   disablePass(&BranchFolderPassID);
13981ad6265SDimitry Andric   disablePass(&MachineBlockPlacementID);
14081ad6265SDimitry Andric 
14181ad6265SDimitry Andric   TargetPassConfig::addPostRegAlloc();
14281ad6265SDimitry Andric }
14381ad6265SDimitry Andric 
14481ad6265SDimitry Andric TargetTransformInfo
14581ad6265SDimitry Andric SPIRVTargetMachine::getTargetTransformInfo(const Function &F) const {
14681ad6265SDimitry Andric   return TargetTransformInfo(SPIRVTTIImpl(this, F));
14781ad6265SDimitry Andric }
14881ad6265SDimitry Andric 
14981ad6265SDimitry Andric TargetPassConfig *SPIRVTargetMachine::createPassConfig(PassManagerBase &PM) {
15081ad6265SDimitry Andric   return new SPIRVPassConfig(*this, PM);
15181ad6265SDimitry Andric }
15281ad6265SDimitry Andric 
153fcaf7f86SDimitry Andric void SPIRVPassConfig::addIRPasses() {
154fcaf7f86SDimitry Andric   TargetPassConfig::addIRPasses();
155bdd1243dSDimitry Andric   addPass(createSPIRVRegularizerPass());
156*5f757f3fSDimitry Andric   addPass(createSPIRVPrepareFunctionsPass(TM));
157fcaf7f86SDimitry Andric }
15881ad6265SDimitry Andric 
15981ad6265SDimitry Andric void SPIRVPassConfig::addISelPrepare() {
16081ad6265SDimitry Andric   addPass(createSPIRVEmitIntrinsicsPass(&getTM<SPIRVTargetMachine>()));
16181ad6265SDimitry Andric   TargetPassConfig::addISelPrepare();
16281ad6265SDimitry Andric }
16381ad6265SDimitry Andric 
16481ad6265SDimitry Andric bool SPIRVPassConfig::addIRTranslator() {
16581ad6265SDimitry Andric   addPass(new IRTranslator(getOptLevel()));
16681ad6265SDimitry Andric   return false;
16781ad6265SDimitry Andric }
16881ad6265SDimitry Andric 
16981ad6265SDimitry Andric void SPIRVPassConfig::addPreLegalizeMachineIR() {
17081ad6265SDimitry Andric   addPass(createSPIRVPreLegalizerPass());
17181ad6265SDimitry Andric }
17281ad6265SDimitry Andric 
173bdd1243dSDimitry Andric // Use the default legalizer.
17481ad6265SDimitry Andric bool SPIRVPassConfig::addLegalizeMachineIR() {
17581ad6265SDimitry Andric   addPass(new Legalizer());
17681ad6265SDimitry Andric   return false;
17781ad6265SDimitry Andric }
17881ad6265SDimitry Andric 
179bdd1243dSDimitry Andric // Do not add the RegBankSelect pass, as we only ever need virtual registers.
18081ad6265SDimitry Andric bool SPIRVPassConfig::addRegBankSelect() {
18181ad6265SDimitry Andric   disablePass(&RegBankSelect::ID);
18281ad6265SDimitry Andric   return false;
18381ad6265SDimitry Andric }
18481ad6265SDimitry Andric 
18581ad6265SDimitry Andric namespace {
18681ad6265SDimitry Andric // A custom subclass of InstructionSelect, which is mostly the same except from
18781ad6265SDimitry Andric // not requiring RegBankSelect to occur previously.
18881ad6265SDimitry Andric class SPIRVInstructionSelect : public InstructionSelect {
18981ad6265SDimitry Andric   // We don't use register banks, so unset the requirement for them
19081ad6265SDimitry Andric   MachineFunctionProperties getRequiredProperties() const override {
19181ad6265SDimitry Andric     return InstructionSelect::getRequiredProperties().reset(
19281ad6265SDimitry Andric         MachineFunctionProperties::Property::RegBankSelected);
19381ad6265SDimitry Andric   }
19481ad6265SDimitry Andric };
19581ad6265SDimitry Andric } // namespace
19681ad6265SDimitry Andric 
197bdd1243dSDimitry Andric // Add the custom SPIRVInstructionSelect from above.
19881ad6265SDimitry Andric bool SPIRVPassConfig::addGlobalInstructionSelect() {
19981ad6265SDimitry Andric   addPass(new SPIRVInstructionSelect());
20081ad6265SDimitry Andric   return false;
20181ad6265SDimitry Andric }
202