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