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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Implements the info about SPIR-V target spec. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "SPIRVTargetMachine.h" 14 #include "SPIRV.h" 15 #include "SPIRVCallLowering.h" 16 #include "SPIRVGlobalRegistry.h" 17 #include "SPIRVLegalizerInfo.h" 18 #include "SPIRVTargetObjectFile.h" 19 #include "SPIRVTargetTransformInfo.h" 20 #include "TargetInfo/SPIRVTargetInfo.h" 21 #include "llvm/CodeGen/GlobalISel/IRTranslator.h" 22 #include "llvm/CodeGen/GlobalISel/InstructionSelect.h" 23 #include "llvm/CodeGen/GlobalISel/Legalizer.h" 24 #include "llvm/CodeGen/GlobalISel/RegBankSelect.h" 25 #include "llvm/CodeGen/Passes.h" 26 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.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/Target/TargetOptions.h" 32 #include "llvm/Transforms/Utils.h" 33 #include <optional> 34 35 using namespace llvm; 36 37 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTarget() { 38 // Register the target. 39 RegisterTargetMachine<SPIRVTargetMachine> X(getTheSPIRV32Target()); 40 RegisterTargetMachine<SPIRVTargetMachine> Y(getTheSPIRV64Target()); 41 RegisterTargetMachine<SPIRVTargetMachine> Z(getTheSPIRVLogicalTarget()); 42 43 PassRegistry &PR = *PassRegistry::getPassRegistry(); 44 initializeGlobalISel(PR); 45 initializeSPIRVModuleAnalysisPass(PR); 46 initializeSPIRVConvergenceRegionAnalysisWrapperPassPass(PR); 47 } 48 49 static std::string computeDataLayout(const Triple &TT) { 50 const auto Arch = TT.getArch(); 51 // TODO: this probably needs to be revisited: 52 // Logical SPIR-V has no pointer size, so any fixed pointer size would be 53 // wrong. The choice to default to 32 or 64 is just motivated by another 54 // memory model used for graphics: PhysicalStorageBuffer64. But it shouldn't 55 // mean anything. 56 if (Arch == Triple::spirv32) 57 return "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-" 58 "v96:128-v192:256-v256:256-v512:512-v1024:1024-G1"; 59 if (TT.getVendor() == Triple::VendorType::AMD && 60 TT.getOS() == Triple::OSType::AMDHSA) 61 return "e-i64:64-v16:16-v24:32-v32:32-v48:64-" 62 "v96:128-v192:256-v256:256-v512:512-v1024:1024-G1-P4-A0"; 63 return "e-i64:64-v16:16-v24:32-v32:32-v48:64-" 64 "v96:128-v192:256-v256:256-v512:512-v1024:1024-G1"; 65 } 66 67 static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) { 68 if (!RM) 69 return Reloc::PIC_; 70 return *RM; 71 } 72 73 // Pin SPIRVTargetObjectFile's vtables to this file. 74 SPIRVTargetObjectFile::~SPIRVTargetObjectFile() {} 75 76 SPIRVTargetMachine::SPIRVTargetMachine(const Target &T, const Triple &TT, 77 StringRef CPU, StringRef FS, 78 const TargetOptions &Options, 79 std::optional<Reloc::Model> RM, 80 std::optional<CodeModel::Model> CM, 81 CodeGenOptLevel OL, bool JIT) 82 : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options, 83 getEffectiveRelocModel(RM), 84 getEffectiveCodeModel(CM, CodeModel::Small), OL), 85 TLOF(std::make_unique<SPIRVTargetObjectFile>()), 86 Subtarget(TT, CPU.str(), FS.str(), *this) { 87 initAsmInfo(); 88 setGlobalISel(true); 89 setFastISel(false); 90 setO0WantsFastISel(false); 91 setRequiresStructuredCFG(false); 92 } 93 94 namespace { 95 // SPIR-V Code Generator Pass Configuration Options. 96 class SPIRVPassConfig : public TargetPassConfig { 97 public: 98 SPIRVPassConfig(SPIRVTargetMachine &TM, PassManagerBase &PM) 99 : TargetPassConfig(TM, PM), TM(TM) {} 100 101 SPIRVTargetMachine &getSPIRVTargetMachine() const { 102 return getTM<SPIRVTargetMachine>(); 103 } 104 void addIRPasses() override; 105 void addISelPrepare() override; 106 107 bool addIRTranslator() override; 108 void addPreLegalizeMachineIR() override; 109 bool addLegalizeMachineIR() override; 110 bool addRegBankSelect() override; 111 bool addGlobalInstructionSelect() override; 112 113 FunctionPass *createTargetRegisterAllocator(bool) override; 114 void addFastRegAlloc() override {} 115 void addOptimizedRegAlloc() override {} 116 117 void addPostRegAlloc() override; 118 119 private: 120 const SPIRVTargetMachine &TM; 121 }; 122 } // namespace 123 124 // We do not use physical registers, and maintain virtual registers throughout 125 // the entire pipeline, so return nullptr to disable register allocation. 126 FunctionPass *SPIRVPassConfig::createTargetRegisterAllocator(bool) { 127 return nullptr; 128 } 129 130 // Disable passes that break from assuming no virtual registers exist. 131 void SPIRVPassConfig::addPostRegAlloc() { 132 // Do not work with vregs instead of physical regs. 133 disablePass(&MachineCopyPropagationID); 134 disablePass(&PostRAMachineSinkingID); 135 disablePass(&PostRASchedulerID); 136 disablePass(&FuncletLayoutID); 137 disablePass(&StackMapLivenessID); 138 disablePass(&PatchableFunctionID); 139 disablePass(&ShrinkWrapID); 140 disablePass(&LiveDebugValuesID); 141 disablePass(&MachineLateInstrsCleanupID); 142 143 // Do not work with OpPhi. 144 disablePass(&BranchFolderPassID); 145 disablePass(&MachineBlockPlacementID); 146 147 TargetPassConfig::addPostRegAlloc(); 148 } 149 150 TargetTransformInfo 151 SPIRVTargetMachine::getTargetTransformInfo(const Function &F) const { 152 return TargetTransformInfo(SPIRVTTIImpl(this, F)); 153 } 154 155 TargetPassConfig *SPIRVTargetMachine::createPassConfig(PassManagerBase &PM) { 156 return new SPIRVPassConfig(*this, PM); 157 } 158 159 void SPIRVPassConfig::addIRPasses() { 160 if (TM.getSubtargetImpl()->isVulkanEnv()) { 161 // Once legalized, we need to structurize the CFG to follow the spec. 162 // This is done through the following 8 steps. 163 // TODO(#75801): add the remaining steps. 164 165 // 1. Simplify loop for subsequent transformations. After this steps, loops 166 // have the following properties: 167 // - loops have a single entry edge (pre-header to loop header). 168 // - all loop exits are dominated by the loop pre-header. 169 // - loops have a single back-edge. 170 addPass(createLoopSimplifyPass()); 171 172 // 2. Merge the convergence region exit nodes into one. After this step, 173 // regions are single-entry, single-exit. This will help determine the 174 // correct merge block. 175 addPass(createSPIRVMergeRegionExitTargetsPass()); 176 } 177 178 TargetPassConfig::addIRPasses(); 179 addPass(createSPIRVRegularizerPass()); 180 addPass(createSPIRVPrepareFunctionsPass(TM)); 181 addPass(createSPIRVStripConvergenceIntrinsicsPass()); 182 } 183 184 void SPIRVPassConfig::addISelPrepare() { 185 addPass(createSPIRVEmitIntrinsicsPass(&getTM<SPIRVTargetMachine>())); 186 TargetPassConfig::addISelPrepare(); 187 } 188 189 bool SPIRVPassConfig::addIRTranslator() { 190 addPass(new IRTranslator(getOptLevel())); 191 return false; 192 } 193 194 void SPIRVPassConfig::addPreLegalizeMachineIR() { 195 addPass(createSPIRVPreLegalizerPass()); 196 } 197 198 // Use the default legalizer. 199 bool SPIRVPassConfig::addLegalizeMachineIR() { 200 addPass(new Legalizer()); 201 addPass(createSPIRVPostLegalizerPass()); 202 return false; 203 } 204 205 // Do not add the RegBankSelect pass, as we only ever need virtual registers. 206 bool SPIRVPassConfig::addRegBankSelect() { 207 disablePass(&RegBankSelect::ID); 208 return false; 209 } 210 211 namespace { 212 // A custom subclass of InstructionSelect, which is mostly the same except from 213 // not requiring RegBankSelect to occur previously. 214 class SPIRVInstructionSelect : public InstructionSelect { 215 // We don't use register banks, so unset the requirement for them 216 MachineFunctionProperties getRequiredProperties() const override { 217 return InstructionSelect::getRequiredProperties().reset( 218 MachineFunctionProperties::Property::RegBankSelected); 219 } 220 }; 221 } // namespace 222 223 // Add the custom SPIRVInstructionSelect from above. 224 bool SPIRVPassConfig::addGlobalInstructionSelect() { 225 addPass(new SPIRVInstructionSelect()); 226 return false; 227 } 228