[PATCH 54/79] [DebugInfo] Support translation of DebugBuildIdentifier/DebugStoragePat...
authorLU-JOHN <111294400+LU-JOHN@users.noreply.github.com>
Fri, 19 May 2023 20:05:37 +0000 (15:05 -0500)
committerAndreas Beckmann <anbe@debian.org>
Thu, 14 Mar 2024 19:01:08 +0000 (20:01 +0100)
LLVM compileUnit dwoId is translated to/from DebugBuildIdentifier.
LLVM compileUnit splitDebugFilename is translated to/from DebugStoragePath.

Specification:
https://github.com/KhronosGroup/SPIRV-Registry/blob/main/nonsemantic/NonSemantic.Shader.DebugInfo.100.asciidoc#DebugBuildIdentifier
https://github.com/KhronosGroup/SPIRV-Registry/blob/main/nonsemantic/NonSemantic.Shader.DebugInfo.100.asciidoc#DebugStoragePath

Gbp-Pq: Name 0054-DebugInfo-Support-translation-of-DebugBuildIdentifie.patch

lib/SPIRV/LLVMToSPIRVDbgTran.cpp
lib/SPIRV/LLVMToSPIRVDbgTran.h
lib/SPIRV/SPIRVToLLVMDbgTran.cpp
lib/SPIRV/SPIRVToLLVMDbgTran.h
lib/SPIRV/libSPIRV/SPIRV.debug.h
lib/SPIRV/libSPIRV/SPIRVExtInst.h
test/DebugInfo/storagePath_dwo.ll [new file with mode: 0644]

index 753b1a2273bf3e9aed8ce7109fea29d51159de6d..527d692f948703b214501e1854e93e32ee8031ca 100644 (file)
@@ -544,6 +544,9 @@ SPIRVEntry *LLVMToSPIRVDbgTran::transDbgCompileUnit(const DICompileUnit *CU) {
   Ops[SPIRVDebugInfoVersionIdx] = SPIRVDebug::DebugInfoVersion;
   Ops[DWARFVersionIdx] = M->getDwarfVersion();
   Ops[SourceIdx] = getSource(CU)->getId();
+
+  generateBuildIdentifierAndStoragePath(CU);
+
   auto DwarfLang =
       static_cast<llvm::dwarf::SourceLanguage>(CU->getSourceLanguage());
   Ops[LanguageIdx] =
@@ -1403,6 +1406,53 @@ SPIRVExtInst *LLVMToSPIRVDbgTran::getSource(const T *DIEntry) {
   return Source;
 }
 
+void LLVMToSPIRVDbgTran::generateBuildIdentifierAndStoragePath(
+    const DICompileUnit *DIEntry) {
+  // get information from LLVM IR
+  auto BuildIdentifier = DIEntry->getDWOId();
+  const std::string BuildIdentifierString = std::to_string(BuildIdentifier);
+  const std::string StoragePath = DIEntry->getSplitDebugFilename().str();
+
+  using namespace SPIRVDebug::Operand;
+
+  if (BuildIdentifierInsn || StoragePathInsn) {
+#ifndef NDEBUG
+    assert(BuildIdentifierInsn && StoragePathInsn &&
+           "BuildIdentifier and StoragePath instructions must both be created");
+
+    auto PreviousBuildIdentifierString =
+        BM->get<SPIRVString>(
+              BuildIdentifierInsn
+                  ->getArguments()[BuildIdentifier::IdentifierIdx])
+            ->getStr();
+    assert(PreviousBuildIdentifierString == BuildIdentifierString &&
+           "New BuildIdentifier should match previous BuildIdentifier");
+    auto PreviousStoragePath =
+        BM->get<SPIRVString>(
+              StoragePathInsn->getArguments()[StoragePath::PathIdx])
+            ->getStr();
+    assert(PreviousStoragePath == StoragePath &&
+           "New StoragePath should match previous StoragePath");
+#endif
+    return;
+  }
+
+  // generate BuildIdentifier inst
+  SPIRVWordVec BuildIdentifierOps(BuildIdentifier::OperandCount);
+  BuildIdentifierOps[BuildIdentifier::IdentifierIdx] =
+      BM->getString(BuildIdentifierString)->getId();
+  BuildIdentifierOps[BuildIdentifier::FlagsIdx] =
+      BM->getLiteralAsConstant(1)->getId(); // Placeholder value for now
+  BuildIdentifierInsn = static_cast<SPIRVExtInst *>(BM->addDebugInfo(
+      SPIRVDebug::BuildIdentifier, getVoidTy(), BuildIdentifierOps));
+
+  // generate StoragePath inst
+  SPIRVWordVec StoragePathOps(StoragePath::OperandCount);
+  StoragePathOps[StoragePath::PathIdx] = BM->getString(StoragePath)->getId();
+  StoragePathInsn = static_cast<SPIRVExtInst *>(
+      BM->addDebugInfo(SPIRVDebug::StoragePath, getVoidTy(), StoragePathOps));
+}
+
 SPIRVEntry *LLVMToSPIRVDbgTran::transDbgFileType(const DIFile *F) {
   return BM->getString(getFullPath(F));
 }
index da6685c66d35075742c3773b045b7c97cf4a410e..0ca070d636754f5e30dd53326bdc4cbc68111795 100644 (file)
@@ -146,6 +146,10 @@ private:
   template <class T> SPIRVExtInst *getSource(const T *DIEntry);
   SPIRVEntry *transDbgFileType(const DIFile *F);
 
+  // Generate instructions recording identifier and file where debug information
+  // was split to
+  void generateBuildIdentifierAndStoragePath(const DICompileUnit *DIEntry);
+
   // Local Variables
   SPIRVEntry *transDbgLocalVariable(const DILocalVariable *Var);
 
@@ -170,6 +174,9 @@ private:
   std::unordered_map<const DICompileUnit *, SPIRVExtInst *> SPIRVCUMap;
   std::vector<const DbgVariableIntrinsic *> DbgDeclareIntrinsics;
   std::vector<const DbgVariableIntrinsic *> DbgValueIntrinsics;
+
+  SPIRVExtInst *BuildIdentifierInsn{nullptr};
+  SPIRVExtInst *StoragePathInsn{nullptr};
 }; // class LLVMToSPIRVDbgTran
 
 } // namespace SPIRV
index 40ad90d0c4b1637014ac059299a889c879ca008e..65bb01729d4692896bfc8a1aa777160f085f057f 100644 (file)
@@ -223,6 +223,18 @@ SPIRVToLLVMDbgTran::transCompilationUnit(const SPIRVExtInst *DebugInst,
   // TODO: Remove this workaround once we switch to NonSemantic.Shader.* debug
   // info by default
   auto Producer = findModuleProducer();
+  assert(BuilderMap.size() != 0 && "No debug compile units");
+  if (BuilderMap.size()==1)
+    // Only initialize once
+    setBuildIdentifierAndStoragePath();
+
+  if (!StoragePath.empty()) {
+    return BuilderMap[DebugInst->getId()]->createCompileUnit(
+        SourceLang, getFile(Ops[SourceIdx]), Producer, false, "", 0,
+        StoragePath, DICompileUnit::DebugEmissionKind::FullDebug,
+        BuildIdentifier);
+  }
+
   return BuilderMap[DebugInst->getId()]->createCompileUnit(
       SourceLang, getFile(Ops[SourceIdx]), Producer, false, Flags, 0);
 }
@@ -1350,6 +1362,8 @@ MDNode *SPIRVToLLVMDbgTran::transDebugInstImpl(const SPIRVExtInst *DebugInst) {
   case SPIRVDebug::Operation: // To be translated with transExpression
   case SPIRVDebug::Source:    // To be used by other instructions
   case SPIRVDebug::SourceContinued:
+  case SPIRVDebug::BuildIdentifier: // To be used by transCompilationUnit
+  case SPIRVDebug::StoragePath:     // To be used by transCompilationUnit
     return nullptr;
 
   case SPIRVDebug::Expression:
@@ -1514,6 +1528,43 @@ DIFile *SPIRVToLLVMDbgTran::getFile(const SPIRVId SourceId) {
                    getStringSourceContinued(StrIdx, Source));
 }
 
+void SPIRVToLLVMDbgTran::setBuildIdentifierAndStoragePath() {
+#ifndef NDEBUG
+  bool FoundBuildIdentifier{false};
+  bool FoundStoragePath{false};
+#endif
+
+  for (SPIRVExtInst *EI : BM->getDebugInstVec()) {
+    if (EI->getExtOp() == SPIRVDebug::BuildIdentifier) {
+      using namespace SPIRVDebug::Operand::BuildIdentifier;
+      SPIRVWordVec BuildIdentifierArgs = EI->getArguments();
+      assert(BuildIdentifierArgs.size() == OperandCount &&
+             "Invalid number of operands");
+      assert(!FoundBuildIdentifier &&
+             "More than one BuildIdentifier instruction not allowed");
+      BuildIdentifier = strtoull(
+          getString(BuildIdentifierArgs[IdentifierIdx]).c_str(), NULL, 10);
+#ifndef NDEBUG
+      FoundBuildIdentifier = true;
+#endif
+    } else if (EI->getExtOp() == SPIRVDebug::StoragePath) {
+      using namespace SPIRVDebug::Operand::StoragePath;
+      SPIRVWordVec StoragePathArgs = EI->getArguments();
+      assert(StoragePathArgs.size() == OperandCount &&
+             "Invalid number of operands");
+      assert(!FoundStoragePath &&
+             "More than one StoragePath instruction not allowed");
+      StoragePath = getString(StoragePathArgs[PathIdx]);
+#ifndef NDEBUG
+      FoundStoragePath = true;
+#endif
+    }
+  }
+  assert(((FoundBuildIdentifier && FoundStoragePath) ||
+          (!FoundBuildIdentifier && !FoundStoragePath)) &&
+         "BuildIdentifier and StoragePath must both be set or both unset");
+}
+
 DIBuilder &SPIRVToLLVMDbgTran::getDIBuilder(const SPIRVExtInst *DebugInst) {
   assert(BuilderMap.size() != 0 && "No debug compile units");
   if (BuilderMap.size() == 1)
index 9e9dbc4c9b930403c023c4fb5bf4b854193ad86b..50d0d1e53b60b7d51d829195ae1ac385d7c7a514 100644 (file)
@@ -89,6 +89,7 @@ public:
 
 private:
   DIFile *getFile(const SPIRVId SourceId);
+
   DIFile *
   getDIFile(const std::string &FileName,
             Optional<DIFile::ChecksumInfo<StringRef>> CS = None,
@@ -204,6 +205,12 @@ private:
                                       const SPIRVExtInstSetKind);
   std::string findModuleProducer();
   Optional<DIFile::ChecksumInfo<StringRef>> ParseChecksum(StringRef Text);
+
+  // BuildIdentifier and StoragePath must both be set or both unset.
+  // If StoragePath is empty both variables are unset and not valid.
+  uint64_t BuildIdentifier{0};
+  std::string StoragePath{};
+  void setBuildIdentifierAndStoragePath();
 };
 } // namespace SPIRV
 
index 2d52fc9aff36418c1cc6bee2273fa94603d4ad20..660d9510d64bd3579e0c162a9363de5a1a265e23 100644 (file)
@@ -57,6 +57,8 @@ enum Instruction {
   InstCount                     = 37,
   FunctionDefinition            = 101,
   SourceContinued               = 102,
+  BuildIdentifier               = 105,
+  StoragePath                   = 106,
   EntryPoint                    = 107,
   Module                        = 200,
   TypeSubrange                  = 201,
@@ -321,6 +323,21 @@ enum {
 };
 }
 
+namespace BuildIdentifier {
+enum {
+  IdentifierIdx = 0,
+  FlagsIdx      = 1,
+  OperandCount  = 2
+};
+}
+
+namespace StoragePath {
+enum {
+  PathIdx       = 0,
+  OperandCount  = 1
+};
+}
+
 namespace TypeBasic {
 enum {
   NameIdx                 = 0,
index fc16a994cb358b9f9107127cd7f671d7a9e9e589..315f73f03ed2f103bafb41cda4fa9436afceed4c 100644 (file)
@@ -263,6 +263,8 @@ template <> inline void SPIRVMap<SPIRVDebugExtOpKind, std::string>::init() {
   add(SPIRVDebug::FunctionDefinition, "DebugFunctionDefinition");
   add(SPIRVDebug::SourceContinued, "DebugSourceContinued");
   add(SPIRVDebug::EntryPoint, "DebugEntryPoint");
+  add(SPIRVDebug::BuildIdentifier, "DebugBuildIdentifier");
+  add(SPIRVDebug::StoragePath, "DebugStoragePath");
 }
 SPIRV_DEF_NAMEMAP(SPIRVDebugExtOpKind, SPIRVDebugExtOpMap)
 
diff --git a/test/DebugInfo/storagePath_dwo.ll b/test/DebugInfo/storagePath_dwo.ll
new file mode 100644 (file)
index 0000000..1cbb0ab
--- /dev/null
@@ -0,0 +1,33 @@
+; Test checks that dwoId and splitDebugFilename is preserved from LLVM IR to spirv
+; and spirv to LLVM IR translation.
+
+; RUN: llvm-as %s -o %t.bc
+; RUN: llvm-spirv %t.bc -spirv-text -o - | FileCheck %s --check-prefix CHECK-SPIRV
+; RUN: llvm-spirv %t.bc -o %t.spv
+; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
+; RUN: llvm-dis %t.rev.bc -o %t.rev.ll
+; RUN: FileCheck %s --input-file %t.rev.ll --check-prefix CHECK-LLVM
+
+; CHECK-SPIRV: String [[#stringA_id:]] "11111"
+; CHECK-SPIRV: String [[#stringA_sf:]] "debugA_info.dwo"
+; CHECK-SPIRV: [[#buildID_A:]] [[#]] DebugBuildIdentifier [[#stringA_id]]
+; CHECK-SPIRV: [[#storageID_A:]] [[#]] DebugStoragePath [[#stringA_sf]]
+
+; CHECK-LLVM: !DICompileUnit
+; CHECK-LLVM-SAME: splitDebugFilename: "debugA_info.dwo"
+; CHECK-LLVM-SAME: dwoId: 11111
+; CHECK-LLVM: !DICompileUnit
+; CHECK-LLVM-SAME: splitDebugFilename: "debugA_info.dwo"
+; CHECK-LLVM-SAME: dwoId: 11111
+
+!llvm.dbg.cu = !{!7, !0}
+!llvm.module.flags = !{!3, !4}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Clang", isOptimized: false, runtimeVersion: 2, splitDebugFilename: "debugA_info.dwo", emissionKind: FullDebug, enums: !2, retainedTypes: !2, globals: !2, imports: !2, dwoId: 11111)
+!1 = !DIFile(filename: "<stdin>", directory: "/")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{!6}
+!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!7 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Clang", isOptimized: false, runtimeVersion: 2, splitDebugFilename: "debugA_info.dwo", dwoId: 11111, emissionKind: FullDebug, retainedTypes: !5)