271 lines · cpp
1//===- SPIRVTargetMachine.cpp - Define TargetMachine for SPIR-V -*- C++ -*-===//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-exception6//7//===----------------------------------------------------------------------===//8//9// Implements the info about SPIR-V target spec.10//11//===----------------------------------------------------------------------===//12 13#include "SPIRVTargetMachine.h"14#include "SPIRV.h"15#include "SPIRVCBufferAccess.h"16#include "SPIRVGlobalRegistry.h"17#include "SPIRVLegalizerInfo.h"18#include "SPIRVStructurizerWrapper.h"19#include "SPIRVTargetObjectFile.h"20#include "SPIRVTargetTransformInfo.h"21#include "TargetInfo/SPIRVTargetInfo.h"22#include "llvm/CodeGen/GlobalISel/IRTranslator.h"23#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"24#include "llvm/CodeGen/GlobalISel/Legalizer.h"25#include "llvm/CodeGen/GlobalISel/RegBankSelect.h"26#include "llvm/CodeGen/Passes.h"27#include "llvm/CodeGen/TargetPassConfig.h"28#include "llvm/InitializePasses.h"29#include "llvm/MC/TargetRegistry.h"30#include "llvm/Pass.h"31#include "llvm/Passes/PassBuilder.h"32#include "llvm/Support/Compiler.h"33#include "llvm/Target/TargetOptions.h"34#include "llvm/Transforms/Scalar.h"35#include "llvm/Transforms/Utils.h"36#include <optional>37 38using namespace llvm;39 40extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTarget() {41 // Register the target.42 RegisterTargetMachine<SPIRVTargetMachine> X(getTheSPIRV32Target());43 RegisterTargetMachine<SPIRVTargetMachine> Y(getTheSPIRV64Target());44 RegisterTargetMachine<SPIRVTargetMachine> Z(getTheSPIRVLogicalTarget());45 46 PassRegistry &PR = *PassRegistry::getPassRegistry();47 initializeGlobalISel(PR);48 initializeSPIRVModuleAnalysisPass(PR);49 initializeSPIRVAsmPrinterPass(PR);50 initializeSPIRVConvergenceRegionAnalysisWrapperPassPass(PR);51 initializeSPIRVStructurizerPass(PR);52 initializeSPIRVCBufferAccessLegacyPass(PR);53 initializeSPIRVPreLegalizerCombinerPass(PR);54 initializeSPIRVLegalizePointerCastPass(PR);55 initializeSPIRVRegularizerPass(PR);56 initializeSPIRVPreLegalizerPass(PR);57 initializeSPIRVPostLegalizerPass(PR);58 initializeSPIRVMergeRegionExitTargetsPass(PR);59 initializeSPIRVEmitIntrinsicsPass(PR);60 initializeSPIRVEmitNonSemanticDIPass(PR);61 initializeSPIRVPrepareFunctionsPass(PR);62 initializeSPIRVPrepareGlobalsPass(PR);63 initializeSPIRVStripConvergentIntrinsicsPass(PR);64}65 66static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) {67 if (!RM)68 return Reloc::PIC_;69 return *RM;70}71 72// Pin SPIRVTargetObjectFile's vtables to this file.73SPIRVTargetObjectFile::~SPIRVTargetObjectFile() = default;74 75SPIRVTargetMachine::SPIRVTargetMachine(const Target &T, const Triple &TT,76 StringRef CPU, StringRef FS,77 const TargetOptions &Options,78 std::optional<Reloc::Model> RM,79 std::optional<CodeModel::Model> CM,80 CodeGenOptLevel OL, bool JIT)81 : CodeGenTargetMachineImpl(T, TT.computeDataLayout(), TT, CPU, FS, Options,82 getEffectiveRelocModel(RM),83 getEffectiveCodeModel(CM, CodeModel::Small), OL),84 TLOF(std::make_unique<SPIRVTargetObjectFile>()),85 Subtarget(TT, CPU.str(), FS.str(), *this) {86 initAsmInfo();87 setGlobalISel(true);88 setFastISel(false);89 setO0WantsFastISel(false);90 setRequiresStructuredCFG(false);91}92 93void SPIRVTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {94#define GET_PASS_REGISTRY "SPIRVPassRegistry.def"95#include "llvm/Passes/TargetPassRegistry.inc"96}97 98namespace {99// SPIR-V Code Generator Pass Configuration Options.100class SPIRVPassConfig : public TargetPassConfig {101public:102 SPIRVPassConfig(SPIRVTargetMachine &TM, PassManagerBase &PM)103 : TargetPassConfig(TM, PM), TM(TM) {}104 105 SPIRVTargetMachine &getSPIRVTargetMachine() const {106 return getTM<SPIRVTargetMachine>();107 }108 void addMachineSSAOptimization() override;109 void addIRPasses() override;110 void addISelPrepare() override;111 112 bool addIRTranslator() override;113 void addPreLegalizeMachineIR() override;114 bool addLegalizeMachineIR() override;115 bool addRegBankSelect() override;116 bool addGlobalInstructionSelect() override;117 118 FunctionPass *createTargetRegisterAllocator(bool) override;119 void addFastRegAlloc() override {}120 void addOptimizedRegAlloc() override {}121 122 void addPostRegAlloc() override;123 void addPreEmitPass() override;124 125private:126 const SPIRVTargetMachine &TM;127};128} // namespace129 130// We do not use physical registers, and maintain virtual registers throughout131// the entire pipeline, so return nullptr to disable register allocation.132FunctionPass *SPIRVPassConfig::createTargetRegisterAllocator(bool) {133 return nullptr;134}135 136// A place to disable passes that may break CFG.137void SPIRVPassConfig::addMachineSSAOptimization() {138 TargetPassConfig::addMachineSSAOptimization();139}140 141// Disable passes that break from assuming no virtual registers exist.142void SPIRVPassConfig::addPostRegAlloc() {143 // Do not work with vregs instead of physical regs.144 disablePass(&MachineCopyPropagationID);145 disablePass(&PostRAMachineSinkingID);146 disablePass(&PostRASchedulerID);147 disablePass(&FuncletLayoutID);148 disablePass(&StackMapLivenessID);149 disablePass(&PatchableFunctionID);150 disablePass(&ShrinkWrapID);151 disablePass(&LiveDebugValuesID);152 disablePass(&MachineLateInstrsCleanupID);153 disablePass(&RemoveLoadsIntoFakeUsesID);154 155 // Do not work with OpPhi.156 disablePass(&BranchFolderPassID);157 disablePass(&MachineBlockPlacementID);158 159 TargetPassConfig::addPostRegAlloc();160}161 162TargetTransformInfo163SPIRVTargetMachine::getTargetTransformInfo(const Function &F) const {164 return TargetTransformInfo(std::make_unique<SPIRVTTIImpl>(this, F));165}166 167TargetPassConfig *SPIRVTargetMachine::createPassConfig(PassManagerBase &PM) {168 return new SPIRVPassConfig(*this, PM);169}170 171void SPIRVPassConfig::addIRPasses() {172 TargetPassConfig::addIRPasses();173 174 addPass(createSPIRVRegularizerPass());175 addPass(createSPIRVPrepareFunctionsPass(TM));176 addPass(createSPIRVPrepareGlobalsPass());177}178 179void SPIRVPassConfig::addISelPrepare() {180 if (TM.getSubtargetImpl()->isShader()) {181 // Vulkan does not allow address space casts. This pass is run to remove182 // address space casts that can be removed.183 // If an address space cast is not removed while targeting Vulkan, lowering184 // will fail during MIR lowering.185 addPass(createInferAddressSpacesPass());186 187 // 1. Simplify loop for subsequent transformations. After this steps, loops188 // have the following properties:189 // - loops have a single entry edge (pre-header to loop header).190 // - all loop exits are dominated by the loop pre-header.191 // - loops have a single back-edge.192 addPass(createLoopSimplifyPass());193 194 // 2. Removes registers whose lifetime spans across basic blocks. Also195 // removes phi nodes. This will greatly simplify the next steps.196 addPass(createRegToMemWrapperPass());197 198 // 3. Merge the convergence region exit nodes into one. After this step,199 // regions are single-entry, single-exit. This will help determine the200 // correct merge block.201 addPass(createSPIRVMergeRegionExitTargetsPass());202 203 // 4. Structurize.204 addPass(createSPIRVStructurizerPass());205 206 // 5. Reduce the amount of variables required by pushing some operations207 // back to virtual registers.208 addPass(createPromoteMemoryToRegisterPass());209 }210 211 addPass(createSPIRVStripConvergenceIntrinsicsPass());212 addPass(createSPIRVLegalizeImplicitBindingPass());213 addPass(createSPIRVCBufferAccessLegacyPass());214 addPass(createSPIRVEmitIntrinsicsPass(&getTM<SPIRVTargetMachine>()));215 if (TM.getSubtargetImpl()->isLogicalSPIRV())216 addPass(createSPIRVLegalizePointerCastPass(&getTM<SPIRVTargetMachine>()));217 TargetPassConfig::addISelPrepare();218}219 220bool SPIRVPassConfig::addIRTranslator() {221 addPass(new IRTranslator(getOptLevel()));222 return false;223}224 225void SPIRVPassConfig::addPreLegalizeMachineIR() {226 addPass(createSPIRVPreLegalizerCombiner());227 addPass(createSPIRVPreLegalizerPass());228}229 230// Use the default legalizer.231bool SPIRVPassConfig::addLegalizeMachineIR() {232 addPass(new Legalizer());233 addPass(createSPIRVPostLegalizerPass());234 return false;235}236 237// Do not add the RegBankSelect pass, as we only ever need virtual registers.238bool SPIRVPassConfig::addRegBankSelect() {239 disablePass(&RegBankSelect::ID);240 return false;241}242 243static cl::opt<bool> SPVEnableNonSemanticDI(244 "spv-emit-nonsemantic-debug-info",245 cl::desc("Emit SPIR-V NonSemantic.Shader.DebugInfo.100 instructions"),246 cl::Optional, cl::init(false));247 248void SPIRVPassConfig::addPreEmitPass() {249 if (SPVEnableNonSemanticDI ||250 getSPIRVTargetMachine().getTargetTriple().getVendor() == Triple::AMD) {251 addPass(createSPIRVEmitNonSemanticDIPass(&getTM<SPIRVTargetMachine>()));252 }253}254 255namespace {256// A custom subclass of InstructionSelect, which is mostly the same except from257// not requiring RegBankSelect to occur previously.258class SPIRVInstructionSelect : public InstructionSelect {259 // We don't use register banks, so unset the requirement for them260 MachineFunctionProperties getRequiredProperties() const override {261 return InstructionSelect::getRequiredProperties().resetRegBankSelected();262 }263};264} // namespace265 266// Add the custom SPIRVInstructionSelect from above.267bool SPIRVPassConfig::addGlobalInstructionSelect() {268 addPass(new SPIRVInstructionSelect());269 return false;270}271