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