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