xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp (revision 5b56413d04e608379c9a306373554a8e4d321bc0)
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 
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 
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 
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.
69 SPIRVTargetObjectFile::~SPIRVTargetObjectFile() {}
70 
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:
93   SPIRVPassConfig(SPIRVTargetMachine &TM, PassManagerBase &PM)
94       : TargetPassConfig(TM, PM), TM(TM) {}
95 
96   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;
109   void addFastRegAlloc() override {}
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.
121 FunctionPass *SPIRVPassConfig::createTargetRegisterAllocator(bool) {
122   return nullptr;
123 }
124 
125 // Disable passes that break from assuming no virtual registers exist.
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
146 SPIRVTargetMachine::getTargetTransformInfo(const Function &F) const {
147   return TargetTransformInfo(SPIRVTTIImpl(this, F));
148 }
149 
150 TargetPassConfig *SPIRVTargetMachine::createPassConfig(PassManagerBase &PM) {
151   return new SPIRVPassConfig(*this, PM);
152 }
153 
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 
174 void SPIRVPassConfig::addISelPrepare() {
175   addPass(createSPIRVEmitIntrinsicsPass(&getTM<SPIRVTargetMachine>()));
176   TargetPassConfig::addISelPrepare();
177 }
178 
179 bool SPIRVPassConfig::addIRTranslator() {
180   addPass(new IRTranslator(getOptLevel()));
181   return false;
182 }
183 
184 void SPIRVPassConfig::addPreLegalizeMachineIR() {
185   addPass(createSPIRVPreLegalizerPass());
186 }
187 
188 // Use the default legalizer.
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.
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
205   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.
213 bool SPIRVPassConfig::addGlobalInstructionSelect() {
214   addPass(new SPIRVInstructionSelect());
215   return false;
216 }
217