[DebugInfo] Add macro tracking support to DebugInfoFinder (#179931)
Extend `DebugInfoFinder` to collect and expose macro debug information (`DIMacro` and `DIMacroFile` nodes). Also update `ModuleDebugInfoPrinter` to display macro information including the macro type, name, value, and source location. ----- The motivation behind this PR is that `DebugInfoFinder` is key for the [SPIRV-LLVM-Translator](https://github.com/KhronosGroup/SPIRV-LLVM-Translator) and also for future support of debug info in the SPIRV backend in LLVM. This new lookup of `DIMacro` with their `DIMacroFile` when available simplifies the logic around the translation for this debug information.
This commit is contained in:
parent
52955f8b27
commit
c8d8e5e210
4 changed files with 108 additions and 0 deletions
|
|
@ -127,13 +127,16 @@ private:
|
|||
void processScope(DIScope *Scope);
|
||||
void processType(DIType *DT);
|
||||
void processImportedEntity(const DIImportedEntity *Import);
|
||||
void processMacroNode(DIMacroNode *Macro, DIMacroFile *CurrentMacroFile);
|
||||
bool addCompileUnit(DICompileUnit *CU);
|
||||
bool addGlobalVariable(DIGlobalVariableExpression *DIG);
|
||||
bool addScope(DIScope *Scope);
|
||||
bool addSubprogram(DISubprogram *SP);
|
||||
bool addType(DIType *DT);
|
||||
bool addMacro(DIMacro *Macro, DIMacroFile *MacroFile);
|
||||
|
||||
public:
|
||||
using DIMacroEntry = std::pair<DIMacro *, DIMacroFile *>;
|
||||
using compile_unit_iterator =
|
||||
SmallVectorImpl<DICompileUnit *>::const_iterator;
|
||||
using subprogram_iterator = SmallVectorImpl<DISubprogram *>::const_iterator;
|
||||
|
|
@ -141,6 +144,7 @@ public:
|
|||
SmallVectorImpl<DIGlobalVariableExpression *>::const_iterator;
|
||||
using type_iterator = SmallVectorImpl<DIType *>::const_iterator;
|
||||
using scope_iterator = SmallVectorImpl<DIScope *>::const_iterator;
|
||||
using macro_iterator = SmallVectorImpl<DIMacroEntry>::const_iterator;
|
||||
|
||||
iterator_range<compile_unit_iterator> compile_units() const { return CUs; }
|
||||
|
||||
|
|
@ -154,11 +158,14 @@ public:
|
|||
|
||||
iterator_range<scope_iterator> scopes() const { return Scopes; }
|
||||
|
||||
iterator_range<macro_iterator> macros() const { return Macros; }
|
||||
|
||||
unsigned compile_unit_count() const { return CUs.size(); }
|
||||
unsigned global_variable_count() const { return GVs.size(); }
|
||||
unsigned subprogram_count() const { return SPs.size(); }
|
||||
unsigned type_count() const { return TYs.size(); }
|
||||
unsigned scope_count() const { return Scopes.size(); }
|
||||
unsigned macro_count() const { return Macros.size(); }
|
||||
|
||||
private:
|
||||
SmallVector<DICompileUnit *, 8> CUs;
|
||||
|
|
@ -166,6 +173,7 @@ private:
|
|||
SmallVector<DIGlobalVariableExpression *, 8> GVs;
|
||||
SmallVector<DIType *, 8> TYs;
|
||||
SmallVector<DIScope *, 8> Scopes;
|
||||
SmallVector<DIMacroEntry, 8> Macros;
|
||||
SmallPtrSet<const MDNode *, 32> NodesSeen;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -103,6 +103,31 @@ static void printModuleDebugInfo(raw_ostream &O, const Module *M,
|
|||
}
|
||||
O << '\n';
|
||||
}
|
||||
|
||||
for (const auto &MacroEntry : Finder.macros()) {
|
||||
const DIMacro *Macro = MacroEntry.first;
|
||||
const DIMacroFile *MacroFile = MacroEntry.second;
|
||||
|
||||
O << "Macro: ";
|
||||
auto MacroType = dwarf::MacinfoString(Macro->getMacinfoType());
|
||||
if (!MacroType.empty())
|
||||
O << MacroType;
|
||||
else
|
||||
O << "unknown-macinfo(" << Macro->getMacinfoType() << ")";
|
||||
|
||||
O << " '" << Macro->getName() << "'";
|
||||
if (!Macro->getValue().empty())
|
||||
O << " = '" << Macro->getValue() << "'";
|
||||
|
||||
if (MacroFile && MacroFile->getFile()) {
|
||||
const DIFile *File = MacroFile->getFile();
|
||||
printFile(O, File->getFilename(), File->getDirectory(),
|
||||
MacroFile->getLine());
|
||||
} else {
|
||||
O << " at line " << Macro->getLine();
|
||||
}
|
||||
O << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
ModuleDebugInfoPrinterPass::ModuleDebugInfoPrinterPass(raw_ostream &OS)
|
||||
|
|
|
|||
|
|
@ -176,6 +176,7 @@ void DebugInfoFinder::reset() {
|
|||
GVs.clear();
|
||||
TYs.clear();
|
||||
Scopes.clear();
|
||||
Macros.clear();
|
||||
NodesSeen.clear();
|
||||
}
|
||||
|
||||
|
|
@ -212,6 +213,8 @@ void DebugInfoFinder::processCompileUnit(DICompileUnit *CU) {
|
|||
processSubprogram(cast<DISubprogram>(RT));
|
||||
for (auto *Import : CU->getImportedEntities())
|
||||
processImportedEntity(Import);
|
||||
for (auto *Macro : CU->getMacros())
|
||||
processMacroNode(Macro, nullptr);
|
||||
}
|
||||
|
||||
void DebugInfoFinder::processInstruction(const Module &M,
|
||||
|
|
@ -275,6 +278,36 @@ void DebugInfoFinder::processImportedEntity(const DIImportedEntity *Import) {
|
|||
processScope(M->getScope());
|
||||
}
|
||||
|
||||
/// Process a macro debug info node (DIMacroNode).
|
||||
///
|
||||
/// A DIMacroNode is one of two types:
|
||||
/// - DIMacro: A single macro definition. Add it to the Macros list along with
|
||||
/// its containing DIMacroFile.
|
||||
/// - DIMacroFile: A file containing macros. Recursively process all nested
|
||||
/// macro nodes within it (avoiding duplicates by tracking visited nodes).
|
||||
void DebugInfoFinder::processMacroNode(DIMacroNode *Macro,
|
||||
DIMacroFile *CurrentMacroFile) {
|
||||
if (!Macro)
|
||||
return;
|
||||
|
||||
if (auto *M = dyn_cast<DIMacro>(Macro)) {
|
||||
addMacro(M, CurrentMacroFile);
|
||||
return;
|
||||
}
|
||||
|
||||
auto *MF = dyn_cast<DIMacroFile>(Macro);
|
||||
assert(MF &&
|
||||
"Expected a DIMacroFile (it can't be any other type at this point)");
|
||||
|
||||
// Check if we've already seen this macro file to avoid infinite recursion
|
||||
if (!NodesSeen.insert(MF).second)
|
||||
return;
|
||||
|
||||
// Recursively process nested macros in the macro file
|
||||
for (auto *Element : MF->getElements())
|
||||
processMacroNode(Element, MF);
|
||||
}
|
||||
|
||||
void DebugInfoFinder::processScope(DIScope *Scope) {
|
||||
if (!Scope)
|
||||
return;
|
||||
|
|
@ -389,6 +422,17 @@ bool DebugInfoFinder::addScope(DIScope *Scope) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DebugInfoFinder::addMacro(DIMacro *Macro, DIMacroFile *MacroFile) {
|
||||
if (!Macro)
|
||||
return false;
|
||||
|
||||
if (!NodesSeen.insert(Macro).second)
|
||||
return false;
|
||||
|
||||
Macros.push_back(std::make_pair(Macro, MacroFile));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Recursively handle DILocations in followup metadata etc.
|
||||
///
|
||||
/// TODO: If for example a followup loop metadata would reference itself this
|
||||
|
|
|
|||
31
llvm/test/DebugInfo/Generic/debuginfofinder-macros.ll
Normal file
31
llvm/test/DebugInfo/Generic/debuginfofinder-macros.ll
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
; RUN: opt -passes='print<module-debuginfo>' -disable-output 2>&1 < %s \
|
||||
; RUN: | FileCheck %s
|
||||
|
||||
; Macro hierarchy graph:
|
||||
; CompileUnit
|
||||
; ├── MacroFile: ./def.c (!2)
|
||||
; │ ├── Define Macro: 'SIZE' = '5' (!6)
|
||||
; │ ├── Undef Macro: 'SIZE' (!7)
|
||||
; │ └── MacroFile: ./def.nested.c (!4)
|
||||
; │ └── Undef Macro: 'BAZ' (!9)
|
||||
; └── Define Macro: 'BAZ' (!8)
|
||||
|
||||
; CHECK: Macro: DW_MACINFO_define 'SIZE' = '5' from ./def.c
|
||||
; CHECK: Macro: DW_MACINFO_undef 'SIZE' from ./def.c
|
||||
; CHECK: Macro: DW_MACINFO_undef 'BAZ' from ./def.nested.c
|
||||
; CHECK: Macro: DW_MACINFO_define 'BAZ' at line 1
|
||||
|
||||
!llvm.module.flags = !{!0, !10}
|
||||
!llvm.dbg.cu = !{!1}
|
||||
|
||||
!0 = !{i32 7, !"Dwarf Version", i32 0}
|
||||
!1 = distinct !DICompileUnit(language: DW_LANG_OpenCL, file: !3, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, macros: !{!2, !8})
|
||||
!2 = !DIMacroFile(file: !3, nodes: !{!6, !7, !4})
|
||||
!3 = !DIFile(filename: "def.c", directory: ".")
|
||||
!4 = !DIMacroFile(file: !5, nodes: !{!9})
|
||||
!5 = !DIFile(filename: "def.nested.c", directory: ".")
|
||||
!6 = !DIMacro(type: DW_MACINFO_define, line: 1, name: "SIZE", value: "5")
|
||||
!7 = !DIMacro(type: DW_MACINFO_undef, line: 1, name: "SIZE")
|
||||
!8 = !DIMacro(type: DW_MACINFO_define, line: 1, name: "BAZ")
|
||||
!9 = !DIMacro(type: DW_MACINFO_undef, line: 1, name: "BAZ")
|
||||
!10 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
Loading…
Reference in a new issue