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" 321db9f3b2SDimitry Andric #include "llvm/Transforms/Utils.h" 33bdd1243dSDimitry Andric #include <optional> 3481ad6265SDimitry Andric 3581ad6265SDimitry Andric using namespace llvm; 3681ad6265SDimitry Andric 3781ad6265SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTarget() { 3881ad6265SDimitry Andric // Register the target. 3981ad6265SDimitry Andric RegisterTargetMachine<SPIRVTargetMachine> X(getTheSPIRV32Target()); 4081ad6265SDimitry Andric RegisterTargetMachine<SPIRVTargetMachine> Y(getTheSPIRV64Target()); 415f757f3fSDimitry Andric RegisterTargetMachine<SPIRVTargetMachine> Z(getTheSPIRVLogicalTarget()); 4281ad6265SDimitry Andric 4381ad6265SDimitry Andric PassRegistry &PR = *PassRegistry::getPassRegistry(); 4481ad6265SDimitry Andric initializeGlobalISel(PR); 4581ad6265SDimitry Andric initializeSPIRVModuleAnalysisPass(PR); 4681ad6265SDimitry Andric } 4781ad6265SDimitry Andric 4881ad6265SDimitry Andric static std::string computeDataLayout(const Triple &TT) { 4981ad6265SDimitry Andric const auto Arch = TT.getArch(); 505f757f3fSDimitry Andric // TODO: this probably needs to be revisited: 515f757f3fSDimitry Andric // Logical SPIR-V has no pointer size, so any fixed pointer size would be 525f757f3fSDimitry Andric // wrong. The choice to default to 32 or 64 is just motivated by another 535f757f3fSDimitry Andric // memory model used for graphics: PhysicalStorageBuffer64. But it shouldn't 545f757f3fSDimitry Andric // mean anything. 5581ad6265SDimitry Andric if (Arch == Triple::spirv32) 5681ad6265SDimitry Andric return "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-" 5781ad6265SDimitry Andric "v96:128-v192:256-v256:256-v512:512-v1024:1024"; 5881ad6265SDimitry Andric return "e-i64:64-v16:16-v24:32-v32:32-v48:64-" 5981ad6265SDimitry Andric "v96:128-v192:256-v256:256-v512:512-v1024:1024"; 6081ad6265SDimitry Andric } 6181ad6265SDimitry Andric 62bdd1243dSDimitry Andric static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) { 6381ad6265SDimitry Andric if (!RM) 6481ad6265SDimitry Andric return Reloc::PIC_; 6581ad6265SDimitry Andric return *RM; 6681ad6265SDimitry Andric } 6781ad6265SDimitry Andric 6881ad6265SDimitry Andric // Pin SPIRVTargetObjectFile's vtables to this file. 6981ad6265SDimitry Andric SPIRVTargetObjectFile::~SPIRVTargetObjectFile() {} 7081ad6265SDimitry Andric 7181ad6265SDimitry Andric SPIRVTargetMachine::SPIRVTargetMachine(const Target &T, const Triple &TT, 7281ad6265SDimitry Andric StringRef CPU, StringRef FS, 7381ad6265SDimitry Andric const TargetOptions &Options, 74bdd1243dSDimitry Andric std::optional<Reloc::Model> RM, 75bdd1243dSDimitry Andric std::optional<CodeModel::Model> CM, 765f757f3fSDimitry Andric CodeGenOptLevel OL, bool JIT) 7781ad6265SDimitry Andric : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options, 7881ad6265SDimitry Andric getEffectiveRelocModel(RM), 7981ad6265SDimitry Andric getEffectiveCodeModel(CM, CodeModel::Small), OL), 80bdd1243dSDimitry Andric TLOF(std::make_unique<SPIRVTargetObjectFile>()), 8181ad6265SDimitry Andric Subtarget(TT, CPU.str(), FS.str(), *this) { 8281ad6265SDimitry Andric initAsmInfo(); 8381ad6265SDimitry Andric setGlobalISel(true); 8481ad6265SDimitry Andric setFastISel(false); 8581ad6265SDimitry Andric setO0WantsFastISel(false); 8681ad6265SDimitry Andric setRequiresStructuredCFG(false); 8781ad6265SDimitry Andric } 8881ad6265SDimitry Andric 8981ad6265SDimitry Andric namespace { 9081ad6265SDimitry Andric // SPIR-V Code Generator Pass Configuration Options. 9181ad6265SDimitry Andric class SPIRVPassConfig : public TargetPassConfig { 9281ad6265SDimitry Andric public: 9381ad6265SDimitry Andric SPIRVPassConfig(SPIRVTargetMachine &TM, PassManagerBase &PM) 945f757f3fSDimitry Andric : TargetPassConfig(TM, PM), TM(TM) {} 9581ad6265SDimitry Andric 9681ad6265SDimitry Andric SPIRVTargetMachine &getSPIRVTargetMachine() const { 9781ad6265SDimitry Andric return getTM<SPIRVTargetMachine>(); 9881ad6265SDimitry Andric } 9981ad6265SDimitry Andric void addIRPasses() override; 10081ad6265SDimitry Andric void addISelPrepare() override; 10181ad6265SDimitry Andric 10281ad6265SDimitry Andric bool addIRTranslator() override; 10381ad6265SDimitry Andric void addPreLegalizeMachineIR() override; 10481ad6265SDimitry Andric bool addLegalizeMachineIR() override; 10581ad6265SDimitry Andric bool addRegBankSelect() override; 10681ad6265SDimitry Andric bool addGlobalInstructionSelect() override; 10781ad6265SDimitry Andric 10881ad6265SDimitry Andric FunctionPass *createTargetRegisterAllocator(bool) override; 10981ad6265SDimitry Andric void addFastRegAlloc() override {} 11081ad6265SDimitry Andric void addOptimizedRegAlloc() override {} 11181ad6265SDimitry Andric 11281ad6265SDimitry Andric void addPostRegAlloc() override; 1135f757f3fSDimitry Andric 1145f757f3fSDimitry Andric private: 1155f757f3fSDimitry Andric const SPIRVTargetMachine &TM; 11681ad6265SDimitry Andric }; 11781ad6265SDimitry Andric } // namespace 11881ad6265SDimitry Andric 11981ad6265SDimitry Andric // We do not use physical registers, and maintain virtual registers throughout 12081ad6265SDimitry Andric // the entire pipeline, so return nullptr to disable register allocation. 12181ad6265SDimitry Andric FunctionPass *SPIRVPassConfig::createTargetRegisterAllocator(bool) { 12281ad6265SDimitry Andric return nullptr; 12381ad6265SDimitry Andric } 12481ad6265SDimitry Andric 12581ad6265SDimitry Andric // Disable passes that break from assuming no virtual registers exist. 12681ad6265SDimitry Andric void SPIRVPassConfig::addPostRegAlloc() { 12781ad6265SDimitry Andric // Do not work with vregs instead of physical regs. 12881ad6265SDimitry Andric disablePass(&MachineCopyPropagationID); 12981ad6265SDimitry Andric disablePass(&PostRAMachineSinkingID); 13081ad6265SDimitry Andric disablePass(&PostRASchedulerID); 13181ad6265SDimitry Andric disablePass(&FuncletLayoutID); 13281ad6265SDimitry Andric disablePass(&StackMapLivenessID); 13381ad6265SDimitry Andric disablePass(&PatchableFunctionID); 13481ad6265SDimitry Andric disablePass(&ShrinkWrapID); 13581ad6265SDimitry Andric disablePass(&LiveDebugValuesID); 136bdd1243dSDimitry Andric disablePass(&MachineLateInstrsCleanupID); 13781ad6265SDimitry Andric 13881ad6265SDimitry Andric // Do not work with OpPhi. 13981ad6265SDimitry Andric disablePass(&BranchFolderPassID); 14081ad6265SDimitry Andric disablePass(&MachineBlockPlacementID); 14181ad6265SDimitry Andric 14281ad6265SDimitry Andric TargetPassConfig::addPostRegAlloc(); 14381ad6265SDimitry Andric } 14481ad6265SDimitry Andric 14581ad6265SDimitry Andric TargetTransformInfo 14681ad6265SDimitry Andric SPIRVTargetMachine::getTargetTransformInfo(const Function &F) const { 14781ad6265SDimitry Andric return TargetTransformInfo(SPIRVTTIImpl(this, F)); 14881ad6265SDimitry Andric } 14981ad6265SDimitry Andric 15081ad6265SDimitry Andric TargetPassConfig *SPIRVTargetMachine::createPassConfig(PassManagerBase &PM) { 15181ad6265SDimitry Andric return new SPIRVPassConfig(*this, PM); 15281ad6265SDimitry Andric } 15381ad6265SDimitry Andric 154fcaf7f86SDimitry Andric void SPIRVPassConfig::addIRPasses() { 1551db9f3b2SDimitry Andric if (TM.getSubtargetImpl()->isVulkanEnv()) { 1561db9f3b2SDimitry Andric // Once legalized, we need to structurize the CFG to follow the spec. 1571db9f3b2SDimitry Andric // This is done through the following 8 steps. 1581db9f3b2SDimitry Andric // TODO(#75801): add the remaining steps. 1591db9f3b2SDimitry Andric 1601db9f3b2SDimitry Andric // 1. Simplify loop for subsequent transformations. After this steps, loops 1611db9f3b2SDimitry Andric // have the following properties: 1621db9f3b2SDimitry Andric // - loops have a single entry edge (pre-header to loop header). 1631db9f3b2SDimitry Andric // - all loop exits are dominated by the loop pre-header. 1641db9f3b2SDimitry Andric // - loops have a single back-edge. 1651db9f3b2SDimitry Andric addPass(createLoopSimplifyPass()); 1661db9f3b2SDimitry Andric } 1671db9f3b2SDimitry Andric 168fcaf7f86SDimitry Andric TargetPassConfig::addIRPasses(); 169bdd1243dSDimitry Andric addPass(createSPIRVRegularizerPass()); 1705f757f3fSDimitry Andric addPass(createSPIRVPrepareFunctionsPass(TM)); 171*7a6dacacSDimitry Andric addPass(createSPIRVStripConvergenceIntrinsicsPass()); 172fcaf7f86SDimitry Andric } 17381ad6265SDimitry Andric 17481ad6265SDimitry Andric void SPIRVPassConfig::addISelPrepare() { 17581ad6265SDimitry Andric addPass(createSPIRVEmitIntrinsicsPass(&getTM<SPIRVTargetMachine>())); 17681ad6265SDimitry Andric TargetPassConfig::addISelPrepare(); 17781ad6265SDimitry Andric } 17881ad6265SDimitry Andric 17981ad6265SDimitry Andric bool SPIRVPassConfig::addIRTranslator() { 18081ad6265SDimitry Andric addPass(new IRTranslator(getOptLevel())); 18181ad6265SDimitry Andric return false; 18281ad6265SDimitry Andric } 18381ad6265SDimitry Andric 18481ad6265SDimitry Andric void SPIRVPassConfig::addPreLegalizeMachineIR() { 18581ad6265SDimitry Andric addPass(createSPIRVPreLegalizerPass()); 18681ad6265SDimitry Andric } 18781ad6265SDimitry Andric 188bdd1243dSDimitry Andric // Use the default legalizer. 18981ad6265SDimitry Andric bool SPIRVPassConfig::addLegalizeMachineIR() { 19081ad6265SDimitry Andric addPass(new Legalizer()); 19181ad6265SDimitry Andric return false; 19281ad6265SDimitry Andric } 19381ad6265SDimitry Andric 194bdd1243dSDimitry Andric // Do not add the RegBankSelect pass, as we only ever need virtual registers. 19581ad6265SDimitry Andric bool SPIRVPassConfig::addRegBankSelect() { 19681ad6265SDimitry Andric disablePass(&RegBankSelect::ID); 19781ad6265SDimitry Andric return false; 19881ad6265SDimitry Andric } 19981ad6265SDimitry Andric 20081ad6265SDimitry Andric namespace { 20181ad6265SDimitry Andric // A custom subclass of InstructionSelect, which is mostly the same except from 20281ad6265SDimitry Andric // not requiring RegBankSelect to occur previously. 20381ad6265SDimitry Andric class SPIRVInstructionSelect : public InstructionSelect { 20481ad6265SDimitry Andric // We don't use register banks, so unset the requirement for them 20581ad6265SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 20681ad6265SDimitry Andric return InstructionSelect::getRequiredProperties().reset( 20781ad6265SDimitry Andric MachineFunctionProperties::Property::RegBankSelected); 20881ad6265SDimitry Andric } 20981ad6265SDimitry Andric }; 21081ad6265SDimitry Andric } // namespace 21181ad6265SDimitry Andric 212bdd1243dSDimitry Andric // Add the custom SPIRVInstructionSelect from above. 21381ad6265SDimitry Andric bool SPIRVPassConfig::addGlobalInstructionSelect() { 21481ad6265SDimitry Andric addPass(new SPIRVInstructionSelect()); 21581ad6265SDimitry Andric return false; 21681ad6265SDimitry Andric } 217