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/IR/LegacyPassManager.h"
29 #include "llvm/InitializePasses.h"
30 #include "llvm/MC/TargetRegistry.h"
31 #include "llvm/Pass.h"
32 #include "llvm/Target/TargetOptions.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
42 PassRegistry &PR = *PassRegistry::getPassRegistry();
43 initializeGlobalISel(PR);
44 initializeSPIRVModuleAnalysisPass(PR);
45 }
46
computeDataLayout(const Triple & TT)47 static std::string computeDataLayout(const Triple &TT) {
48 const auto Arch = TT.getArch();
49 if (Arch == Triple::spirv32)
50 return "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"
51 "v96:128-v192:256-v256:256-v512:512-v1024:1024";
52 return "e-i64:64-v16:16-v24:32-v32:32-v48:64-"
53 "v96:128-v192:256-v256:256-v512:512-v1024:1024";
54 }
55
getEffectiveRelocModel(std::optional<Reloc::Model> RM)56 static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) {
57 if (!RM)
58 return Reloc::PIC_;
59 return *RM;
60 }
61
62 // Pin SPIRVTargetObjectFile's vtables to this file.
~SPIRVTargetObjectFile()63 SPIRVTargetObjectFile::~SPIRVTargetObjectFile() {}
64
SPIRVTargetMachine(const Target & T,const Triple & TT,StringRef CPU,StringRef FS,const TargetOptions & Options,std::optional<Reloc::Model> RM,std::optional<CodeModel::Model> CM,CodeGenOpt::Level OL,bool JIT)65 SPIRVTargetMachine::SPIRVTargetMachine(const Target &T, const Triple &TT,
66 StringRef CPU, StringRef FS,
67 const TargetOptions &Options,
68 std::optional<Reloc::Model> RM,
69 std::optional<CodeModel::Model> CM,
70 CodeGenOpt::Level OL, bool JIT)
71 : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options,
72 getEffectiveRelocModel(RM),
73 getEffectiveCodeModel(CM, CodeModel::Small), OL),
74 TLOF(std::make_unique<SPIRVTargetObjectFile>()),
75 Subtarget(TT, CPU.str(), FS.str(), *this) {
76 initAsmInfo();
77 setGlobalISel(true);
78 setFastISel(false);
79 setO0WantsFastISel(false);
80 setRequiresStructuredCFG(false);
81 }
82
83 namespace {
84 // SPIR-V Code Generator Pass Configuration Options.
85 class SPIRVPassConfig : public TargetPassConfig {
86 public:
SPIRVPassConfig(SPIRVTargetMachine & TM,PassManagerBase & PM)87 SPIRVPassConfig(SPIRVTargetMachine &TM, PassManagerBase &PM)
88 : TargetPassConfig(TM, PM) {}
89
getSPIRVTargetMachine() const90 SPIRVTargetMachine &getSPIRVTargetMachine() const {
91 return getTM<SPIRVTargetMachine>();
92 }
93 void addIRPasses() override;
94 void addISelPrepare() override;
95
96 bool addIRTranslator() override;
97 void addPreLegalizeMachineIR() override;
98 bool addLegalizeMachineIR() override;
99 bool addRegBankSelect() override;
100 bool addGlobalInstructionSelect() override;
101
102 FunctionPass *createTargetRegisterAllocator(bool) override;
addFastRegAlloc()103 void addFastRegAlloc() override {}
addOptimizedRegAlloc()104 void addOptimizedRegAlloc() override {}
105
106 void addPostRegAlloc() override;
107 };
108 } // namespace
109
110 // We do not use physical registers, and maintain virtual registers throughout
111 // the entire pipeline, so return nullptr to disable register allocation.
createTargetRegisterAllocator(bool)112 FunctionPass *SPIRVPassConfig::createTargetRegisterAllocator(bool) {
113 return nullptr;
114 }
115
116 // Disable passes that break from assuming no virtual registers exist.
addPostRegAlloc()117 void SPIRVPassConfig::addPostRegAlloc() {
118 // Do not work with vregs instead of physical regs.
119 disablePass(&MachineCopyPropagationID);
120 disablePass(&PostRAMachineSinkingID);
121 disablePass(&PostRASchedulerID);
122 disablePass(&FuncletLayoutID);
123 disablePass(&StackMapLivenessID);
124 disablePass(&PatchableFunctionID);
125 disablePass(&ShrinkWrapID);
126 disablePass(&LiveDebugValuesID);
127 disablePass(&MachineLateInstrsCleanupID);
128
129 // Do not work with OpPhi.
130 disablePass(&BranchFolderPassID);
131 disablePass(&MachineBlockPlacementID);
132
133 TargetPassConfig::addPostRegAlloc();
134 }
135
136 TargetTransformInfo
getTargetTransformInfo(const Function & F) const137 SPIRVTargetMachine::getTargetTransformInfo(const Function &F) const {
138 return TargetTransformInfo(SPIRVTTIImpl(this, F));
139 }
140
createPassConfig(PassManagerBase & PM)141 TargetPassConfig *SPIRVTargetMachine::createPassConfig(PassManagerBase &PM) {
142 return new SPIRVPassConfig(*this, PM);
143 }
144
addIRPasses()145 void SPIRVPassConfig::addIRPasses() {
146 TargetPassConfig::addIRPasses();
147 addPass(createSPIRVRegularizerPass());
148 addPass(createSPIRVPrepareFunctionsPass());
149 }
150
addISelPrepare()151 void SPIRVPassConfig::addISelPrepare() {
152 addPass(createSPIRVEmitIntrinsicsPass(&getTM<SPIRVTargetMachine>()));
153 TargetPassConfig::addISelPrepare();
154 }
155
addIRTranslator()156 bool SPIRVPassConfig::addIRTranslator() {
157 addPass(new IRTranslator(getOptLevel()));
158 return false;
159 }
160
addPreLegalizeMachineIR()161 void SPIRVPassConfig::addPreLegalizeMachineIR() {
162 addPass(createSPIRVPreLegalizerPass());
163 }
164
165 // Use the default legalizer.
addLegalizeMachineIR()166 bool SPIRVPassConfig::addLegalizeMachineIR() {
167 addPass(new Legalizer());
168 return false;
169 }
170
171 // Do not add the RegBankSelect pass, as we only ever need virtual registers.
addRegBankSelect()172 bool SPIRVPassConfig::addRegBankSelect() {
173 disablePass(&RegBankSelect::ID);
174 return false;
175 }
176
177 namespace {
178 // A custom subclass of InstructionSelect, which is mostly the same except from
179 // not requiring RegBankSelect to occur previously.
180 class SPIRVInstructionSelect : public InstructionSelect {
181 // We don't use register banks, so unset the requirement for them
getRequiredProperties() const182 MachineFunctionProperties getRequiredProperties() const override {
183 return InstructionSelect::getRequiredProperties().reset(
184 MachineFunctionProperties::Property::RegBankSelected);
185 }
186 };
187 } // namespace
188
189 // Add the custom SPIRVInstructionSelect from above.
addGlobalInstructionSelect()190 bool SPIRVPassConfig::addGlobalInstructionSelect() {
191 addPass(new SPIRVInstructionSelect());
192 return false;
193 }
194