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 "Analysis/SPIRVConvergenceRegionAnalysis.h"
15#include "SPIRV.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/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/CodeGen.h"
32#include "llvm/Support/Compiler.h"
33#include "llvm/Target/TargetOptions.h"
34#include "llvm/Transforms/IPO/ExpandVariadics.h"
35#include "llvm/Transforms/Scalar.h"
36#include "llvm/Transforms/Utils.h"
37#include <optional>
38
39using namespace llvm;
40
41extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTarget() {
42 // Register the target.
43 RegisterTargetMachine<SPIRVTargetMachine> X(getTheSPIRV32Target());
44 RegisterTargetMachine<SPIRVTargetMachine> Y(getTheSPIRV64Target());
45 RegisterTargetMachine<SPIRVTargetMachine> Z(getTheSPIRVLogicalTarget());
46
47 PassRegistry &PR = *PassRegistry::getPassRegistry();
48 initializeGlobalISel(PR);
49 initializeSPIRVModuleAnalysisWrapperPassPass(PR);
50 initializeSPIRVAsmPrinterPass(PR);
51 initializeSPIRVConvergenceRegionAnalysisWrapperPassPass(PR);
52 initializeSPIRVStructurizerPass(PR);
53 initializeSPIRVCBufferAccessLegacyPass(PR);
54 initializeSPIRVPushConstantAccessLegacyPass(PR);
55 initializeSPIRVPreLegalizerCombinerLegacyPass(PR);
56 initializeSPIRVLegalizePointerCastLegacyPass(PR);
57 initializeSPIRVLegalizeZeroSizeArraysLegacyPass(PR);
58 initializeSPIRVRegularizerLegacyPass(PR);
59 initializeSPIRVPreLegalizerLegacyPass(PR);
60 initializeSPIRVPostLegalizerLegacyPass(PR);
61 initializeSPIRVPrepareModuleAnalysisLegacyPass(PR);
62 initializeSPIRVMergeRegionExitTargetsLegacyPass(PR);
63 initializeSPIRVEmitIntrinsicsLegacyPass(PR);
64 initializeSPIRVPrepareFunctionsLegacyPass(PR);
65 initializeSPIRVPrepareGlobalsLegacyPass(PR);
66 initializeSPIRVLegalizeResourceBindingLegacyPass(PR);
67 initializeSPIRVCtorDtorLoweringLegacyPass(PR);
68 initializeSPIRVFinalizeShaderLinkageLegacyPass(PR);
69}
70
71static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) {
72 if (!RM)
73 return Reloc::PIC_;
74 return *RM;
75}
76
77// Pin SPIRVTargetObjectFile's vtables to this file.
78SPIRVTargetObjectFile::~SPIRVTargetObjectFile() = default;
79
80SPIRVTargetMachine::SPIRVTargetMachine(const Target &T, const Triple &TT,
81 StringRef CPU, StringRef FS,
82 const TargetOptions &Options,
83 std::optional<Reloc::Model> RM,
84 std::optional<CodeModel::Model> CM,
85 CodeGenOptLevel OL, bool JIT)
86 : CodeGenTargetMachineImpl(T, TT, CPU, FS, Options,
87 getEffectiveRelocModel(RM),
88 getEffectiveCodeModel(CM, Default: CodeModel::Small), OL),
89 TLOF(std::make_unique<SPIRVTargetObjectFile>()),
90 Subtarget(TT, CPU.str(), FS.str(), *this) {
91 initAsmInfo();
92 setGlobalISel(true);
93 setFastISel(false);
94 setO0WantsFastISel(false);
95 setRequiresStructuredCFG(false);
96}
97
98namespace {
99// SPIR-V Code Generator Pass Configuration Options.
100class SPIRVPassConfig : public TargetPassConfig {
101public:
102 SPIRVPassConfig(SPIRVTargetMachine &TM, PassManagerBase &PM)
103 : TargetPassConfig(TM, PM), TM(TM) {}
104
105 SPIRVTargetMachine &getSPIRVTargetMachine() const {
106 return getTM<SPIRVTargetMachine>();
107 }
108 void addMachineSSAOptimization() override;
109 void addIRPasses() override;
110 void addISelPrepare() override;
111
112 bool addIRTranslator() override;
113 void addPreLegalizeMachineIR() override;
114 bool addLegalizeMachineIR() override;
115 bool addRegBankSelect() override;
116 bool addGlobalInstructionSelect() override;
117
118 FunctionPass *createTargetRegisterAllocator(bool) override;
119 void addFastRegAlloc() override {}
120 void addOptimizedRegAlloc() override {}
121
122 void addPostRegAlloc() override;
123 void addPreEmitPass2() override;
124
125private:
126 const SPIRVTargetMachine &TM;
127};
128} // namespace
129
130// We do not use physical registers, and maintain virtual registers throughout
131// the entire pipeline, so return nullptr to disable register allocation.
132FunctionPass *SPIRVPassConfig::createTargetRegisterAllocator(bool) {
133 return nullptr;
134}
135
136// A place to disable passes that may break CFG.
137void SPIRVPassConfig::addMachineSSAOptimization() {
138 TargetPassConfig::addMachineSSAOptimization();
139}
140
141// Disable passes that break from assuming no virtual registers exist.
142void SPIRVPassConfig::addPostRegAlloc() {
143 // Do not work with vregs instead of physical regs.
144 disablePass(PassID: &MachineCopyPropagationID);
145 disablePass(PassID: &PostRAMachineSinkingID);
146 disablePass(PassID: &PostRASchedulerID);
147 disablePass(PassID: &FuncletLayoutID);
148 disablePass(PassID: &StackMapLivenessID);
149 disablePass(PassID: &PatchableFunctionID);
150 disablePass(PassID: &ShrinkWrapID);
151 disablePass(PassID: &LiveDebugValuesID);
152 disablePass(PassID: &MachineLateInstrsCleanupID);
153 disablePass(PassID: &RemoveLoadsIntoFakeUsesID);
154
155 // Do not work with OpPhi.
156 disablePass(PassID: &BranchFolderPassID);
157 disablePass(PassID: &MachineBlockPlacementID);
158
159 TargetPassConfig::addPostRegAlloc();
160}
161
162void SPIRVPassConfig::addPreEmitPass2() {
163 addPass(P: createSPIRVPrepareModuleAnalysisLegacyPass());
164}
165
166TargetTransformInfo
167SPIRVTargetMachine::getTargetTransformInfo(const Function &F) const {
168 return TargetTransformInfo(std::make_unique<SPIRVTTIImpl>(args: this, args: F));
169}
170
171TargetPassConfig *SPIRVTargetMachine::createPassConfig(PassManagerBase &PM) {
172 return new SPIRVPassConfig(*this, PM);
173}
174
175void SPIRVPassConfig::addIRPasses() {
176 addPass(P: createAtomicExpandLegacyPass());
177
178 TargetPassConfig::addIRPasses();
179
180 if (TM.getSubtargetImpl()->isShader()) {
181 if (getOptLevel() != CodeGenOptLevel::None)
182 addPass(P: createSPIRVFinalizeShaderLinkagePass(TM));
183 } else {
184 // Variadic function calls aren't supported in shader code.
185 // This needs to come before SPIRVPrepareFunctions because this
186 // may introduce intrinsic calls.
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: createStripConvergenceIntrinsicsPass());
233 addPass(P: createSPIRVLegalizeResourceBindingPass());
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 IRTranslatorLegacy(getOptLevel()));
245 return false;
246}
247
248void SPIRVPassConfig::addPreLegalizeMachineIR() {
249 addPass(P: createSPIRVPreLegalizerCombinerLegacyPass());
250 addPass(P: createSPIRVPreLegalizerLegacyPass());
251}
252
253// Use the default legalizer.
254bool SPIRVPassConfig::addLegalizeMachineIR() {
255 addPass(P: new LegalizerLegacy());
256 addPass(P: createSPIRVPostLegalizerLegacyPass());
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: &RegBankSelectLegacy::ID);
263 return false;
264}
265
266// Deprecated flag kept for backward compatibility. NSDI emission is now handled
267// by SPIRVNonSemanticDebugHandler, registered in SPIRVAsmPrinter::
268// doInitialization() when the module contains debug info (llvm.dbg.cu).
269// TODO: Remove this option after a deprecation period. Callers that used
270// -spv-emit-nonsemantic-debug-info should switch to -g.
271static cl::opt<bool> SPVEnableNonSemanticDI(
272 "spv-emit-nonsemantic-debug-info",
273 cl::desc("Deprecated. Use -g to emit SPIR-V NonSemantic.Shader.DebugInfo "
274 "instructions"),
275 cl::init(Val: false));
276
277// Add the custom SPIRVInstructionSelect from above.
278bool SPIRVPassConfig::addGlobalInstructionSelect() {
279 addPass(P: new InstructionSelectLegacy(getOptLevel(),
280 /*RequireRegBankSelection=*/false));
281 return false;
282}
283