[llvm] [SPIRV] Emitting DebugSource, DebugCompileUnit (PR #97558)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 3 04:34:32 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-spir-v

Author: None (bwlodarcz)

<details>
<summary>Changes</summary>

This commit introduces emission of DebugSource, DebugCompileUnit from NonSemantic.Shader.DebugInfo.100 and required OpString with filename.
NonSemantic.Shader.DebugInfo.100 is divided, following DWARF into two main concepts – emitting DIE and Line.
In DWARF .debug_abbriev and .debug_line sections are responsible for emitting tree with information (DEIs) about e.g. types, compilation unit. Corresponding to that in NonSemantic.Shader.DebugInfo.100 have instructions like DebugSource, DebugCompileUnit etc. which preforms same role in SPIR-V file. The difference is in fact that in SPIR-V there are no sections but logical layout which forces order of the instruction emission.
The NonSemantic.Shader.DebugInfo.100 requires for this type of global information to be emitted after OpTypeXXX and OpConstantXXX instructions.
One of the goals was to minimize changes and interaction with SPIRVModuleAnalysis as possible which current commit achieves by emitting it’s instructions directly into MachineFunction.
The possibility of duplicates are mitigated by guard inside pass which emits the global information only once in one function.
By that method duplicates don’t have chance to be emitted.
>From that point, adding new debug global instructions should be straightforward.

---
Full diff: https://github.com/llvm/llvm-project/pull/97558.diff


7 Files Affected:

- (modified) llvm/lib/Target/SPIRV/CMakeLists.txt (+1) 
- (modified) llvm/lib/Target/SPIRV/SPIRV.h (+2) 
- (modified) llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp (+6-2) 
- (added) llvm/lib/Target/SPIRV/SPIRVEmitNonSemanticDI.cpp (+148) 
- (modified) llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp (+15-2) 
- (modified) llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h (+2-1) 
- (modified) llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp (+1) 


``````````diff
diff --git a/llvm/lib/Target/SPIRV/CMakeLists.txt b/llvm/lib/Target/SPIRV/CMakeLists.txt
index 14647e92f5d08..5f8aea5fc8d84 100644
--- a/llvm/lib/Target/SPIRV/CMakeLists.txt
+++ b/llvm/lib/Target/SPIRV/CMakeLists.txt
@@ -40,6 +40,7 @@ add_llvm_target(SPIRVCodeGen
   SPIRVSubtarget.cpp
   SPIRVTargetMachine.cpp
   SPIRVUtils.cpp
+  SPIRVEmitNonSemanticDI.cpp
 
   LINK_COMPONENTS
   Analysis
diff --git a/llvm/lib/Target/SPIRV/SPIRV.h b/llvm/lib/Target/SPIRV/SPIRV.h
index e597a1dc8dc06..6c35a467f53be 100644
--- a/llvm/lib/Target/SPIRV/SPIRV.h
+++ b/llvm/lib/Target/SPIRV/SPIRV.h
@@ -26,6 +26,7 @@ FunctionPass *createSPIRVRegularizerPass();
 FunctionPass *createSPIRVPreLegalizerPass();
 FunctionPass *createSPIRVPostLegalizerPass();
 ModulePass *createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM);
+MachineFunctionPass *createSPIRVEmitNonSemanticDIPass(SPIRVTargetMachine *TM);
 InstructionSelector *
 createSPIRVInstructionSelector(const SPIRVTargetMachine &TM,
                                const SPIRVSubtarget &Subtarget,
@@ -36,6 +37,7 @@ void initializeSPIRVConvergenceRegionAnalysisWrapperPassPass(PassRegistry &);
 void initializeSPIRVPreLegalizerPass(PassRegistry &);
 void initializeSPIRVPostLegalizerPass(PassRegistry &);
 void initializeSPIRVEmitIntrinsicsPass(PassRegistry &);
+void initializeSPIRVEmitNonSemanticDIPass(PassRegistry &);
 } // namespace llvm
 
 #endif // LLVM_LIB_TARGET_SPIRV_SPIRV_H
diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
index 3206c264f99d3..f9f36cc25eec5 100644
--- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
@@ -273,6 +273,8 @@ void SPIRVAsmPrinter::outputDebugSourceAndStrings(const Module &M) {
     addStringImm(Str.first(), Inst);
     outputMCInst(Inst);
   }
+  // Output OpString.
+  outputModuleSection(SPIRV::MB_DebugStrings);
   // Output OpSource.
   MCInst Inst;
   Inst.setOpcode(SPIRV::OpSource);
@@ -588,9 +590,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 function declarations (functions without a body).
+  // 10. All global NonSemantic.Shader.DebugInfo.100 instructions.
+  outputModuleSection(SPIRV::MB_NonSemanticGlobalDI);
+  // 11. All function declarations (functions without a body).
   outputExtFuncDecls();
-  // 11. All function definitions (functions with a body).
+  // 12. All function definitions (functions with a body).
   // This is done in regular function output.
 }
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitNonSemanticDI.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitNonSemanticDI.cpp
new file mode 100644
index 0000000000000..f630685d98ac8
--- /dev/null
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitNonSemanticDI.cpp
@@ -0,0 +1,148 @@
+#include "MCTargetDesc/SPIRVBaseInfo.h"
+#include "SPIRVGlobalRegistry.h"
+#include "SPIRVRegisterInfo.h"
+#include "SPIRVTargetMachine.h"
+#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.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/IR/DebugInfoMetadata.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/PassRegistry.h"
+#include "llvm/Support/Casting.h"
+
+namespace llvm {
+struct SPIRVEmitNonSemanticDI : public MachineFunctionPass {
+  static char ID;
+  SPIRVTargetMachine *TM;
+  SPIRVEmitNonSemanticDI(SPIRVTargetMachine *TM);
+  SPIRVEmitNonSemanticDI();
+
+  bool runOnMachineFunction(MachineFunction &MF) override;
+
+private:
+  bool IsGlobalDIEmitted = false;
+  bool emitGlobalDI(MachineFunction &MF);
+};
+
+void initializeSPIRVEmitNonSemanticDIPass(PassRegistry &);
+
+FunctionPass *createSPIRVEmitNonSemanticDIPass(SPIRVTargetMachine *TM) {
+  return new SPIRVEmitNonSemanticDI(TM);
+}
+} // namespace llvm
+
+using namespace llvm;
+
+INITIALIZE_PASS(SPIRVEmitNonSemanticDI, "spirv-nonsemantic-debug-info",
+                "SPIRV NonSemantic.Shader.DebugInfo.100 emitter", false, false)
+
+char SPIRVEmitNonSemanticDI::ID = 0;
+
+SPIRVEmitNonSemanticDI::SPIRVEmitNonSemanticDI(SPIRVTargetMachine *TM)
+    : MachineFunctionPass(ID), TM(TM) {
+  initializeSPIRVEmitNonSemanticDIPass(*PassRegistry::getPassRegistry());
+}
+
+SPIRVEmitNonSemanticDI::SPIRVEmitNonSemanticDI() : MachineFunctionPass(ID) {
+  initializeSPIRVEmitNonSemanticDIPass(*PassRegistry::getPassRegistry());
+}
+
+bool SPIRVEmitNonSemanticDI::emitGlobalDI(MachineFunction &MF) {
+  MachineModuleInfo &MMI = MF.getMMI();
+  const Module *M = MMI.getModule();
+  NamedMDNode *DbgCu = M->getNamedMetadata("llvm.dbg.cu");
+  if (!DbgCu) {
+    return false;
+  }
+  std::string FilePath;
+  unsigned SourceLanguage;
+  unsigned NumOp = DbgCu->getNumOperands();
+  if (NumOp) {
+    if (const auto *CompileUnit =
+            dyn_cast<DICompileUnit>(DbgCu->getOperand(0))) {
+      DIFile *File = CompileUnit->getFile();
+      FilePath = ((File->getDirectory() + "/" + File->getFilename())).str();
+      SourceLanguage = CompileUnit->getSourceLanguage();
+    }
+  }
+  NamedMDNode *ModuleFlags = M->getNamedMetadata("llvm.module.flags");
+  int64_t DwarfVersion = 0;
+  int64_t DebugInfoVersion = 0;
+  for (auto *Op : ModuleFlags->operands()) {
+    const MDOperand &StrOp = Op->getOperand(1);
+    if (StrOp.equalsStr("Dwarf Version")) {
+      DwarfVersion =
+          cast<ConstantInt>(
+              cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())
+              ->getSExtValue();
+    } else if (StrOp.equalsStr("Debug Info Version")) {
+      DebugInfoVersion =
+          cast<ConstantInt>(
+              cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())
+              ->getSExtValue();
+    }
+  }
+  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();
+  for (MachineBasicBlock &MBB : MF) {
+    MachineIRBuilder MIRBuilder(MBB, MBB.begin());
+
+    MachineInstrBuilder MIB = MIRBuilder.buildInstr(SPIRV::OpString);
+    Register StrReg = MRI.createVirtualRegister(&SPIRV::IDRegClass);
+    MachineOperand StrRegOp = MachineOperand::CreateReg(StrReg, true);
+    MIB.add(StrRegOp);
+    addStringImm(FilePath, MIB);
+
+    const MachineInstr *VoidTyMI =
+        GR->getOrCreateSPIRVType(Type::getVoidTy(M->getContext()), MIRBuilder);
+
+    MIB = MIRBuilder.buildInstr(SPIRV::OpExtInst);
+    Register DebugSourceResIdReg =
+        MRI.createVirtualRegister(&SPIRV::IDRegClass);
+    MIB.addDef(DebugSourceResIdReg);              // Result ID
+    MIB.addUse(VoidTyMI->getOperand(0).getReg()); // Result Type
+    MIB.addImm(static_cast<int64_t>(
+        SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100)); // Set ID
+    MIB.addImm(SPIRV::NonSemanticExtInst::DebugSource);            //
+    MIB.addUse(StrReg);
+    MIB.constrainAllUses(*TII, *TRI, *RBI);
+
+    Register DwarfVersionReg = GR->buildConstantInt(DwarfVersion, MIRBuilder);
+    Register DebugInfoVersionReg =
+        GR->buildConstantInt(DebugInfoVersion, MIRBuilder);
+    Register SourceLanguageReg =
+        GR->buildConstantInt(SourceLanguage, MIRBuilder);
+
+    MIB = MIRBuilder.buildInstr(SPIRV::OpExtInst);
+    Register DebugCompUnitResIdReg =
+        MRI.createVirtualRegister(&SPIRV::IDRegClass);
+    MIB.addDef(DebugCompUnitResIdReg);            // Result ID
+    MIB.addUse(VoidTyMI->getOperand(0).getReg()); // Result Type
+    MIB.addImm(static_cast<int64_t>(
+        SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100)); // Set ID
+    MIB.addImm(SPIRV::NonSemanticExtInst::DebugCompilationUnit);
+    MIB.addUse(DebugInfoVersionReg);
+    MIB.addUse(DwarfVersionReg);
+    MIB.addUse(DebugSourceResIdReg);
+    MIB.addUse(SourceLanguageReg);
+    MIB.constrainAllUses(*TII, *TRI, *RBI);
+  }
+
+  return true;
+}
+
+bool SPIRVEmitNonSemanticDI::runOnMachineFunction(MachineFunction &MF) {
+  bool Res = false;
+  if (!IsGlobalDIEmitted) {
+    Res = emitGlobalDI(MF);
+    IsGlobalDIEmitted = true;
+  }
+  return Res;
+}
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index ac0aa682ea4be..c69a82db14bb8 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -21,7 +21,6 @@
 #include "SPIRVSubtarget.h"
 #include "SPIRVTargetMachine.h"
 #include "SPIRVUtils.h"
-#include "TargetInfo/SPIRVTargetInfo.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
@@ -427,7 +426,21 @@ void SPIRVModuleAnalysis::processOtherInstrs(const Module &M) {
         if (MAI.getSkipEmission(&MI))
           continue;
         const unsigned OpCode = MI.getOpcode();
-        if (OpCode == SPIRV::OpName || OpCode == SPIRV::OpMemberName) {
+        if (OpCode == SPIRV::OpString) {
+          collectOtherInstr(MI, MAI, SPIRV::MB_DebugStrings, IS);
+        } else if (OpCode == SPIRV::OpExtInst) {
+          MachineOperand Ins = MI.getOperand(3);
+          namespace NS = SPIRV::NonSemanticExtInst;
+          static constexpr int64_t GlobalNonSemanticDITy[] = {
+              NS::DebugSource, NS::DebugCompilationUnit};
+          bool IsGlobalDI = false;
+          for (unsigned Idx = 0; Idx < std::size(GlobalNonSemanticDITy); ++Idx) {
+            IsGlobalDI |= Ins.getImm() == GlobalNonSemanticDITy[Idx];
+          }
+          if (IsGlobalDI) {
+            collectOtherInstr(MI, MAI, SPIRV::MB_NonSemanticGlobalDI, IS);
+          }
+        } else if (OpCode == SPIRV::OpName || OpCode == SPIRV::OpMemberName) {
           collectOtherInstr(MI, MAI, SPIRV::MB_DebugNames, IS);
         } else if (OpCode == SPIRV::OpEntryPoint) {
           collectOtherInstr(MI, MAI, SPIRV::MB_EntryPoints, IS);
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
index 79226d6d93efb..024728c347e8a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
@@ -20,7 +20,6 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringMap.h"
 
 namespace llvm {
 class SPIRVSubtarget;
@@ -34,9 +33,11 @@ enum ModuleSectionType {
   MB_EntryPoints, // All OpEntryPoint instructions (if any).
   //  MB_ExecutionModes, MB_DebugSourceAndStrings,
   MB_DebugNames,           // All OpName and OpMemberName intrs.
+  MB_DebugStrings,         // All OpString intrs.
   MB_DebugModuleProcessed, // All OpModuleProcessed instructions.
   MB_Annotations,          // OpDecorate, OpMemberDecorate etc.
   MB_TypeConstVars,        // OpTypeXXX, OpConstantXXX, and global OpVariables.
+  MB_NonSemanticGlobalDI,  // OpExtInst with e.g. DebugSource, DebugTypeBasic.
   MB_ExtFuncDecls,         // OpFunction etc. to declare for external funcs.
   NUM_MODULE_SECTIONS      // Total number of sections requiring basic blocks.
 };
diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
index 52fc6f33b4ef1..bffc079981bc1 100644
--- a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
@@ -199,6 +199,7 @@ void SPIRVPassConfig::addPreLegalizeMachineIR() {
 bool SPIRVPassConfig::addLegalizeMachineIR() {
   addPass(new Legalizer());
   addPass(createSPIRVPostLegalizerPass());
+  addPass(createSPIRVEmitNonSemanticDIPass(&getTM<SPIRVTargetMachine>()));
   return false;
 }
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/97558


More information about the llvm-commits mailing list