| //===- 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; |
| } |