brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.5 KiB · 10bbca2 Raw
271 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// Implements the info about SPIR-V target spec.10//11//===----------------------------------------------------------------------===//12 13#include "SPIRVTargetMachine.h"14#include "SPIRV.h"15#include "SPIRVCBufferAccess.h"16#include "SPIRVGlobalRegistry.h"17#include "SPIRVLegalizerInfo.h"18#include "SPIRVStructurizerWrapper.h"19#include "SPIRVTargetObjectFile.h"20#include "SPIRVTargetTransformInfo.h"21#include "TargetInfo/SPIRVTargetInfo.h"22#include "llvm/CodeGen/GlobalISel/IRTranslator.h"23#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"24#include "llvm/CodeGen/GlobalISel/Legalizer.h"25#include "llvm/CodeGen/GlobalISel/RegBankSelect.h"26#include "llvm/CodeGen/Passes.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/Passes/PassBuilder.h"32#include "llvm/Support/Compiler.h"33#include "llvm/Target/TargetOptions.h"34#include "llvm/Transforms/Scalar.h"35#include "llvm/Transforms/Utils.h"36#include <optional>37 38using namespace llvm;39 40extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTarget() {41  // Register the target.42  RegisterTargetMachine<SPIRVTargetMachine> X(getTheSPIRV32Target());43  RegisterTargetMachine<SPIRVTargetMachine> Y(getTheSPIRV64Target());44  RegisterTargetMachine<SPIRVTargetMachine> Z(getTheSPIRVLogicalTarget());45 46  PassRegistry &PR = *PassRegistry::getPassRegistry();47  initializeGlobalISel(PR);48  initializeSPIRVModuleAnalysisPass(PR);49  initializeSPIRVAsmPrinterPass(PR);50  initializeSPIRVConvergenceRegionAnalysisWrapperPassPass(PR);51  initializeSPIRVStructurizerPass(PR);52  initializeSPIRVCBufferAccessLegacyPass(PR);53  initializeSPIRVPreLegalizerCombinerPass(PR);54  initializeSPIRVLegalizePointerCastPass(PR);55  initializeSPIRVRegularizerPass(PR);56  initializeSPIRVPreLegalizerPass(PR);57  initializeSPIRVPostLegalizerPass(PR);58  initializeSPIRVMergeRegionExitTargetsPass(PR);59  initializeSPIRVEmitIntrinsicsPass(PR);60  initializeSPIRVEmitNonSemanticDIPass(PR);61  initializeSPIRVPrepareFunctionsPass(PR);62  initializeSPIRVPrepareGlobalsPass(PR);63  initializeSPIRVStripConvergentIntrinsicsPass(PR);64}65 66static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) {67  if (!RM)68    return Reloc::PIC_;69  return *RM;70}71 72// Pin SPIRVTargetObjectFile's vtables to this file.73SPIRVTargetObjectFile::~SPIRVTargetObjectFile() = default;74 75SPIRVTargetMachine::SPIRVTargetMachine(const Target &T, const Triple &TT,76                                       StringRef CPU, StringRef FS,77                                       const TargetOptions &Options,78                                       std::optional<Reloc::Model> RM,79                                       std::optional<CodeModel::Model> CM,80                                       CodeGenOptLevel OL, bool JIT)81    : CodeGenTargetMachineImpl(T, TT.computeDataLayout(), TT, CPU, FS, Options,82                               getEffectiveRelocModel(RM),83                               getEffectiveCodeModel(CM, CodeModel::Small), OL),84      TLOF(std::make_unique<SPIRVTargetObjectFile>()),85      Subtarget(TT, CPU.str(), FS.str(), *this) {86  initAsmInfo();87  setGlobalISel(true);88  setFastISel(false);89  setO0WantsFastISel(false);90  setRequiresStructuredCFG(false);91}92 93void SPIRVTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {94#define GET_PASS_REGISTRY "SPIRVPassRegistry.def"95#include "llvm/Passes/TargetPassRegistry.inc"96}97 98namespace {99// SPIR-V Code Generator Pass Configuration Options.100class SPIRVPassConfig : public TargetPassConfig {101public:102  SPIRVPassConfig(SPIRVTargetMachine &TM, PassManagerBase &PM)103      : TargetPassConfig(TM, PM), TM(TM) {}104 105  SPIRVTargetMachine &getSPIRVTargetMachine() const {106    return getTM<SPIRVTargetMachine>();107  }108  void addMachineSSAOptimization() override;109  void addIRPasses() override;110  void addISelPrepare() override;111 112  bool addIRTranslator() override;113  void addPreLegalizeMachineIR() override;114  bool addLegalizeMachineIR() override;115  bool addRegBankSelect() override;116  bool addGlobalInstructionSelect() override;117 118  FunctionPass *createTargetRegisterAllocator(bool) override;119  void addFastRegAlloc() override {}120  void addOptimizedRegAlloc() override {}121 122  void addPostRegAlloc() override;123  void addPreEmitPass() override;124 125private:126  const SPIRVTargetMachine &TM;127};128} // namespace129 130// We do not use physical registers, and maintain virtual registers throughout131// the entire pipeline, so return nullptr to disable register allocation.132FunctionPass *SPIRVPassConfig::createTargetRegisterAllocator(bool) {133  return nullptr;134}135 136// A place to disable passes that may break CFG.137void SPIRVPassConfig::addMachineSSAOptimization() {138  TargetPassConfig::addMachineSSAOptimization();139}140 141// Disable passes that break from assuming no virtual registers exist.142void SPIRVPassConfig::addPostRegAlloc() {143  // Do not work with vregs instead of physical regs.144  disablePass(&MachineCopyPropagationID);145  disablePass(&PostRAMachineSinkingID);146  disablePass(&PostRASchedulerID);147  disablePass(&FuncletLayoutID);148  disablePass(&StackMapLivenessID);149  disablePass(&PatchableFunctionID);150  disablePass(&ShrinkWrapID);151  disablePass(&LiveDebugValuesID);152  disablePass(&MachineLateInstrsCleanupID);153  disablePass(&RemoveLoadsIntoFakeUsesID);154 155  // Do not work with OpPhi.156  disablePass(&BranchFolderPassID);157  disablePass(&MachineBlockPlacementID);158 159  TargetPassConfig::addPostRegAlloc();160}161 162TargetTransformInfo163SPIRVTargetMachine::getTargetTransformInfo(const Function &F) const {164  return TargetTransformInfo(std::make_unique<SPIRVTTIImpl>(this, F));165}166 167TargetPassConfig *SPIRVTargetMachine::createPassConfig(PassManagerBase &PM) {168  return new SPIRVPassConfig(*this, PM);169}170 171void SPIRVPassConfig::addIRPasses() {172  TargetPassConfig::addIRPasses();173 174  addPass(createSPIRVRegularizerPass());175  addPass(createSPIRVPrepareFunctionsPass(TM));176  addPass(createSPIRVPrepareGlobalsPass());177}178 179void SPIRVPassConfig::addISelPrepare() {180  if (TM.getSubtargetImpl()->isShader()) {181    // Vulkan does not allow address space casts. This pass is run to remove182    // address space casts that can be removed.183    // If an address space cast is not removed while targeting Vulkan, lowering184    // will fail during MIR lowering.185    addPass(createInferAddressSpacesPass());186 187    // 1.  Simplify loop for subsequent transformations. After this steps, loops188    // have the following properties:189    //  - loops have a single entry edge (pre-header to loop header).190    //  - all loop exits are dominated by the loop pre-header.191    //  - loops have a single back-edge.192    addPass(createLoopSimplifyPass());193 194    // 2. Removes registers whose lifetime spans across basic blocks. Also195    // removes phi nodes. This will greatly simplify the next steps.196    addPass(createRegToMemWrapperPass());197 198    // 3. Merge the convergence region exit nodes into one. After this step,199    // regions are single-entry, single-exit. This will help determine the200    // correct merge block.201    addPass(createSPIRVMergeRegionExitTargetsPass());202 203    // 4. Structurize.204    addPass(createSPIRVStructurizerPass());205 206    // 5. Reduce the amount of variables required by pushing some operations207    // back to virtual registers.208    addPass(createPromoteMemoryToRegisterPass());209  }210 211  addPass(createSPIRVStripConvergenceIntrinsicsPass());212  addPass(createSPIRVLegalizeImplicitBindingPass());213  addPass(createSPIRVCBufferAccessLegacyPass());214  addPass(createSPIRVEmitIntrinsicsPass(&getTM<SPIRVTargetMachine>()));215  if (TM.getSubtargetImpl()->isLogicalSPIRV())216    addPass(createSPIRVLegalizePointerCastPass(&getTM<SPIRVTargetMachine>()));217  TargetPassConfig::addISelPrepare();218}219 220bool SPIRVPassConfig::addIRTranslator() {221  addPass(new IRTranslator(getOptLevel()));222  return false;223}224 225void SPIRVPassConfig::addPreLegalizeMachineIR() {226  addPass(createSPIRVPreLegalizerCombiner());227  addPass(createSPIRVPreLegalizerPass());228}229 230// Use the default legalizer.231bool SPIRVPassConfig::addLegalizeMachineIR() {232  addPass(new Legalizer());233  addPass(createSPIRVPostLegalizerPass());234  return false;235}236 237// Do not add the RegBankSelect pass, as we only ever need virtual registers.238bool SPIRVPassConfig::addRegBankSelect() {239  disablePass(&RegBankSelect::ID);240  return false;241}242 243static cl::opt<bool> SPVEnableNonSemanticDI(244    "spv-emit-nonsemantic-debug-info",245    cl::desc("Emit SPIR-V NonSemantic.Shader.DebugInfo.100 instructions"),246    cl::Optional, cl::init(false));247 248void SPIRVPassConfig::addPreEmitPass() {249  if (SPVEnableNonSemanticDI ||250      getSPIRVTargetMachine().getTargetTriple().getVendor() == Triple::AMD) {251    addPass(createSPIRVEmitNonSemanticDIPass(&getTM<SPIRVTargetMachine>()));252  }253}254 255namespace {256// A custom subclass of InstructionSelect, which is mostly the same except from257// not requiring RegBankSelect to occur previously.258class SPIRVInstructionSelect : public InstructionSelect {259  // We don't use register banks, so unset the requirement for them260  MachineFunctionProperties getRequiredProperties() const override {261    return InstructionSelect::getRequiredProperties().resetRegBankSelected();262  }263};264} // namespace265 266// Add the custom SPIRVInstructionSelect from above.267bool SPIRVPassConfig::addGlobalInstructionSelect() {268  addPass(new SPIRVInstructionSelect());269  return false;270}271