| //===- SPIRVTargetMachine.cpp - Define TargetMachine for SPIR-V -*- C++ -*-===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // Implements the info about SPIR-V target spec. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "SPIRVTargetMachine.h" | |
| #include "SPIRV.h" | |
| #include "SPIRVCallLowering.h" | |
| #include "SPIRVGlobalRegistry.h" | |
| #include "SPIRVLegalizerInfo.h" | |
| #include "SPIRVTargetObjectFile.h" | |
| #include "SPIRVTargetTransformInfo.h" | |
| #include "TargetInfo/SPIRVTargetInfo.h" | |
| #include "llvm/CodeGen/GlobalISel/IRTranslator.h" | |
| #include "llvm/CodeGen/GlobalISel/InstructionSelect.h" | |
| #include "llvm/CodeGen/GlobalISel/Legalizer.h" | |
| #include "llvm/CodeGen/GlobalISel/RegBankSelect.h" | |
| #include "llvm/CodeGen/Passes.h" | |
| #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" | |
| #include "llvm/CodeGen/TargetPassConfig.h" | |
| #include "llvm/IR/LegacyPassManager.h" | |
| #include "llvm/InitializePasses.h" | |
| #include "llvm/MC/TargetRegistry.h" | |
| #include "llvm/Pass.h" | |
| #include "llvm/Target/TargetOptions.h" | |
| #include <optional> | |
| using namespace llvm; | |
| extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTarget() { | |
| // Register the target. | |
| RegisterTargetMachine<SPIRVTargetMachine> X(getTheSPIRV32Target()); | |
| RegisterTargetMachine<SPIRVTargetMachine> Y(getTheSPIRV64Target()); | |
| PassRegistry &PR = *PassRegistry::getPassRegistry(); | |
| initializeGlobalISel(PR); | |
| initializeSPIRVModuleAnalysisPass(PR); | |
| } | |
| static std::string computeDataLayout(const Triple &TT) { | |
| const auto Arch = TT.getArch(); | |
| if (Arch == Triple::spirv32) | |
| return "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-" | |
| "v96:128-v192:256-v256:256-v512:512-v1024:1024"; | |
| return "e-i64:64-v16:16-v24:32-v32:32-v48:64-" | |
| "v96:128-v192:256-v256:256-v512:512-v1024:1024"; | |
| } | |
| static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) { | |
| if (!RM) | |
| return Reloc::PIC_; | |
| return *RM; | |
| } | |
| // Pin SPIRVTargetObjectFile's vtables to this file. | |
| SPIRVTargetObjectFile::~SPIRVTargetObjectFile() {} | |
| SPIRVTargetMachine::SPIRVTargetMachine(const Target &T, const Triple &TT, | |
| StringRef CPU, StringRef FS, | |
| const TargetOptions &Options, | |
| std::optional<Reloc::Model> RM, | |
| std::optional<CodeModel::Model> CM, | |
| CodeGenOpt::Level OL, bool JIT) | |
| : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options, | |
| getEffectiveRelocModel(RM), | |
| getEffectiveCodeModel(CM, CodeModel::Small), OL), | |
| TLOF(std::make_unique<SPIRVTargetObjectFile>()), | |
| Subtarget(TT, CPU.str(), FS.str(), *this) { | |
| initAsmInfo(); | |
| setGlobalISel(true); | |
| setFastISel(false); | |
| setO0WantsFastISel(false); | |
| setRequiresStructuredCFG(false); | |
| } | |
| namespace { | |
| // SPIR-V Code Generator Pass Configuration Options. | |
| class SPIRVPassConfig : public TargetPassConfig { | |
| public: | |
| SPIRVPassConfig(SPIRVTargetMachine &TM, PassManagerBase &PM) | |
| : TargetPassConfig(TM, PM) {} | |
| SPIRVTargetMachine &getSPIRVTargetMachine() const { | |
| return getTM<SPIRVTargetMachine>(); | |
| } | |
| void addIRPasses() override; | |
| void addISelPrepare() override; | |
| bool addIRTranslator() override; | |
| void addPreLegalizeMachineIR() override; | |
| bool addLegalizeMachineIR() override; | |
| bool addRegBankSelect() override; | |
| bool addGlobalInstructionSelect() override; | |
| FunctionPass *createTargetRegisterAllocator(bool) override; | |
| void addFastRegAlloc() override {} | |
| void addOptimizedRegAlloc() override {} | |
| void addPostRegAlloc() override; | |
| }; | |
| } // namespace | |
| // We do not use physical registers, and maintain virtual registers throughout | |
| // the entire pipeline, so return nullptr to disable register allocation. | |
| FunctionPass *SPIRVPassConfig::createTargetRegisterAllocator(bool) { | |
| return nullptr; | |
| } | |
| // Disable passes that break from assuming no virtual registers exist. | |
| void SPIRVPassConfig::addPostRegAlloc() { | |
| // Do not work with vregs instead of physical regs. | |
| disablePass(&MachineCopyPropagationID); | |
| disablePass(&PostRAMachineSinkingID); | |
| disablePass(&PostRASchedulerID); | |
| disablePass(&FuncletLayoutID); | |
| disablePass(&StackMapLivenessID); | |
| disablePass(&PatchableFunctionID); | |
| disablePass(&ShrinkWrapID); | |
| disablePass(&LiveDebugValuesID); | |
| disablePass(&MachineLateInstrsCleanupID); | |
| // Do not work with OpPhi. | |
| disablePass(&BranchFolderPassID); | |
| disablePass(&MachineBlockPlacementID); | |
| TargetPassConfig::addPostRegAlloc(); | |
| } | |
| TargetTransformInfo | |
| SPIRVTargetMachine::getTargetTransformInfo(const Function &F) const { | |
| return TargetTransformInfo(SPIRVTTIImpl(this, F)); | |
| } | |
| TargetPassConfig *SPIRVTargetMachine::createPassConfig(PassManagerBase &PM) { | |
| return new SPIRVPassConfig(*this, PM); | |
| } | |
| void SPIRVPassConfig::addIRPasses() { | |
| TargetPassConfig::addIRPasses(); | |
| addPass(createSPIRVRegularizerPass()); | |
| addPass(createSPIRVPrepareFunctionsPass()); | |
| } | |
| void SPIRVPassConfig::addISelPrepare() { | |
| addPass(createSPIRVEmitIntrinsicsPass(&getTM<SPIRVTargetMachine>())); | |
| TargetPassConfig::addISelPrepare(); | |
| } | |
| bool SPIRVPassConfig::addIRTranslator() { | |
| addPass(new IRTranslator(getOptLevel())); | |
| return false; | |
| } | |
| void SPIRVPassConfig::addPreLegalizeMachineIR() { | |
| addPass(createSPIRVPreLegalizerPass()); | |
| } | |
| // Use the default legalizer. | |
| bool SPIRVPassConfig::addLegalizeMachineIR() { | |
| addPass(new Legalizer()); | |
| return false; | |
| } | |
| // Do not add the RegBankSelect pass, as we only ever need virtual registers. | |
| bool SPIRVPassConfig::addRegBankSelect() { | |
| disablePass(&RegBankSelect::ID); | |
| return false; | |
| } | |
| namespace { | |
| // A custom subclass of InstructionSelect, which is mostly the same except from | |
| // not requiring RegBankSelect to occur previously. | |
| class SPIRVInstructionSelect : public InstructionSelect { | |
| // We don't use register banks, so unset the requirement for them | |
| MachineFunctionProperties getRequiredProperties() const override { | |
| return InstructionSelect::getRequiredProperties().reset( | |
| MachineFunctionProperties::Property::RegBankSelected); | |
| } | |
| }; | |
| } // namespace | |
| // Add the custom SPIRVInstructionSelect from above. | |
| bool SPIRVPassConfig::addGlobalInstructionSelect() { | |
| addPass(new SPIRVInstructionSelect()); | |
| return false; | |
| } |