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
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] =
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));
}
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);
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
// 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);
}
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:
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)
private:
DIFile *getFile(const SPIRVId SourceId);
+
DIFile *
getDIFile(const std::string &FileName,
Optional<DIFile::ChecksumInfo<StringRef>> CS = None,
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
InstCount = 37,
FunctionDefinition = 101,
SourceContinued = 102,
+ BuildIdentifier = 105,
+ StoragePath = 106,
EntryPoint = 107,
Module = 200,
TypeSubrange = 201,
};
}
+namespace BuildIdentifier {
+enum {
+ IdentifierIdx = 0,
+ FlagsIdx = 1,
+ OperandCount = 2
+};
+}
+
+namespace StoragePath {
+enum {
+ PathIdx = 0,
+ OperandCount = 1
+};
+}
+
namespace TypeBasic {
enum {
NameIdx = 0,
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)
--- /dev/null
+; 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)