Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions lib/SPIRV/LLVMToSPIRVDbgTran.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ void LLVMToSPIRVDbgTran::transDebugMetadata() {
transDbgEntry(IE);
}

transDbgMacros();

for (const DIType *T : DIF.types())
transDbgEntry(T);

Expand Down Expand Up @@ -1681,3 +1683,75 @@ SPIRVEntry *LLVMToSPIRVDbgTran::transDbgModule(const DIModule *Module) {
BM->addCapability(spv::CapabilityDebugInfoModuleINTEL);
return BM->addDebugInfo(SPIRVDebug::ModuleINTEL, getVoidTy(), Ops);
}

void LLVMToSPIRVDbgTran::transDbgMacros() {
auto ProcessMacros = [&](unsigned MacroType, auto &&Handler) {
for (const auto &[Macro, MacroFile] : DIF.macros()) {
if (Macro->getMacinfoType() != MacroType)
continue;

SPIRVString *FileName = BM->getString("");
if (MacroFile && MacroFile->getFile())
FileName = BM->getString(getFullPath(MacroFile->getFile()));

Handler(Macro, FileName);
}
};

// Process DW_MACINFO_define macros and populate MacroDefMap
ProcessMacros(dwarf::DW_MACINFO_define,
[&](const DIMacro *Macro, SPIRVString *FileName) {
transDbgMacroDefine(Macro, FileName);
});

// Process DW_MACINFO_undef macros (after DW_MACINFO_define populates
// MacroDefMap). DebugMacroUndef in SPIR-V requires a reference to the
// DebugMacroDef (not just the macro name as in LLVM IR)
ProcessMacros(dwarf::DW_MACINFO_undef,
[&](const DIMacro *Macro, SPIRVString *FileName) {
transDbgMacroUndef(Macro, FileName);
});
}

SPIRVEntry *LLVMToSPIRVDbgTran::transDbgMacroDefine(const DIMacro *Macro,
SPIRVString *FileName) {
SPIRVWordVec Ops;
using namespace SPIRVDebug::Operand::MacroDef;
Ops.resize(OperandCount);
Ops[SourceIdx] = FileName->getId();
Ops[LineIdx] =
SPIRVWriter->transValue(getUInt(M, Macro->getLine()), nullptr)->getId();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm looking correctly at the spec, Line is a literal number, not an <id>.

Ops[NameIdx] = BM->getString(Macro->getName().str())->getId();
Ops[ValueIdx] = BM->getString(Macro->getValue().str())->getId();

SPIRVEntry *MacroEntry =
BM->addDebugInfo(SPIRVDebug::MacroDef, getVoidTy(), Ops);
MDMap[Macro] = MacroEntry;
MacroDefMap[Macro->getName().str()] = static_cast<SPIRVExtInst *>(MacroEntry);
return MacroEntry;
}

SPIRVEntry *LLVMToSPIRVDbgTran::transDbgMacroUndef(const DIMacro *Macro,
SPIRVString *FileName) {
SPIRVWordVec Ops;
using namespace SPIRVDebug::Operand::MacroUndef;
Ops.resize(OperandCount);
Ops[SourceIdx] = FileName->getId();
Ops[LineIdx] =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same than above.

SPIRVWriter->transValue(getUInt(M, Macro->getLine()), nullptr)->getId();

SPIRVId MacroDefId = getDebugInfoNoneId();

// transDbgMacroDefine is processed first so MacroDefMap is already populated
// at this point
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// at this point
// at this point.

auto It = MacroDefMap.find(Macro->getName().str());
if (It != MacroDefMap.end()) {
MacroDefId = It->second->getId();
}

Ops[MacroIdx] = MacroDefId;
SPIRVEntry *MacroEntry =
BM->addDebugInfo(SPIRVDebug::MacroUndef, getVoidTy(), Ops);
MDMap[Macro] = MacroEntry;
return MacroEntry;
}
6 changes: 6 additions & 0 deletions lib/SPIRV/LLVMToSPIRVDbgTran.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ class LLVMToSPIRVDbgTran {
// A module in programming language. Example - Fortran module, clang module.
SPIRVEntry *transDbgModule(const DIModule *IE);

// Macros
SPIRVEntry *transDbgMacroDefine(const DIMacro *Macro, SPIRVString *FileName);
SPIRVEntry *transDbgMacroUndef(const DIMacro *Macro, SPIRVString *FileName);
void transDbgMacros();

// Flags
SPIRVWord mapDebugFlags(DINode::DIFlags DFlags);
SPIRVWord transDebugFlags(const DINode *DN);
Expand All @@ -174,6 +179,7 @@ class LLVMToSPIRVDbgTran {
LLVMToSPIRVBase *SPIRVWriter;
std::unordered_map<const MDNode *, SPIRVEntry *> MDMap;
std::unordered_map<std::string, SPIRVExtInst *> FileMap;
std::unordered_map<std::string, SPIRVExtInst *> MacroDefMap;
DebugInfoFinder DIF;
SPIRVType *VoidT = nullptr;
SPIRVType *Int32T = nullptr;
Expand Down
76 changes: 76 additions & 0 deletions lib/SPIRV/SPIRVToLLVMDbgTran.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1407,6 +1407,76 @@ DINode *SPIRVToLLVMDbgTran::transModule(const SPIRVExtInst *DebugInst) {
Scope, Name, ConfigMacros, IncludePath, ApiNotes, File, Line, IsDecl);
}

DIMacroFile *
SPIRVToLLVMDbgTran::getOrCreateMacroFile(DIFile *File,
const SPIRVExtInst *DebugInst) {
auto It = MacroFileMap.find(File);
if (It != MacroFileMap.end())
return It->second;

// Use nullptr parent (top-level) since SPIR-V DebugMacroDef doesn't preserve
// include hierarchy. All macro files are treated as root files.
DIMacroFile *MacroFile =
getDIBuilder(DebugInst).createTempMacroFile(nullptr, 0, File);
MacroFileMap[File] = MacroFile;
return MacroFile;
}

DIMacro *SPIRVToLLVMDbgTran::transMacroDef(const SPIRVExtInst *DebugInst) {
using namespace SPIRVDebug::Operand::MacroDef;
const SPIRVWordVec &Ops = DebugInst->getArguments();
assert(Ops.size() >= OperandCount && "Invalid number of operands");

const std::string &SourceFileName = getString(Ops[SourceIdx]);
DIFile *File = getDIFile(SourceFileName);

DIMacroFile *MacroFile =
!File ? nullptr : getOrCreateMacroFile(File, DebugInst);

SPIRVWord Line =
getConstantValueOrLiteral(Ops, LineIdx, DebugInst->getExtSetKind());
StringRef Name = getString(Ops[NameIdx]);
StringRef Value = getString(Ops[ValueIdx]);

return getDIBuilder(DebugInst).createMacro(
MacroFile, Line, dwarf::DW_MACINFO_define, Name, Value);
}

DIMacro *SPIRVToLLVMDbgTran::transMacroUndef(const SPIRVExtInst *DebugInst) {
using namespace SPIRVDebug::Operand::MacroUndef;
const SPIRVWordVec &Ops = DebugInst->getArguments();
assert(Ops.size() >= OperandCount && "Invalid number of operands");

const std::string &SourceFileName = getString(Ops[SourceIdx]);
DIFile *File = getDIFile(SourceFileName);

DIMacroFile *MacroFile =
!File ? nullptr : getOrCreateMacroFile(File, DebugInst);

SPIRVWord Line =
getConstantValueOrLiteral(Ops, LineIdx, DebugInst->getExtSetKind());

DIMacro *ReferencedMacro =
transDebugInst<DIMacro>(BM->get<SPIRVExtInst>(Ops[MacroIdx]));

// Handle edge case: LLVM IR allows DW_MACINFO_undef without a prior
// DW_MACINFO_def (i.e., undefining a macro that was never defined).
// Example: !DIMacro(type: DW_MACINFO_undef, line: 1, name: "SIZE")
// with no corresponding DW_MACINFO_def for "SIZE"
//
// When translated to SPIR-V, this becomes:
// DebugMacroUndef <source> <line> DebugInfoNone
//
// This results in ReferencedMacro being nullptr. We must use a non-empty
// fallback name because DIBuilder::createMacro() in LLVM rejects empty
// strings.
StringRef Name =
ReferencedMacro ? ReferencedMacro->getName() : "<UNAVAILABLE_MACRO_NAME>";

return getDIBuilder(DebugInst).createMacro(MacroFile, Line,
dwarf::DW_MACINFO_undef, Name);
}

MDNode *SPIRVToLLVMDbgTran::transExpression(const SPIRVExtInst *DebugInst) {
const SPIRVWordVec &Args = DebugInst->getArguments();
std::vector<uint64_t> Ops;
Expand Down Expand Up @@ -1530,6 +1600,12 @@ MDNode *SPIRVToLLVMDbgTran::transDebugInstImpl(const SPIRVExtInst *DebugInst) {
case SPIRVDebug::ModuleINTEL:
return transModule(DebugInst);

case SPIRVDebug::MacroDef:
return transMacroDef(DebugInst);

case SPIRVDebug::MacroUndef:
return transMacroUndef(DebugInst);

case SPIRVDebug::Operation: // To be translated with transExpression
case SPIRVDebug::Source: // To be used by other instructions
case SPIRVDebug::SourceContinued:
Expand Down
8 changes: 8 additions & 0 deletions lib/SPIRV/SPIRVToLLVMDbgTran.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,13 @@ class SPIRVToLLVMDbgTran {

DINode *transModule(const SPIRVExtInst *DebugInst);

DIMacro *transMacroDef(const SPIRVExtInst *DebugInst);

DIMacro *transMacroUndef(const SPIRVExtInst *DebugInst);

DIMacroFile *getOrCreateMacroFile(DIFile *File,
const SPIRVExtInst *DebugInst);

MDNode *transExpression(const SPIRVExtInst *DebugInst);

SPIRVModule *BM;
Expand All @@ -188,6 +195,7 @@ class SPIRVToLLVMDbgTran {
std::unordered_map<std::string, DIFile *> FileMap;
std::unordered_map<SPIRVId, DISubprogram *> FuncMap;
std::unordered_map<const SPIRVExtInst *, MDNode *> DebugInstCache;
std::unordered_map<DIFile *, DIMacroFile *> MacroFileMap;

struct SplitFileName {
SplitFileName(const std::string &FileName);
Expand Down
19 changes: 19 additions & 0 deletions lib/SPIRV/libSPIRV/SPIRV.debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -971,6 +971,25 @@ enum {
} // namespace NonSemantic
} // namespace ImportedEntity

namespace MacroDef {
enum {
SourceIdx = 0,
LineIdx = 1,
NameIdx = 2,
ValueIdx = 3,
OperandCount = 4
};
}

namespace MacroUndef {
enum {
SourceIdx = 0,
LineIdx = 1,
MacroIdx = 2,
OperandCount = 3
};
}

namespace ModuleINTEL {
enum {
NameIdx = 0,
Expand Down
2 changes: 2 additions & 0 deletions lib/SPIRV/libSPIRV/SPIRVExtInst.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ template <> inline void SPIRVMap<SPIRVDebugExtOpKind, std::string>::init() {
add(SPIRVDebug::NoScope, "DebugNoScope");
add(SPIRVDebug::InlinedAt, "DebugInlinedAt");
add(SPIRVDebug::ImportedEntity, "DebugImportedEntity");
add(SPIRVDebug::MacroDef, "DebugMacroDef");
add(SPIRVDebug::MacroUndef, "DebugMacroUndef");
add(SPIRVDebug::ModuleINTEL, "DebugModuleINTEL");
add(SPIRVDebug::Module, "DebugModule");
add(SPIRVDebug::Expression, "DebugExpression");
Expand Down
55 changes: 55 additions & 0 deletions test/DebugInfo/DebugMacroDef.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
; Test round-trip translation of debug macro information:
; LLVM IR -> SPIR-V -> LLVM IR

; RUN: llvm-spirv --spirv-debug-info-version=nonsemantic-shader-100 %s -o %t.spv
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implement bidirectional translation of LLVM DIMacro to SPIR-V DebugMacroDef and DebugMacroUndef instructions.

Note, that the spec links in the PR description are leading to OpenCL.DebugInfo.100 instruction set, while:
a. tests are covering nonsemantic debug info;
b. code is also build for nonsemantic, see few Literal parameters of the instructions in the referenced OpenCL spec, while in the implementation (and nonsemantic variant) there operands are Ids.

I'd suggest to test and implement all 3 debug information types: OpenCL, nonsemantic.100 and nonsemantic.200. The later 2 are identical for Macro handling. OpenCL is a bit different, but not that drastically: see the following lines here and there which transforms literals to constants:

    if (isNonSemanticDebugInfo())
      transformToConstant(Ops, {ScopeLineIdx});

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, will do.

; RUN: spirv-val %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

; CHECK-DAG: ![[#r1:]] = !DIFile(filename: "def.c", directory: ".")
; CHECK-DAG: ![[#r2:]] = !DIMacroFile(file: ![[#r1]], nodes: ![[#r3:]])
; CHECK-DAG: ![[#r3]] = !{![[#r4:]], ![[#r5:]]}
; CHECK-DAG: ![[#r4]] = !DIMacro(type: DW_MACINFO_define, line: 1, name: "SIZE", value: "5")
; CHECK-DAG: ![[#r5]] = !DIMacro(type: DW_MACINFO_undef, line: 1, name: "SIZE")

target triple = "spir64-unknown-unknown"

; Function Attrs: nounwind
define spir_func i32 @main() #0 {
entry:
ret i32 0
}

attributes #0 = { nounwind }

!llvm.module.flags = !{!0, !1, !12}
!llvm.dbg.cu = !{!4}
!spirv.MemoryModel = !{!13}
!opencl.enable.FP_CONTRACT = !{}
!spirv.Source = !{!14}
!opencl.spir.version = !{!15}
!opencl.used.extensions = !{!16}
!opencl.used.optional.core.features = !{!16}
!spirv.Generator = !{!17}

!0 = !{i32 7, !"Dwarf Version", i32 0}
!1 = !{i32 2, !"Source Lang Literal", !2}
!2 = !{!3}
!3 = !{!4, i32 12}
!4 = distinct !DICompileUnit(language: DW_LANG_OpenCL, file: !5, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, macros: !6)
!5 = !DIFile(filename: "def.c", directory: "/tmp")
!6 = !{!7}
!7 = !DIMacroFile(file: !8, nodes: !9)
!8 = !DIFile(filename: "def.c", directory: ".")
!9 = !{!10, !11}
!10 = !DIMacro(type: DW_MACINFO_define, line: 1, name: "SIZE", value: "5")
!11 = !DIMacro(type: DW_MACINFO_undef, line: 1, name: "SIZE")
!12 = !{i32 2, !"Debug Info Version", i32 3}
!13 = !{i32 2, i32 2}
!14 = !{i32 4, i32 100000}
!15 = !{i32 1, i32 2}
!16 = !{}
!17 = !{i16 7, i16 0}

50 changes: 50 additions & 0 deletions test/DebugInfo/DebugMacroDefRoot.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
; This test exercises the case where the DICompileUnit has as !DIMacro without a DIMacroFile

; Test round-trip translation of debug macro information:
; LLVM IR -> SPIR-V -> LLVM IR

; RUN: llvm-spirv --spirv-debug-info-version=nonsemantic-shader-100 %s -o %t.spv
; RUN: spirv-val %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-NOT: !DIMacroFile
; CHECK-DAG: !DIMacro(type: DW_MACINFO_define, line: 1, name: "SIZE", value: "5")

target triple = "spir64-unknown-unknown"

; Function Attrs: nounwind
define spir_func i32 @main() #0 {
entry:
ret i32 0
}

attributes #0 = { nounwind }

!llvm.module.flags = !{!0, !1, !12}
!llvm.dbg.cu = !{!4}
!spirv.MemoryModel = !{!13}
!opencl.enable.FP_CONTRACT = !{}
!spirv.Source = !{!14}
!opencl.spir.version = !{!15}
!opencl.used.extensions = !{!16}
!opencl.used.optional.core.features = !{!16}
!spirv.Generator = !{!17}

!0 = !{i32 7, !"Dwarf Version", i32 0}
!1 = !{i32 2, !"Source Lang Literal", !2}
!2 = !{!3}
!3 = !{!4, i32 12}
!4 = distinct !DICompileUnit(language: DW_LANG_OpenCL, file: !5, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, macros: !6)
!5 = !DIFile(filename: "def.c", directory: "/tmp")
!6 = !{!10}
!10 = !DIMacro(type: DW_MACINFO_define, line: 1, name: "SIZE", value: "5")
!12 = !{i32 2, !"Debug Info Version", i32 3}
!13 = !{i32 2, i32 2}
!14 = !{i32 4, i32 100000}
!15 = !{i32 1, i32 2}
!16 = !{}
!17 = !{i16 7, i16 0}

Loading
Loading