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

source code of llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp