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 "SPIRVCallLowering.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/TargetLoweringObjectFileImpl.h"
27 #include "llvm/CodeGen/TargetPassConfig.h"
28 #include "llvm/InitializePasses.h"
29 #include "llvm/MC/TargetRegistry.h"
30 #include "llvm/Pass.h"
31 #include "llvm/Target/TargetOptions.h"
32 #include "llvm/Transforms/Utils.h"
33 #include <optional>
34
35 using namespace llvm;
36
LLVMInitializeSPIRVTarget()37 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTarget() {
38 // Register the target.
39 RegisterTargetMachine<SPIRVTargetMachine> X(getTheSPIRV32Target());
40 RegisterTargetMachine<SPIRVTargetMachine> Y(getTheSPIRV64Target());
41 RegisterTargetMachine<SPIRVTargetMachine> Z(getTheSPIRVLogicalTarget());
42
43 PassRegistry &PR = *PassRegistry::getPassRegistry();
44 initializeGlobalISel(PR);
45 initializeSPIRVModuleAnalysisPass(PR);
46 initializeSPIRVConvergenceRegionAnalysisWrapperPassPass(PR);
47 }
48
computeDataLayout(const Triple & TT)49 static std::string computeDataLayout(const Triple &TT) {
50 const auto Arch = TT.getArch();
51 // TODO: this probably needs to be revisited:
52 // Logical SPIR-V has no pointer size, so any fixed pointer size would be
53 // wrong. The choice to default to 32 or 64 is just motivated by another
54 // memory model used for graphics: PhysicalStorageBuffer64. But it shouldn't
55 // mean anything.
56 if (Arch == Triple::spirv32)
57 return "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"
58 "v96:128-v192:256-v256:256-v512:512-v1024:1024-G1";
59 if (TT.getVendor() == Triple::VendorType::AMD &&
60 TT.getOS() == Triple::OSType::AMDHSA)
61 return "e-i64:64-v16:16-v24:32-v32:32-v48:64-"
62 "v96:128-v192:256-v256:256-v512:512-v1024:1024-G1-P4-A0";
63 return "e-i64:64-v16:16-v24:32-v32:32-v48:64-"
64 "v96:128-v192:256-v256:256-v512:512-v1024:1024-G1";
65 }
66
getEffectiveRelocModel(std::optional<Reloc::Model> RM)67 static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) {
68 if (!RM)
69 return Reloc::PIC_;
70 return *RM;
71 }
72
73 // Pin SPIRVTargetObjectFile's vtables to this file.
~SPIRVTargetObjectFile()74 SPIRVTargetObjectFile::~SPIRVTargetObjectFile() {}
75
SPIRVTargetMachine(const Target & T,const Triple & TT,StringRef CPU,StringRef FS,const TargetOptions & Options,std::optional<Reloc::Model> RM,std::optional<CodeModel::Model> CM,CodeGenOptLevel OL,bool JIT)76 SPIRVTargetMachine::SPIRVTargetMachine(const Target &T, const Triple &TT,
77 StringRef CPU, StringRef FS,
78 const TargetOptions &Options,
79 std::optional<Reloc::Model> RM,
80 std::optional<CodeModel::Model> CM,
81 CodeGenOptLevel OL, bool JIT)
82 : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options,
83 getEffectiveRelocModel(RM),
84 getEffectiveCodeModel(CM, CodeModel::Small), OL),
85 TLOF(std::make_unique<SPIRVTargetObjectFile>()),
86 Subtarget(TT, CPU.str(), FS.str(), *this) {
87 initAsmInfo();
88 setGlobalISel(true);
89 setFastISel(false);
90 setO0WantsFastISel(false);
91 setRequiresStructuredCFG(false);
92 }
93
94 namespace {
95 // SPIR-V Code Generator Pass Configuration Options.
96 class SPIRVPassConfig : public TargetPassConfig {
97 public:
SPIRVPassConfig(SPIRVTargetMachine & TM,PassManagerBase & PM)98 SPIRVPassConfig(SPIRVTargetMachine &TM, PassManagerBase &PM)
99 : TargetPassConfig(TM, PM), TM(TM) {}
100
getSPIRVTargetMachine() const101 SPIRVTargetMachine &getSPIRVTargetMachine() const {
102 return getTM<SPIRVTargetMachine>();
103 }
104 void addIRPasses() override;
105 void addISelPrepare() override;
106
107 bool addIRTranslator() override;
108 void addPreLegalizeMachineIR() override;
109 bool addLegalizeMachineIR() override;
110 bool addRegBankSelect() override;
111 bool addGlobalInstructionSelect() override;
112
113 FunctionPass *createTargetRegisterAllocator(bool) override;
addFastRegAlloc()114 void addFastRegAlloc() override {}
addOptimizedRegAlloc()115 void addOptimizedRegAlloc() override {}
116
117 void addPostRegAlloc() override;
118
119 private:
120 const SPIRVTargetMachine &TM;
121 };
122 } // namespace
123
124 // We do not use physical registers, and maintain virtual registers throughout
125 // the entire pipeline, so return nullptr to disable register allocation.
createTargetRegisterAllocator(bool)126 FunctionPass *SPIRVPassConfig::createTargetRegisterAllocator(bool) {
127 return nullptr;
128 }
129
130 // Disable passes that break from assuming no virtual registers exist.
addPostRegAlloc()131 void SPIRVPassConfig::addPostRegAlloc() {
132 // Do not work with vregs instead of physical regs.
133 disablePass(&MachineCopyPropagationID);
134 disablePass(&PostRAMachineSinkingID);
135 disablePass(&PostRASchedulerID);
136 disablePass(&FuncletLayoutID);
137 disablePass(&StackMapLivenessID);
138 disablePass(&PatchableFunctionID);
139 disablePass(&ShrinkWrapID);
140 disablePass(&LiveDebugValuesID);
141 disablePass(&MachineLateInstrsCleanupID);
142
143 // Do not work with OpPhi.
144 disablePass(&BranchFolderPassID);
145 disablePass(&MachineBlockPlacementID);
146
147 TargetPassConfig::addPostRegAlloc();
148 }
149
150 TargetTransformInfo
getTargetTransformInfo(const Function & F) const151 SPIRVTargetMachine::getTargetTransformInfo(const Function &F) const {
152 return TargetTransformInfo(SPIRVTTIImpl(this, F));
153 }
154
createPassConfig(PassManagerBase & PM)155 TargetPassConfig *SPIRVTargetMachine::createPassConfig(PassManagerBase &PM) {
156 return new SPIRVPassConfig(*this, PM);
157 }
158
addIRPasses()159 void SPIRVPassConfig::addIRPasses() {
160 if (TM.getSubtargetImpl()->isVulkanEnv()) {
161 // Once legalized, we need to structurize the CFG to follow the spec.
162 // This is done through the following 8 steps.
163 // TODO(#75801): add the remaining steps.
164
165 // 1. Simplify loop for subsequent transformations. After this steps, loops
166 // have the following properties:
167 // - loops have a single entry edge (pre-header to loop header).
168 // - all loop exits are dominated by the loop pre-header.
169 // - loops have a single back-edge.
170 addPass(createLoopSimplifyPass());
171
172 // 2. Merge the convergence region exit nodes into one. After this step,
173 // regions are single-entry, single-exit. This will help determine the
174 // correct merge block.
175 addPass(createSPIRVMergeRegionExitTargetsPass());
176 }
177
178 TargetPassConfig::addIRPasses();
179 addPass(createSPIRVRegularizerPass());
180 addPass(createSPIRVPrepareFunctionsPass(TM));
181 addPass(createSPIRVStripConvergenceIntrinsicsPass());
182 }
183
addISelPrepare()184 void SPIRVPassConfig::addISelPrepare() {
185 addPass(createSPIRVEmitIntrinsicsPass(&getTM<SPIRVTargetMachine>()));
186 TargetPassConfig::addISelPrepare();
187 }
188
addIRTranslator()189 bool SPIRVPassConfig::addIRTranslator() {
190 addPass(new IRTranslator(getOptLevel()));
191 return false;
192 }
193
addPreLegalizeMachineIR()194 void SPIRVPassConfig::addPreLegalizeMachineIR() {
195 addPass(createSPIRVPreLegalizerPass());
196 }
197
198 // Use the default legalizer.
addLegalizeMachineIR()199 bool SPIRVPassConfig::addLegalizeMachineIR() {
200 addPass(new Legalizer());
201 addPass(createSPIRVPostLegalizerPass());
202 return false;
203 }
204
205 // Do not add the RegBankSelect pass, as we only ever need virtual registers.
addRegBankSelect()206 bool SPIRVPassConfig::addRegBankSelect() {
207 disablePass(&RegBankSelect::ID);
208 return false;
209 }
210
211 namespace {
212 // A custom subclass of InstructionSelect, which is mostly the same except from
213 // not requiring RegBankSelect to occur previously.
214 class SPIRVInstructionSelect : public InstructionSelect {
215 // We don't use register banks, so unset the requirement for them
getRequiredProperties() const216 MachineFunctionProperties getRequiredProperties() const override {
217 return InstructionSelect::getRequiredProperties().reset(
218 MachineFunctionProperties::Property::RegBankSelected);
219 }
220 };
221 } // namespace
222
223 // Add the custom SPIRVInstructionSelect from above.
addGlobalInstructionSelect()224 bool SPIRVPassConfig::addGlobalInstructionSelect() {
225 addPass(new SPIRVInstructionSelect());
226 return false;
227 }
228