181ad6265SDimitry Andric //===- SPIRVTargetMachine.cpp - Define TargetMachine for SPIR-V -*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // Implements the info about SPIR-V target spec. 1081ad6265SDimitry Andric // 1181ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1281ad6265SDimitry Andric 1381ad6265SDimitry Andric #include "SPIRVTargetMachine.h" 1481ad6265SDimitry Andric #include "SPIRV.h" 1581ad6265SDimitry Andric #include "SPIRVCallLowering.h" 1681ad6265SDimitry Andric #include "SPIRVGlobalRegistry.h" 1781ad6265SDimitry Andric #include "SPIRVLegalizerInfo.h" 1881ad6265SDimitry Andric #include "SPIRVTargetObjectFile.h" 1981ad6265SDimitry Andric #include "SPIRVTargetTransformInfo.h" 2081ad6265SDimitry Andric #include "TargetInfo/SPIRVTargetInfo.h" 2181ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/IRTranslator.h" 2281ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/InstructionSelect.h" 2381ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/Legalizer.h" 2481ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/RegBankSelect.h" 2581ad6265SDimitry Andric #include "llvm/CodeGen/Passes.h" 2681ad6265SDimitry Andric #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" 2781ad6265SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 2881ad6265SDimitry Andric #include "llvm/IR/LegacyPassManager.h" 2981ad6265SDimitry Andric #include "llvm/InitializePasses.h" 3081ad6265SDimitry Andric #include "llvm/MC/TargetRegistry.h" 3181ad6265SDimitry Andric #include "llvm/Pass.h" 3281ad6265SDimitry Andric #include "llvm/Target/TargetOptions.h" 33*bdd1243dSDimitry Andric #include <optional> 3481ad6265SDimitry Andric 3581ad6265SDimitry Andric using namespace llvm; 3681ad6265SDimitry Andric 3781ad6265SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTarget() { 3881ad6265SDimitry Andric // Register the target. 3981ad6265SDimitry Andric RegisterTargetMachine<SPIRVTargetMachine> X(getTheSPIRV32Target()); 4081ad6265SDimitry Andric RegisterTargetMachine<SPIRVTargetMachine> Y(getTheSPIRV64Target()); 4181ad6265SDimitry Andric 4281ad6265SDimitry Andric PassRegistry &PR = *PassRegistry::getPassRegistry(); 4381ad6265SDimitry Andric initializeGlobalISel(PR); 4481ad6265SDimitry Andric initializeSPIRVModuleAnalysisPass(PR); 4581ad6265SDimitry Andric } 4681ad6265SDimitry Andric 4781ad6265SDimitry Andric static std::string computeDataLayout(const Triple &TT) { 4881ad6265SDimitry Andric const auto Arch = TT.getArch(); 4981ad6265SDimitry Andric if (Arch == Triple::spirv32) 5081ad6265SDimitry Andric return "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-" 5181ad6265SDimitry Andric "v96:128-v192:256-v256:256-v512:512-v1024:1024"; 5281ad6265SDimitry Andric return "e-i64:64-v16:16-v24:32-v32:32-v48:64-" 5381ad6265SDimitry Andric "v96:128-v192:256-v256:256-v512:512-v1024:1024"; 5481ad6265SDimitry Andric } 5581ad6265SDimitry Andric 56*bdd1243dSDimitry Andric static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) { 5781ad6265SDimitry Andric if (!RM) 5881ad6265SDimitry Andric return Reloc::PIC_; 5981ad6265SDimitry Andric return *RM; 6081ad6265SDimitry Andric } 6181ad6265SDimitry Andric 6281ad6265SDimitry Andric // Pin SPIRVTargetObjectFile's vtables to this file. 6381ad6265SDimitry Andric SPIRVTargetObjectFile::~SPIRVTargetObjectFile() {} 6481ad6265SDimitry Andric 6581ad6265SDimitry Andric SPIRVTargetMachine::SPIRVTargetMachine(const Target &T, const Triple &TT, 6681ad6265SDimitry Andric StringRef CPU, StringRef FS, 6781ad6265SDimitry Andric const TargetOptions &Options, 68*bdd1243dSDimitry Andric std::optional<Reloc::Model> RM, 69*bdd1243dSDimitry Andric std::optional<CodeModel::Model> CM, 7081ad6265SDimitry Andric CodeGenOpt::Level OL, bool JIT) 7181ad6265SDimitry Andric : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options, 7281ad6265SDimitry Andric getEffectiveRelocModel(RM), 7381ad6265SDimitry Andric getEffectiveCodeModel(CM, CodeModel::Small), OL), 74*bdd1243dSDimitry Andric TLOF(std::make_unique<SPIRVTargetObjectFile>()), 7581ad6265SDimitry Andric Subtarget(TT, CPU.str(), FS.str(), *this) { 7681ad6265SDimitry Andric initAsmInfo(); 7781ad6265SDimitry Andric setGlobalISel(true); 7881ad6265SDimitry Andric setFastISel(false); 7981ad6265SDimitry Andric setO0WantsFastISel(false); 8081ad6265SDimitry Andric setRequiresStructuredCFG(false); 8181ad6265SDimitry Andric } 8281ad6265SDimitry Andric 8381ad6265SDimitry Andric namespace { 8481ad6265SDimitry Andric // SPIR-V Code Generator Pass Configuration Options. 8581ad6265SDimitry Andric class SPIRVPassConfig : public TargetPassConfig { 8681ad6265SDimitry Andric public: 8781ad6265SDimitry Andric SPIRVPassConfig(SPIRVTargetMachine &TM, PassManagerBase &PM) 8881ad6265SDimitry Andric : TargetPassConfig(TM, PM) {} 8981ad6265SDimitry Andric 9081ad6265SDimitry Andric SPIRVTargetMachine &getSPIRVTargetMachine() const { 9181ad6265SDimitry Andric return getTM<SPIRVTargetMachine>(); 9281ad6265SDimitry Andric } 9381ad6265SDimitry Andric void addIRPasses() override; 9481ad6265SDimitry Andric void addISelPrepare() override; 9581ad6265SDimitry Andric 9681ad6265SDimitry Andric bool addIRTranslator() override; 9781ad6265SDimitry Andric void addPreLegalizeMachineIR() override; 9881ad6265SDimitry Andric bool addLegalizeMachineIR() override; 9981ad6265SDimitry Andric bool addRegBankSelect() override; 10081ad6265SDimitry Andric bool addGlobalInstructionSelect() override; 10181ad6265SDimitry Andric 10281ad6265SDimitry Andric FunctionPass *createTargetRegisterAllocator(bool) override; 10381ad6265SDimitry Andric void addFastRegAlloc() override {} 10481ad6265SDimitry Andric void addOptimizedRegAlloc() override {} 10581ad6265SDimitry Andric 10681ad6265SDimitry Andric void addPostRegAlloc() override; 10781ad6265SDimitry Andric }; 10881ad6265SDimitry Andric } // namespace 10981ad6265SDimitry Andric 11081ad6265SDimitry Andric // We do not use physical registers, and maintain virtual registers throughout 11181ad6265SDimitry Andric // the entire pipeline, so return nullptr to disable register allocation. 11281ad6265SDimitry Andric FunctionPass *SPIRVPassConfig::createTargetRegisterAllocator(bool) { 11381ad6265SDimitry Andric return nullptr; 11481ad6265SDimitry Andric } 11581ad6265SDimitry Andric 11681ad6265SDimitry Andric // Disable passes that break from assuming no virtual registers exist. 11781ad6265SDimitry Andric void SPIRVPassConfig::addPostRegAlloc() { 11881ad6265SDimitry Andric // Do not work with vregs instead of physical regs. 11981ad6265SDimitry Andric disablePass(&MachineCopyPropagationID); 12081ad6265SDimitry Andric disablePass(&PostRAMachineSinkingID); 12181ad6265SDimitry Andric disablePass(&PostRASchedulerID); 12281ad6265SDimitry Andric disablePass(&FuncletLayoutID); 12381ad6265SDimitry Andric disablePass(&StackMapLivenessID); 12481ad6265SDimitry Andric disablePass(&PatchableFunctionID); 12581ad6265SDimitry Andric disablePass(&ShrinkWrapID); 12681ad6265SDimitry Andric disablePass(&LiveDebugValuesID); 127*bdd1243dSDimitry Andric disablePass(&MachineLateInstrsCleanupID); 12881ad6265SDimitry Andric 12981ad6265SDimitry Andric // Do not work with OpPhi. 13081ad6265SDimitry Andric disablePass(&BranchFolderPassID); 13181ad6265SDimitry Andric disablePass(&MachineBlockPlacementID); 13281ad6265SDimitry Andric 13381ad6265SDimitry Andric TargetPassConfig::addPostRegAlloc(); 13481ad6265SDimitry Andric } 13581ad6265SDimitry Andric 13681ad6265SDimitry Andric TargetTransformInfo 13781ad6265SDimitry Andric SPIRVTargetMachine::getTargetTransformInfo(const Function &F) const { 13881ad6265SDimitry Andric return TargetTransformInfo(SPIRVTTIImpl(this, F)); 13981ad6265SDimitry Andric } 14081ad6265SDimitry Andric 14181ad6265SDimitry Andric TargetPassConfig *SPIRVTargetMachine::createPassConfig(PassManagerBase &PM) { 14281ad6265SDimitry Andric return new SPIRVPassConfig(*this, PM); 14381ad6265SDimitry Andric } 14481ad6265SDimitry Andric 145fcaf7f86SDimitry Andric void SPIRVPassConfig::addIRPasses() { 146fcaf7f86SDimitry Andric TargetPassConfig::addIRPasses(); 147*bdd1243dSDimitry Andric addPass(createSPIRVRegularizerPass()); 148fcaf7f86SDimitry Andric addPass(createSPIRVPrepareFunctionsPass()); 149fcaf7f86SDimitry Andric } 15081ad6265SDimitry Andric 15181ad6265SDimitry Andric void SPIRVPassConfig::addISelPrepare() { 15281ad6265SDimitry Andric addPass(createSPIRVEmitIntrinsicsPass(&getTM<SPIRVTargetMachine>())); 15381ad6265SDimitry Andric TargetPassConfig::addISelPrepare(); 15481ad6265SDimitry Andric } 15581ad6265SDimitry Andric 15681ad6265SDimitry Andric bool SPIRVPassConfig::addIRTranslator() { 15781ad6265SDimitry Andric addPass(new IRTranslator(getOptLevel())); 15881ad6265SDimitry Andric return false; 15981ad6265SDimitry Andric } 16081ad6265SDimitry Andric 16181ad6265SDimitry Andric void SPIRVPassConfig::addPreLegalizeMachineIR() { 16281ad6265SDimitry Andric addPass(createSPIRVPreLegalizerPass()); 16381ad6265SDimitry Andric } 16481ad6265SDimitry Andric 165*bdd1243dSDimitry Andric // Use the default legalizer. 16681ad6265SDimitry Andric bool SPIRVPassConfig::addLegalizeMachineIR() { 16781ad6265SDimitry Andric addPass(new Legalizer()); 16881ad6265SDimitry Andric return false; 16981ad6265SDimitry Andric } 17081ad6265SDimitry Andric 171*bdd1243dSDimitry Andric // Do not add the RegBankSelect pass, as we only ever need virtual registers. 17281ad6265SDimitry Andric bool SPIRVPassConfig::addRegBankSelect() { 17381ad6265SDimitry Andric disablePass(&RegBankSelect::ID); 17481ad6265SDimitry Andric return false; 17581ad6265SDimitry Andric } 17681ad6265SDimitry Andric 17781ad6265SDimitry Andric namespace { 17881ad6265SDimitry Andric // A custom subclass of InstructionSelect, which is mostly the same except from 17981ad6265SDimitry Andric // not requiring RegBankSelect to occur previously. 18081ad6265SDimitry Andric class SPIRVInstructionSelect : public InstructionSelect { 18181ad6265SDimitry Andric // We don't use register banks, so unset the requirement for them 18281ad6265SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 18381ad6265SDimitry Andric return InstructionSelect::getRequiredProperties().reset( 18481ad6265SDimitry Andric MachineFunctionProperties::Property::RegBankSelected); 18581ad6265SDimitry Andric } 18681ad6265SDimitry Andric }; 18781ad6265SDimitry Andric } // namespace 18881ad6265SDimitry Andric 189*bdd1243dSDimitry Andric // Add the custom SPIRVInstructionSelect from above. 19081ad6265SDimitry Andric bool SPIRVPassConfig::addGlobalInstructionSelect() { 19181ad6265SDimitry Andric addPass(new SPIRVInstructionSelect()); 19281ad6265SDimitry Andric return false; 19381ad6265SDimitry Andric } 194