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