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