Unverified Commit 35480b22 authored by Diego Novillo's avatar Diego Novillo Committed by GitHub
Browse files

[SPIRV] Migrate NSDI emission from a machine pass to DebugHandlerBase (#191212)

This PR implements the basic harness for the migration I discussed in
https://discourse.llvm.org/t/hlsl-spirv-nsdi-debug-info-support-for-clang-dxc/90149.
parent 22bb938f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ add_llvm_target(SPIRVCodeGen
  SPIRVTargetTransformInfo.cpp
  SPIRVTypeInst.cpp
  SPIRVUtils.cpp
  SPIRVEmitNonSemanticDI.cpp
  SPIRVNonSemanticDebugHandler.cpp
  SPIRVCBufferAccess.cpp
  SPIRVPushConstantAccess.cpp

+2 −3
Original line number Diff line number Diff line
@@ -10,7 +10,8 @@
#define LLVM_LIB_TARGET_SPIRV_SPIRV_H

#include "MCTargetDesc/SPIRVMCTargetDesc.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Pass.h"
#include "llvm/PassRegistry.h"
#include "llvm/Target/TargetMachine.h"

namespace llvm {
@@ -33,7 +34,6 @@ FunctionPass *createSPIRVPreLegalizerPass();
FunctionPass *createSPIRVPostLegalizerPass();
ModulePass *createSPIRVEmitIntrinsicsPass(const SPIRVTargetMachine &TM);
ModulePass *createSPIRVPrepareGlobalsPass();
MachineFunctionPass *createSPIRVEmitNonSemanticDIPass(SPIRVTargetMachine *TM);
ModulePass *createSPIRVCtorDtorLoweringLegacyPass();
InstructionSelector *
createSPIRVInstructionSelector(const SPIRVTargetMachine &TM,
@@ -50,7 +50,6 @@ void initializeSPIRVStructurizerPass(PassRegistry &);
void initializeSPIRVCBufferAccessLegacyPass(PassRegistry &);
void initializeSPIRVPushConstantAccessLegacyPass(PassRegistry &);
void initializeSPIRVEmitIntrinsicsPass(PassRegistry &);
void initializeSPIRVEmitNonSemanticDIPass(PassRegistry &);
void initializeSPIRVLegalizePointerCastPass(PassRegistry &);
void initializeSPIRVRegularizerPass(PassRegistry &);
void initializeSPIRVMergeRegionExitTargetsPass(PassRegistry &);
+48 −4
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include "SPIRVInstrInfo.h"
#include "SPIRVMCInstLower.h"
#include "SPIRVModuleAnalysis.h"
#include "SPIRVNonSemanticDebugHandler.h"
#include "SPIRVSubtarget.h"
#include "SPIRVTargetMachine.h"
#include "SPIRVUtils.h"
@@ -105,6 +106,11 @@ public:
  void getAnalysisUsage(AnalysisUsage &AU) const override;
  SPIRV::ModuleAnalysisInfo *MAI;

  // Non-owning pointer to the NSDI handler registered via addAsmPrinterHandler.
  // The handler's lifetime is managed by AsmPrinter (the base class of this
  // object), so this pointer cannot dangle.
  SPIRVNonSemanticDebugHandler *NSDebugHandler = nullptr;

protected:
  void cleanUp(Module &M);
};
@@ -118,12 +124,18 @@ void SPIRVAsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const {

// If the module has no functions, we need output global info anyway.
void SPIRVAsmPrinter::emitEndOfAsmFile(Module &M) {
  if (ModuleSectionsEmitted == false) {
  if (!ModuleSectionsEmitted) {
    outputModuleSections();
    ModuleSectionsEmitted = true;
  }

  ST = static_cast<const SPIRVTargetMachine &>(TM).getSubtargetImpl();
  // SPIRVModuleAnalysis sets GR->Bound = MAI->MaxID before printing. Any IDs
  // allocated by AsmPrinter handlers (e.g. SPIRVNonSemanticDebugHandler) during
  // outputModuleSections() are not counted. Refresh the bound here so the
  // formula below sees the final allocation count.
  if (MAI)
    ST->getSPIRVGlobalRegistry()->setBound(MAI->MaxID);
  VersionTuple SPIRVVersion = ST->getSPIRVVersion();
  uint32_t Major = SPIRVVersion.getMajor();
  uint32_t Minor = SPIRVVersion.getMinor().value_or(0);
@@ -149,7 +161,7 @@ void SPIRVAsmPrinter::cleanUp(Module &M) {
}

void SPIRVAsmPrinter::emitFunctionHeader() {
  if (ModuleSectionsEmitted == false) {
  if (!ModuleSectionsEmitted) {
    outputModuleSections();
    ModuleSectionsEmitted = true;
  }
@@ -166,6 +178,15 @@ void SPIRVAsmPrinter::emitFunctionHeader() {

  auto Section = getObjFileLowering().SectionForGlobal(&F, TM);
  MF->setSection(Section);

  // SPIRVAsmPrinter::emitFunctionHeader() does not call the base class,
  // so handlers never receive beginFunction() from the normal path. Drive the
  // per-function lifecycle here, matching what AsmPrinter::emitFunctionHeader()
  // does for other targets.
  for (auto &Handler : Handlers) {
    Handler->beginFunction(MF);
    Handler->beginBasicBlockSection(MF->front());
  }
}

void SPIRVAsmPrinter::outputOpFunctionEnd() {
@@ -316,6 +337,13 @@ void SPIRVAsmPrinter::outputDebugSourceAndStrings(const Module &M) {
  Inst.addOperand(
      MCOperand::createImm(static_cast<unsigned>(MAI->SrcLangVersion)));
  outputMCInst(Inst);
  // Emit OpString instructions for NSDI file paths and type names here, in
  // section 7. OpString must precede type/constant declarations per the SPIR-V
  // module layout (section 2.4). The OpExtInst instructions that reference
  // these strings are emitted later at section 10 by
  // emitNonSemanticGlobalDebugInfo().
  if (NSDebugHandler)
    NSDebugHandler->emitNonSemanticDebugStrings(*MAI);
}

void SPIRVAsmPrinter::outputOpExtInstImports(const Module &M) {
@@ -821,6 +849,12 @@ void SPIRVAsmPrinter::outputModuleSections() {
  TII = ST->getInstrInfo();
  MAI = &getAnalysis<SPIRVModuleAnalysis>().MAI;
  assert(ST && TII && MAI && M && "Module analysis is required");

  // Let the NSDI handler add its extension and ext inst import entry to MAI
  // before the module header sections are emitted.
  if (NSDebugHandler)
    NSDebugHandler->prepareModuleOutput(*ST, *MAI);

  // Output instructions according to the Logical Layout of a Module:
  // 1,2. All OpCapability instructions, then optional OpExtension
  // instructions.
@@ -851,8 +885,11 @@ void SPIRVAsmPrinter::outputModuleSections() {
  // the first section to allow use of: OpLine and OpNoLine debug information;
  // non-semantic instructions with OpExtInst.
  outputModuleSection(SPIRV::MB_TypeConstVars);
  // 10. All global NonSemantic.Shader.DebugInfo.100 instructions.
  outputModuleSection(SPIRV::MB_NonSemanticGlobalDI);
  // 10. All global NonSemantic.Shader.DebugInfo.100 instructions. The
  // SPIRVNonSemanticDebugHandler emits these directly as MCInsts; the
  // MB_NonSemanticGlobalDI section in MAI is intentionally left empty.
  if (NSDebugHandler)
    NSDebugHandler->emitNonSemanticGlobalDebugInfo(*MAI);
  // 11. All function declarations (functions without a body).
  outputExtFuncDecls();
  // 12. All function definitions (functions with a body).
@@ -861,6 +898,13 @@ void SPIRVAsmPrinter::outputModuleSections() {

bool SPIRVAsmPrinter::doInitialization(Module &M) {
  ModuleSectionsEmitted = false;
  // Register the NSDI handler before calling the base class so that
  // AsmPrinter::doInitialization() calls Handler->beginModule(M) for it.
  if (M.getNamedMetadata("llvm.dbg.cu")) {
    auto Handler = std::make_unique<SPIRVNonSemanticDebugHandler>(*this);
    NSDebugHandler = Handler.get();
    addAsmPrinterHandler(std::move(Handler));
  }
  // We need to call the parent's one explicitly.
  return AsmPrinter::doInitialization(M);
}
+0 −366
Original line number Diff line number Diff line
#include "MCTargetDesc/SPIRVBaseInfo.h"
#include "MCTargetDesc/SPIRVMCTargetDesc.h"
#include "SPIRV.h"
#include "SPIRVGlobalRegistry.h"
#include "SPIRVRegisterInfo.h"
#include "SPIRVTargetMachine.h"
#include "SPIRVUtils.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Register.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DebugProgramInstruction.h"
#include "llvm/IR/Metadata.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Path.h"

#define DEBUG_TYPE "spirv-nonsemantic-debug-info"

using namespace llvm;

namespace {
struct SPIRVEmitNonSemanticDI : public MachineFunctionPass {
  static char ID;
  SPIRVTargetMachine *TM;
  SPIRVEmitNonSemanticDI(SPIRVTargetMachine *TM = nullptr)
      : MachineFunctionPass(ID), TM(TM) {}

  bool runOnMachineFunction(MachineFunction &MF) override;

private:
  bool IsGlobalDIEmitted = false;
  bool emitGlobalDI(MachineFunction &MF);
};
} // anonymous namespace

INITIALIZE_PASS(SPIRVEmitNonSemanticDI, DEBUG_TYPE,
                "SPIRV NonSemantic.Shader.DebugInfo.100 emitter", false, false)

char SPIRVEmitNonSemanticDI::ID = 0;

MachineFunctionPass *
llvm::createSPIRVEmitNonSemanticDIPass(SPIRVTargetMachine *TM) {
  return new SPIRVEmitNonSemanticDI(TM);
}

enum BaseTypeAttributeEncoding {
  Unspecified = 0,
  Address = 1,
  Boolean = 2,
  Float = 3,
  Signed = 4,
  SignedChar = 5,
  Unsigned = 6,
  UnsignedChar = 7
};

enum SourceLanguage {
  Unknown = 0,
  ESSL = 1,
  GLSL = 2,
  OpenCL_C = 3,
  OpenCL_CPP = 4,
  HLSL = 5,
  CPP_for_OpenCL = 6,
  SYCL = 7,
  HERO_C = 8,
  NZSL = 9,
  WGSL = 10,
  Slang = 11,
  Zig = 12
};

bool SPIRVEmitNonSemanticDI::emitGlobalDI(MachineFunction &MF) {
  // If this MachineFunction doesn't have any BB repeat procedure
  // for the next
  if (MF.begin() == MF.end()) {
    IsGlobalDIEmitted = false;
    return false;
  }

  // Required variables to get from metadata search
  LLVMContext *Context;
  SmallVector<SmallString<128>> FilePaths;
  SmallVector<int64_t> LLVMSourceLanguages;
  int64_t DwarfVersion = 0;
  int64_t DebugInfoVersion = 0;
  SetVector<DIBasicType *> BasicTypes;
  SetVector<DIDerivedType *> PointerDerivedTypes;
  // Searching through the Module metadata to find nescessary
  // information like DwarfVersion or SourceLanguage
  {
    const MachineModuleInfo &MMI =
        getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
    const Module *M = MMI.getModule();
    Context = &M->getContext();
    const NamedMDNode *DbgCu = M->getNamedMetadata("llvm.dbg.cu");
    if (!DbgCu)
      return false;
    // NonSemantic.Shader.DebugInfo.100 requires SPV_KHR_non_semantic_info.
    // Bail out if the extension is not available for this target. Targets that
    // do not enable this extension by default should enable it explicitly with
    // --spirv-ext=+SPV_KHR_non_semantic_info.
    if (!TM->getSubtargetImpl()->canUseExtension(
            SPIRV::Extension::SPV_KHR_non_semantic_info))
      return false;
    for (const auto *Op : DbgCu->operands()) {
      if (const auto *CompileUnit = dyn_cast<DICompileUnit>(Op)) {
        DIFile *File = CompileUnit->getFile();
        FilePaths.emplace_back();
        sys::path::append(FilePaths.back(), File->getDirectory(),
                          File->getFilename());
        LLVMSourceLanguages.push_back(
            CompileUnit->getSourceLanguage().getUnversionedName());
      }
    }
    const NamedMDNode *ModuleFlags = M->getNamedMetadata("llvm.module.flags");
    assert(ModuleFlags && "Expected llvm.module.flags metadata to be present");
    for (const auto *Op : ModuleFlags->operands()) {
      const MDOperand &MaybeStrOp = Op->getOperand(1);
      if (MaybeStrOp.equalsStr("Dwarf Version"))
        DwarfVersion =
            cast<ConstantInt>(
                cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())
                ->getSExtValue();
      else if (MaybeStrOp.equalsStr("Debug Info Version"))
        DebugInfoVersion =
            cast<ConstantInt>(
                cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())
                ->getSExtValue();
    }

    // This traversal is the only supported way to access
    // instruction related DI metadata like DIBasicType
    for (auto &F : *M) {
      for (auto &BB : F) {
        for (auto &I : BB) {
          for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) {
            DILocalVariable *LocalVariable = DVR.getVariable();
            if (auto *BasicType =
                    dyn_cast<DIBasicType>(LocalVariable->getType())) {
              BasicTypes.insert(BasicType);
            } else if (auto *DerivedType =
                           dyn_cast<DIDerivedType>(LocalVariable->getType())) {
              if (DerivedType->getTag() == dwarf::DW_TAG_pointer_type) {
                PointerDerivedTypes.insert(DerivedType);
                // DIBasicType can be unreachable from DbgRecord and only
                // pointed on from other DI types
                // DerivedType->getBaseType is null when pointer
                // is representing a void type
                if (auto *BT = dyn_cast_or_null<DIBasicType>(
                        DerivedType->getBaseType()))
                  BasicTypes.insert(BT);
              }
            }
          }
        }
      }
    }
  }
  // NonSemantic.Shader.DebugInfo.100 global DI instruction emitting
  {
    // Required LLVM variables for emitting logic
    const SPIRVInstrInfo *TII = TM->getSubtargetImpl()->getInstrInfo();
    const SPIRVRegisterInfo *TRI = TM->getSubtargetImpl()->getRegisterInfo();
    const RegisterBankInfo *RBI = TM->getSubtargetImpl()->getRegBankInfo();
    SPIRVGlobalRegistry *GR = TM->getSubtargetImpl()->getSPIRVGlobalRegistry();
    MachineRegisterInfo &MRI = MF.getRegInfo();
    MachineBasicBlock &MBB = *MF.begin();

    // To correct placement of a OpLabel instruction during SPIRVAsmPrinter
    // emission all new instructions needs to be placed after OpFunction
    // and before first terminator
    MachineIRBuilder MIRBuilder(MBB, MBB.getFirstTerminator());

    const auto EmitOpString = [&](StringRef SR) {
      const Register StrReg = MRI.createVirtualRegister(&SPIRV::IDRegClass);
      MRI.setType(StrReg, LLT::scalar(32));
      MachineInstrBuilder MIB = MIRBuilder.buildInstr(SPIRV::OpString);
      MIB.addDef(StrReg);
      addStringImm(SR, MIB);
      return StrReg;
    };

    const SPIRVTypeInst VoidTy =
        GR->getOrCreateSPIRVType(Type::getVoidTy(*Context), MIRBuilder,
                                 SPIRV::AccessQualifier::ReadWrite, false);

    const auto EmitDIInstruction =
        [&](SPIRV::NonSemanticExtInst::NonSemanticExtInst Inst,
            std::initializer_list<Register> Registers) {
          const Register InstReg =
              MRI.createVirtualRegister(&SPIRV::IDRegClass);
          MRI.setType(InstReg, LLT::scalar(32));
          MachineInstrBuilder MIB =
              MIRBuilder.buildInstr(SPIRV::OpExtInst)
                  .addDef(InstReg)
                  .addUse(GR->getSPIRVTypeID(VoidTy))
                  .addImm(static_cast<int64_t>(
                      SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100))
                  .addImm(Inst);
          for (auto Reg : Registers) {
            MIB.addUse(Reg);
          }
          MIB.constrainAllUses(*TII, *TRI, *RBI);
          GR->assignSPIRVTypeToVReg(VoidTy, InstReg, MF);
          return InstReg;
        };

    const SPIRVTypeInst I32Ty =
        GR->getOrCreateSPIRVType(Type::getInt32Ty(*Context), MIRBuilder,
                                 SPIRV::AccessQualifier::ReadWrite, false);

    const Register DwarfVersionReg =
        GR->buildConstantInt(DwarfVersion, MIRBuilder, I32Ty, false);

    const Register DebugInfoVersionReg =
        GR->buildConstantInt(DebugInfoVersion, MIRBuilder, I32Ty, false);

    for (unsigned Idx = 0; Idx < LLVMSourceLanguages.size(); ++Idx) {
      const Register FilePathStrReg = EmitOpString(FilePaths[Idx]);

      const Register DebugSourceResIdReg = EmitDIInstruction(
          SPIRV::NonSemanticExtInst::DebugSource, {FilePathStrReg});

      SourceLanguage SpirvSourceLanguage = SourceLanguage::Unknown;
      switch (LLVMSourceLanguages[Idx]) {
      case dwarf::DW_LANG_OpenCL:
        SpirvSourceLanguage = SourceLanguage::OpenCL_C;
        break;
      case dwarf::DW_LANG_OpenCL_CPP:
        SpirvSourceLanguage = SourceLanguage::OpenCL_CPP;
        break;
      case dwarf::DW_LANG_CPP_for_OpenCL:
        SpirvSourceLanguage = SourceLanguage::CPP_for_OpenCL;
        break;
      case dwarf::DW_LANG_GLSL:
        SpirvSourceLanguage = SourceLanguage::GLSL;
        break;
      case dwarf::DW_LANG_HLSL:
        SpirvSourceLanguage = SourceLanguage::HLSL;
        break;
      case dwarf::DW_LANG_SYCL:
        SpirvSourceLanguage = SourceLanguage::SYCL;
        break;
      case dwarf::DW_LANG_Zig:
        SpirvSourceLanguage = SourceLanguage::Zig;
      }

      const Register SourceLanguageReg =
          GR->buildConstantInt(SpirvSourceLanguage, MIRBuilder, I32Ty, false);

      [[maybe_unused]]
      const Register DebugCompUnitResIdReg =
          EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugCompilationUnit,
                            {DebugInfoVersionReg, DwarfVersionReg,
                             DebugSourceResIdReg, SourceLanguageReg});
    }

    // We aren't extracting any DebugInfoFlags now so we
    // emitting zero to use as <id>Flags argument for DebugBasicType
    const Register I32ZeroReg =
        GR->buildConstantInt(0, MIRBuilder, I32Ty, false, false);

    // We need to store pairs because further instructions reference
    // the DIBasicTypes and size will be always small so there isn't
    // need for any kind of map
    SmallVector<std::pair<const DIBasicType *const, const Register>, 12>
        BasicTypeRegPairs;
    for (auto *BasicType : BasicTypes) {
      const Register BasicTypeStrReg = EmitOpString(BasicType->getName());

      const Register ConstIntBitwidthReg = GR->buildConstantInt(
          BasicType->getSizeInBits(), MIRBuilder, I32Ty, false);

      uint64_t AttributeEncoding = BaseTypeAttributeEncoding::Unspecified;
      switch (BasicType->getEncoding()) {
      case dwarf::DW_ATE_signed:
        AttributeEncoding = BaseTypeAttributeEncoding::Signed;
        break;
      case dwarf::DW_ATE_unsigned:
        AttributeEncoding = BaseTypeAttributeEncoding::Unsigned;
        break;
      case dwarf::DW_ATE_unsigned_char:
        AttributeEncoding = BaseTypeAttributeEncoding::UnsignedChar;
        break;
      case dwarf::DW_ATE_signed_char:
        AttributeEncoding = BaseTypeAttributeEncoding::SignedChar;
        break;
      case dwarf::DW_ATE_float:
        AttributeEncoding = BaseTypeAttributeEncoding::Float;
        break;
      case dwarf::DW_ATE_boolean:
        AttributeEncoding = BaseTypeAttributeEncoding::Boolean;
        break;
      case dwarf::DW_ATE_address:
        AttributeEncoding = BaseTypeAttributeEncoding::Address;
      }

      const Register AttributeEncodingReg =
          GR->buildConstantInt(AttributeEncoding, MIRBuilder, I32Ty, false);

      const Register BasicTypeReg =
          EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugTypeBasic,
                            {BasicTypeStrReg, ConstIntBitwidthReg,
                             AttributeEncodingReg, I32ZeroReg});
      BasicTypeRegPairs.emplace_back(BasicType, BasicTypeReg);
    }

    if (PointerDerivedTypes.size()) {
      for (const auto *PointerDerivedType : PointerDerivedTypes) {

        assert(PointerDerivedType->getDWARFAddressSpace().has_value());
        const Register StorageClassReg = GR->buildConstantInt(
            addressSpaceToStorageClass(
                PointerDerivedType->getDWARFAddressSpace().value(),
                *TM->getSubtargetImpl()),
            MIRBuilder, I32Ty, false);

        // If the Pointer is representing a void type it's getBaseType
        // is a nullptr
        const auto *MaybeNestedBasicType =
            dyn_cast_or_null<DIBasicType>(PointerDerivedType->getBaseType());
        if (MaybeNestedBasicType) {
          for (const auto &BasicTypeRegPair : BasicTypeRegPairs) {
            const auto &[DefinedBasicType, BasicTypeReg] = BasicTypeRegPair;
            if (DefinedBasicType == MaybeNestedBasicType) {
              [[maybe_unused]]
              const Register DebugPointerTypeReg = EmitDIInstruction(
                  SPIRV::NonSemanticExtInst::DebugTypePointer,
                  {BasicTypeReg, StorageClassReg, I32ZeroReg});
            }
          }
        } else {
          const Register DebugInfoNoneReg =
              EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugInfoNone, {});
          [[maybe_unused]]
          const Register DebugPointerTypeReg = EmitDIInstruction(
              SPIRV::NonSemanticExtInst::DebugTypePointer,
              {DebugInfoNoneReg, StorageClassReg, I32ZeroReg});
        }
      }
    }
  }
  return true;
}

bool SPIRVEmitNonSemanticDI::runOnMachineFunction(MachineFunction &MF) {
  bool Res = false;
  // emitGlobalDI needs to be executed only once to avoid
  // emitting duplicates
  if (!IsGlobalDIEmitted) {
    IsGlobalDIEmitted = true;
    Res = emitGlobalDI(MF);
  }
  return Res;
}
+6 −0
Original line number Diff line number Diff line
@@ -678,6 +678,12 @@ void SPIRVModuleAnalysis::processOtherInstrs(const Module &M) {
                   MI.getOperand(2).getImm() ==
                       SPIRV::InstructionSet::
                           NonSemantic_Shader_DebugInfo_100) {
          // TODO: This branch is dead. SPIRVNonSemanticDebugHandler emits NSDI
          // instructions directly as MCInsts at print time; no
          // MachineInstructions with the NSDI ext set are created anymore.
          // Remove this block and
          // MB_NonSemanticGlobalDI once per-function NSDI emission is confirmed
          // not to need MIR routing.
          MachineOperand Ins = MI.getOperand(3);
          namespace NS = SPIRV::NonSemanticExtInst;
          static constexpr int64_t GlobalNonSemanticDITy[] = {
Loading