xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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