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
37using namespace llvm;
38
39extern "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
63static 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
84static 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.
91SPIRVTargetObjectFile::~SPIRVTargetObjectFile() {}
92
93SPIRVTargetMachine::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, Default: 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
111void SPIRVTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
112#define GET_PASS_REGISTRY "SPIRVPassRegistry.def"
113#include "llvm/Passes/TargetPassRegistry.inc"
114}
115
116namespace {
117// SPIR-V Code Generator Pass Configuration Options.
118class SPIRVPassConfig : public TargetPassConfig {
119public:
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
143private:
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.
150FunctionPass *SPIRVPassConfig::createTargetRegisterAllocator(bool) {
151 return nullptr;
152}
153
154// A place to disable passes that may break CFG.
155void SPIRVPassConfig::addMachineSSAOptimization() {
156 TargetPassConfig::addMachineSSAOptimization();
157}
158
159// Disable passes that break from assuming no virtual registers exist.
160void SPIRVPassConfig::addPostRegAlloc() {
161 // Do not work with vregs instead of physical regs.
162 disablePass(PassID: &MachineCopyPropagationID);
163 disablePass(PassID: &PostRAMachineSinkingID);
164 disablePass(PassID: &PostRASchedulerID);
165 disablePass(PassID: &FuncletLayoutID);
166 disablePass(PassID: &StackMapLivenessID);
167 disablePass(PassID: &PatchableFunctionID);
168 disablePass(PassID: &ShrinkWrapID);
169 disablePass(PassID: &LiveDebugValuesID);
170 disablePass(PassID: &MachineLateInstrsCleanupID);
171 disablePass(PassID: &RemoveLoadsIntoFakeUsesID);
172
173 // Do not work with OpPhi.
174 disablePass(PassID: &BranchFolderPassID);
175 disablePass(PassID: &MachineBlockPlacementID);
176
177 TargetPassConfig::addPostRegAlloc();
178}
179
180TargetTransformInfo
181SPIRVTargetMachine::getTargetTransformInfo(const Function &F) const {
182 return TargetTransformInfo(std::make_unique<SPIRVTTIImpl>(args: this, args: F));
183}
184
185TargetPassConfig *SPIRVTargetMachine::createPassConfig(PassManagerBase &PM) {
186 return new SPIRVPassConfig(*this, PM);
187}
188
189void 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(P: 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(P: 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(P: 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(P: createSPIRVMergeRegionExitTargetsPass());
214
215 // 4. Structurize.
216 addPass(P: createSPIRVStructurizerPass());
217
218 // 5. Reduce the amount of variables required by pushing some operations
219 // back to virtual registers.
220 addPass(P: createPromoteMemoryToRegisterPass());
221 }
222
223 addPass(P: createSPIRVRegularizerPass());
224 addPass(P: createSPIRVPrepareFunctionsPass(TM));
225 addPass(P: createSPIRVStripConvergenceIntrinsicsPass());
226}
227
228void SPIRVPassConfig::addISelPrepare() {
229 addPass(P: createSPIRVEmitIntrinsicsPass(TM: &getTM<SPIRVTargetMachine>()));
230 if (TM.getSubtargetImpl()->isLogicalSPIRV())
231 addPass(P: createSPIRVLegalizePointerCastPass(TM: &getTM<SPIRVTargetMachine>()));
232 TargetPassConfig::addISelPrepare();
233}
234
235bool SPIRVPassConfig::addIRTranslator() {
236 addPass(P: new IRTranslator(getOptLevel()));
237 return false;
238}
239
240void SPIRVPassConfig::addPreLegalizeMachineIR() {
241 addPass(P: createSPIRVPreLegalizerCombiner());
242 addPass(P: createSPIRVPreLegalizerPass());
243}
244
245// Use the default legalizer.
246bool SPIRVPassConfig::addLegalizeMachineIR() {
247 addPass(P: new Legalizer());
248 addPass(P: createSPIRVPostLegalizerPass());
249 return false;
250}
251
252// Do not add the RegBankSelect pass, as we only ever need virtual registers.
253bool SPIRVPassConfig::addRegBankSelect() {
254 disablePass(PassID: &RegBankSelect::ID);
255 return false;
256}
257
258static 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(Val: false));
262
263void SPIRVPassConfig::addPreEmitPass() {
264 if (SPVEnableNonSemanticDI) {
265 addPass(P: createSPIRVEmitNonSemanticDIPass(TM: &getTM<SPIRVTargetMachine>()));
266 }
267}
268
269namespace {
270// A custom subclass of InstructionSelect, which is mostly the same except from
271// not requiring RegBankSelect to occur previously.
272class 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.
281bool SPIRVPassConfig::addGlobalInstructionSelect() {
282 addPass(P: new SPIRVInstructionSelect());
283 return false;
284}
285