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