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