diff --git a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst index 6fcf8423e8125..5d9c838bf3d03 100644 --- a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst +++ b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst @@ -391,6 +391,8 @@ to make the output easier to understand. .. code-block:: text =children: Elements and children are displayed in a tree format. + =debugger: Lines, and optionally variables and instructions are + displayed in a way to simulate stepping through a debugger. =list: Elements are displayed in a tabular format. =parents: Elements and parents are displayed in a tree format. =view: Elements, parents and children are displayed in a tree format. @@ -410,6 +412,10 @@ child (level 1). The **children** layout includes the elements that match any given criteria (:option:`--select`) or (:option:`--compare`) and its children. +The **debugger** layout prints each statement line in order and variables +live at each line (if `--print=symbols` given), as well as instructions +(if `--print=instructions` given). + The **parents** layout includes the elements that match any given criteria (:option:`--select`) or (:option:`--compare`) and its parents. @@ -855,6 +861,87 @@ layout and given the number of matches. ----------------------------- Total 26 8 +DEBUGGER VIEW +""""""""""""" +In debugger view, :program:`llvm-debuginfo-analyzer` prints out +debug-info in a manner that emulates a debugger. For each function, each +statement line is printed out in order, complete with the inlined +callstack. This is useful to verify the specific orders of lines, as +well as verifying inline callstacks. + +.. code-block:: none + + llvm-debuginfo-analyzer --report=debugger + test-dwarf-clang.o test-dwarf-gcc.o + + Logical View: + {File} test-dwarf-clang.o + {CompileUnit} test.cpp + {Function} foo + {Line} test.cpp:2 [foo] + {Line} test.cpp:3 [foo] + {Line} test.cpp:5 [foo] + {Line} test.cpp:6 [foo] + {Line} test.cpp:8 [foo] + {Line} test.cpp:9 [foo] + + Logical View: + {File} test-dwarf-gcc.o + {CompileUnit} test.cpp + {Function} foo + {Line} test.cpp:2 [foo] + {Line} test.cpp:3 [foo] + {Line} test.cpp:5 [foo] + {Line} test.cpp:6 [foo] + {Line} test.cpp:8 [foo] + {Line} test.cpp:9 [foo] + +Optionally, by adding `--print=symbols`, live variables for each line is +printed out. + +.. code-block:: none + + llvm-debuginfo-analyzer --report=debugger + test-dwarf-clang.o + + Logical View: + {File} test-dwarf-clang.o + {CompileUnit} test.cpp + {Function} foo + {Line} test.cpp:2 [foo] + {Parameter} ParamBool: bool : fbreg -21 (line 2) + {Parameter} ParamPtr: INTPTR : fbreg -16 (line 2) + {Parameter} ParamUnsigned: unsigned int : fbreg -20 (line 2) + {Line} test.cpp:3 [foo] + {Parameter} ParamBool: bool : fbreg -21 (line 2) + {Parameter} ParamPtr: INTPTR : fbreg -16 (line 2) + {Parameter} ParamUnsigned: unsigned int : fbreg -20 (line 2) + {Line} test.cpp:5 [foo] + {Parameter} ParamBool: bool : fbreg -21 (line 2) + {Parameter} ParamPtr: INTPTR : fbreg -16 (line 2) + {Parameter} ParamUnsigned: unsigned int : fbreg -20 (line 2) + {Variable} CONSTANT: const INTEGER : fbreg -28 (line 5) + {Line} test.cpp:6 [foo] + {Parameter} ParamBool: bool : fbreg -21 (line 2) + {Parameter} ParamPtr: INTPTR : fbreg -16 (line 2) + {Parameter} ParamUnsigned: unsigned int : fbreg -20 (line 2) + {Variable} CONSTANT: const INTEGER : fbreg -28 (line 5) + {Line} test.cpp:8 [foo] + {Parameter} ParamBool: bool : fbreg -21 (line 2) + {Parameter} ParamPtr: INTPTR : fbreg -16 (line 2) + {Parameter} ParamUnsigned: unsigned int : fbreg -20 (line 2) + {Line} test.cpp:9 [foo] + {Parameter} ParamBool: bool : fbreg -21 (line 2) + {Parameter} ParamPtr: INTPTR : fbreg -16 (line 2) + {Parameter} ParamUnsigned: unsigned int : fbreg -20 (line 2) + +Optionally, `--print=instructions`, the lines are interleaved with the +instructions. Combined with the output of `--print=symbols`, tests can +verify specific expressions for live variables. + +Additionally, `--attribute` can be used to include things such as +offsets and scope levels for {Line} and {Instruction}. + COMPARISON MODE ^^^^^^^^^^^^^^^ In this mode :program:`llvm-debuginfo-analyzer` compares logical views diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h index 3618ce7b0ecda..d15cc50f54c58 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h @@ -105,6 +105,7 @@ class LLVM_ABI LVLine : public LVElement { void print(raw_ostream &OS, bool Full = true) const override; void printExtra(raw_ostream &OS, bool Full = true) const override {} + virtual void printDebugger(raw_ostream &OS, LVLevel Indent) const {} }; // Class to represent a DWARF line record object. @@ -134,6 +135,8 @@ class LLVM_ABI LVLineDebug final : public LVLine { bool equals(const LVLine *Line) const override; void printExtra(raw_ostream &OS, bool Full = true) const override; + void printDebugger(raw_ostream &OS, LVLevel Indent) const override; + void printInlineCallstack(raw_ostream &OS) const; }; // Class to represent an assembler line extracted from the text section. @@ -153,6 +156,7 @@ class LLVM_ABI LVLineAssembler final : public LVLine { bool equals(const LVLine *Line) const override; void printExtra(raw_ostream &OS, bool Full = true) const override; + void printDebugger(raw_ostream &OS, LVLevel Indent) const override; }; } // end namespace logicalview diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h index 0718e33f5645b..fc5f11817f2ac 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h @@ -157,8 +157,10 @@ class LLVM_ABI LVLocation : public LVObject { void printRaw(raw_ostream &OS, bool Full = true) const; virtual void printRawExtra(raw_ostream &OS, bool Full = true) const {} + virtual void printLocations(raw_ostream &OS) const {} void print(raw_ostream &OS, bool Full = true) const override; void printExtra(raw_ostream &OS, bool Full = true) const override; + virtual void printDebugger(raw_ostream &OS, LVLevel Indent) const {} }; class LLVM_ABI LVLocationSymbol final : public LVLocation { @@ -177,8 +179,10 @@ class LLVM_ABI LVLocationSymbol final : public LVLocation { uint64_t LocDescOffset) override; void addObject(LVSmall Opcode, ArrayRef Operands) override; + void printLocations(raw_ostream &OS) const override; void printRawExtra(raw_ostream &OS, bool Full = true) const override; void printExtra(raw_ostream &OS, bool Full = true) const override; + void printDebugger(raw_ostream &OS, LVLevel Indent) const override; }; } // end namespace logicalview diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h index 2afbb013fc62f..595bb29775d42 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h @@ -165,6 +165,7 @@ using LVPrintKindSet = std::set; enum class LVReportKind { All, // --report=all Children, // --report=children + Debugger, // --report=debugger List, // --report=list Parents, // --report=parents View // --report=view @@ -406,6 +407,7 @@ class LVOptions { // --report. REPORT_OPTION(All); REPORT_OPTION(Children); + REPORT_OPTION(Debugger); REPORT_OPTION(List); REPORT_OPTION(Parents); REPORT_OPTION(View); diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h index 371bffb2ed163..4dbb43c1099a0 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h @@ -189,6 +189,7 @@ class LLVM_ABI LVReader { return std::string(Path); } + Error printDebugger(); virtual Error printScopes(); virtual Error printMatchedElements(bool UseMatchedElements); virtual void sortScopes() {} diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h index f4f3516769938..f17afec54658e 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h @@ -325,6 +325,9 @@ class LLVM_ABI LVScope : public LVElement { // given 'Targets'. static bool equals(const LVScopes *References, const LVScopes *Targets); + // Returns true if 'Scope' is in the parent stack, false if not. + bool isChildScopeOf(const LVScope *Scope) const; + // For the given 'Scopes' returns a scope that is logically equal // to the current scope; otherwise 'nullptr'. virtual LVScope *findEqualScope(const LVScopes *Scopes) const; @@ -338,6 +341,8 @@ class LLVM_ABI LVScope : public LVElement { void printExtra(raw_ostream &OS, bool Full = true) const override; virtual void printWarnings(raw_ostream &OS, bool Full = true) const {} virtual void printMatchedElements(raw_ostream &OS, bool UseMatchedElements) {} + virtual void printDebugger(raw_ostream &OS) const {} + virtual void printInlineCallstack(raw_ostream &OS) const {} }; // Class to represent a DWARF Union/Structure/Class. @@ -635,6 +640,7 @@ class LLVM_ABI LVScopeCompileUnit final : public LVScope { void printExtra(raw_ostream &OS, bool Full = true) const override; void printWarnings(raw_ostream &OS, bool Full = true) const override; void printMatchedElements(raw_ostream &OS, bool UseMatchedElements) override; + void printDebugger(raw_ostream &OS) const override; }; // Class to represent a DWARF enumerator (DW_TAG_enumeration_type). @@ -716,6 +722,7 @@ class LLVM_ABI LVScopeFunction : public LVScope { LVScope *findEqualScope(const LVScopes *Scopes) const override; void printExtra(raw_ostream &OS, bool Full = true) const override; + void printDebugger(raw_ostream &OS) const override; }; // Class to represent a DWARF inlined function. @@ -850,6 +857,7 @@ class LLVM_ABI LVScopeRoot final : public LVScope { void printExtra(raw_ostream &OS, bool Full = true) const override; Error doPrintMatches(bool Split, raw_ostream &OS, bool UseMatchedElements) const; + Error doPrintDebugger(bool Split, raw_ostream &OS) const; }; // Class to represent a DWARF template parameter pack diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp index c3810d282abc0..180074701a1bf 100644 --- a/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp @@ -208,6 +208,31 @@ void LVLineDebug::printExtra(raw_ostream &OS, bool Full) const { OS << "\n"; } +void LVLineDebug::printInlineCallstack(raw_ostream &OS) const { + const LVScope *Scope = getParentScope(); + const LVScope *PrevScope = nullptr; + while (Scope) { + if (Scope->getIsFunction() || Scope->getIsInlinedFunction()) { + OS << "[" << Scope->getName(); + if (PrevScope && PrevScope->getIsInlinedFunction()) { + OS << ":" + << cast(PrevScope)->getCallLineNumber(); + } + OS << "]"; + PrevScope = Scope; + } + Scope = Scope->getParentScope(); + } +} + +void LVLineDebug::printDebugger(raw_ostream &OS, LVLevel Indent) const { + OS << indentAsString(Indent) << formattedKind(kind()) << " "; + printAttributes(OS); + OS << " " << getPathname() << ":" << getLineNumber() << " "; + printInlineCallstack(OS); + OS << "\n"; +} + //===----------------------------------------------------------------------===// // Assembler line extracted from the ELF .text section. //===----------------------------------------------------------------------===// @@ -220,3 +245,9 @@ void LVLineAssembler::printExtra(raw_ostream &OS, bool Full) const { OS << " " << formattedName(getName()); OS << "\n"; } + +void LVLineAssembler::printDebugger(raw_ostream &OS, LVLevel Indent) const { + OS << indentAsString(Indent) << formattedKind(kind()) << " "; + printAttributes(OS); + OS << " " << getName() << "\n"; +} diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp index 3c078d8ee74b8..ca81af45d0620 100644 --- a/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp @@ -648,6 +648,19 @@ void LVLocation::print(LVLocations *Locations, raw_ostream &OS, bool Full) { Location->print(OS, Full); } +void LVLocationSymbol::printLocations(raw_ostream &OS) const { + if (Entries) { + bool CodeViewLocation = getParentSymbol()->getHasCodeViewLocation(); + std::string Leading; + for (LVOperation *Operation : *Entries) { + OS << Leading + << (CodeViewLocation ? Operation->getOperandsCodeViewInfo() + : Operation->getOperandsDWARFInfo()); + Leading = ", "; + } + } +} + void LVLocationSymbol::printExtra(raw_ostream &OS, bool Full) const { OS << "{Location}"; if (getIsCallSite()) @@ -657,18 +670,21 @@ void LVLocationSymbol::printExtra(raw_ostream &OS, bool Full) const { // Print location entries. if (Full && Entries) { - bool CodeViewLocation = getParentSymbol()->getHasCodeViewLocation(); - std::stringstream Stream; - std::string Leading; - for (LVOperation *Operation : *Entries) { - Stream << Leading - << (CodeViewLocation ? Operation->getOperandsCodeViewInfo() - : Operation->getOperandsDWARFInfo()); - Leading = ", "; - } + std::string Str; + raw_string_ostream Stream(Str); + printLocations(Stream); printAttributes(OS, Full, "{Entry} ", const_cast(this), StringRef(Stream.str()), /*UseQuotes=*/false, /*PrintRef=*/false); } } + +void LVLocationSymbol::printDebugger(raw_ostream &OS, LVLevel Indent) const { + LVSymbol *Sym = getParentSymbol(); + OS << indentAsString(Indent) << formattedKind(Sym->kind()); + OS << " " << Sym->getName() << ": " << Sym->getType()->getName() << " : "; + printLocations(OS); + OS << " (line " << Sym->getLineNumber() << ")"; + OS << "\n"; +} diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp index af35e58ac0dd6..05d136c7c00b5 100644 --- a/llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp @@ -132,6 +132,14 @@ void LVOptions::resolveDependencies() { setPrintWarnings(); } + if (getReportDebugger()) { + // Must include at least the lines, otherwise there's nothing to print + setPrintLines(); + // Printing symbols in debugger report requires the symbol ranges + if (getPrintSymbols()) + setAttributeRange(); + } + // '--warning=all' settings. if (getWarningAll()) { setWarningCoverages(); @@ -186,6 +194,7 @@ void LVOptions::resolveDependencies() { // '--reports=all' settings. if (getReportAll()) { setReportChildren(); + setReportDebugger(); setReportList(); setReportParents(); setReportView(); @@ -202,7 +211,7 @@ void LVOptions::resolveDependencies() { setReportAnyView(); // The report will include: List or Parents or Children. - if (getReportList() || getReportAnyView()) + if (getReportList() || getReportAnyView() || getReportDebugger()) setReportExecute(); // If a view or element comparison has been requested, the following options diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp index d973a47f68732..4b820f7e0bc84 100644 --- a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp @@ -516,13 +516,23 @@ Error LVReader::doPrint() { if (options().getReportParents() || options().getReportView()) if (Error Err = printScopes()) return Err; - + // Requested debugger report. + if (options().getReportDebugger()) + if (Error Err = printDebugger()) + return Err; return Error::success(); } return printScopes(); } +Error LVReader::printDebugger() { + if (Error Err = createSplitFolder()) + return Err; + + return Root->doPrintDebugger(OutputSplit, outs()); +} + Error LVReader::printScopes() { if (bool DoPrint = (options().getPrintExecute() || options().getComparePrint())) { diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp index e03932622b259..dcb53208eb69a 100644 --- a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/LogicalView/Core/LVScope.h" +#include "llvm/ADT/SetVector.h" #include "llvm/DebugInfo/LogicalView/Core/LVCompare.h" #include "llvm/DebugInfo/LogicalView/Core/LVLine.h" #include "llvm/DebugInfo/LogicalView/Core/LVLocation.h" @@ -971,6 +972,16 @@ bool LVScope::equals(const LVScopes *References, const LVScopes *Targets) { return false; } +bool LVScope::isChildScopeOf(const LVScope *Scope) const { + const LVScope *Self = this; + while (Self) { + Self = Self->getParentScope(); + if (Self == Scope) + return true; + } + return false; +} + void LVScope::report(LVComparePass Pass) { getComparator().printItem(this, Pass); getComparator().push(this); @@ -1698,6 +1709,13 @@ void LVScopeCompileUnit::printMatchedElements(raw_ostream &OS, } } +void LVScopeCompileUnit::printDebugger(raw_ostream &OS) const { + outs() << formattedKind(kind()) << " " << getName() << "\n"; + for (const LVScope *ChildScope : *getScopes()) { + ChildScope->printDebugger(OS); + } +} + void LVScopeCompileUnit::print(raw_ostream &OS, bool Full) const { // Reset counters for printed and found elements. const_cast(this)->Found.reset(); @@ -1903,6 +1921,94 @@ void LVScopeFunction::printExtra(raw_ostream &OS, bool Full) const { } } +void LVScopeFunction::printDebugger(raw_ostream &OS) const { + const LVLines *Lines = getLines(); + // If there's no lines, this function has no body. + if (!Lines) + return; + + OS << formattedKind(kind()) << " " << getName() << "\n"; + + std::vector AllLines; + std::unordered_map> LifetimeBegins; + std::unordered_map> + LifetimeEndsExclusive; + + // Collect all child scope lines and symbols + std::vector Worklist = {this}; + for (unsigned i = 0; i < Worklist.size(); i++) { + const LVScope *Scope = Worklist[i]; + if (Scope->scopeCount()) { + for (const LVScope *ChildScope : *Scope->getScopes()) + Worklist.push_back(ChildScope); + } + if (Scope->lineCount()) { + for (const LVLine *Line : *Scope->getLines()) { + AllLines.push_back(Line); + } + } + if (Scope->symbolCount()) { + for (const LVSymbol *Symbol : *Scope->getSymbols()) { + LVLocations SymbolLocations; + Symbol->getLocations(SymbolLocations); + if (SymbolLocations.empty()) + continue; + + for (const LVLocation *Loc : SymbolLocations) { + if (Loc->getIsGapEntry()) + continue; + + LVAddress Begin = Loc->getLowerAddress(); + LVAddress End = Loc->getUpperAddress(); + LifetimeBegins[Begin].push_back(Loc); + LifetimeEndsExclusive[End].push_back(Loc); + } + } + } + } + + // Sort all lines by their address. + std::sort(AllLines.begin(), AllLines.end(), + [](const LVLine *a, const LVLine *b) -> bool { + if (a->getAddress() != b->getAddress()) + return a->getAddress() < b->getAddress(); + if (a->getIsLineDebug() != b->getIsLineDebug()) + return a->getIsLineDebug(); + return a->getID() < b->getID(); + }); + + // Print everything out + const bool IncludeVars = options().getPrintSymbols(); + const bool IncludeCode = options().getPrintInstructions(); + SetVector + LiveSymbols; // This needs to be ordered since we're iterating over it. + for (const LVLine *Line : AllLines) { + // Update live list: Add lives + for (auto Loc : LifetimeBegins[Line->getAddress()]) + LiveSymbols.insert(Loc); + // Update live list: remove dead + for (auto Loc : LifetimeEndsExclusive[Line->getAddress()]) + LiveSymbols.remove(Loc); + + if (Line->getIsNewStatement() && Line->getIsLineDebug() && + Line->getLineNumber() != 0) { + Line->printDebugger(OS, 1); + if (IncludeVars) { + for (auto SymLoc : LiveSymbols) { + const LVSymbol *Sym = SymLoc->getParentSymbol(); + auto SymScope = Sym->getParentScope(); + auto LineScope = Line->getParentScope(); + if (SymScope != LineScope && !LineScope->isChildScopeOf(SymScope)) + continue; + SymLoc->printDebugger(OS, 2); + } + } + } else if (IncludeCode && Line->getIsLineAssembler()) { + Line->printDebugger(OS, 1); + } + } +} + //===----------------------------------------------------------------------===// // DWARF inlined function (DW_TAG_inlined_function). //===----------------------------------------------------------------------===// @@ -2119,6 +2225,28 @@ Error LVScopeRoot::doPrintMatches(bool Split, raw_ostream &OS, return Error::success(); } +Error LVScopeRoot::doPrintDebugger(bool Split, raw_ostream &OS) const { + OS << "\nLogical View:\n"; + static raw_ostream *StreamSplit = &OS; + for (LVScope *Scope : *Scopes) { + if (Split) { + std::string ScopeName(Scope->getName()); + if (std::error_code EC = + getReaderSplitContext().open(ScopeName, ".txt", OS)) + return createStringError(EC, "Unable to create split output file %s", + ScopeName.c_str()); + StreamSplit = static_cast(&getReaderSplitContext().os()); + } + *StreamSplit << formattedKind(kind()) << " " << getName() << "\n"; + Scope->printDebugger(*StreamSplit); + if (Split) { + getReaderSplitContext().close(); + StreamSplit = &getReader().outputStream(); + } + } + return Error::success(); +} + //===----------------------------------------------------------------------===// // DWARF template parameter pack (DW_TAG_GNU_template_parameter_pack). //===----------------------------------------------------------------------===// diff --git a/llvm/test/CodeGen/AMDGPU/amdgpu-debuginfo-check.ll b/llvm/test/CodeGen/AMDGPU/amdgpu-debuginfo-check.ll new file mode 100644 index 0000000000000..24df0bc76853b --- /dev/null +++ b/llvm/test/CodeGen/AMDGPU/amdgpu-debuginfo-check.ll @@ -0,0 +1,112 @@ +; RUN: llc %s -o %t.o -mcpu=gfx1030 -filetype=obj -O0 +; RUN: llvm-debuginfo-analyzer --report=debugger --print=symbols --attribute=level,offset %t.o | FileCheck %s + +; The test compiles this module using the AMDGPU backend under `-O0`, +; and makes sure `llvm-debuginfo-analyzer --report=debugger` works for it. + +; CHECK: {File} +; CHECK: {CompileUnit} basic_var.hlsl +; CHECK: {Function} main +; CHECK: {Line} [0x{{[0-9a-f]+}}][003] basic_var.hlsl:7 [main] +; CHECK: {Line} [0x{{[0-9a-f]+}}][003] basic_var.hlsl:11 [main] +; CHECK: {Parameter} dtid: uint3 : reg{{.+}}, piece 4 +; CHECK: {Line} [0x{{[0-9a-f]+}}][003] basic_var.hlsl:17 [main] +; CHECK: {Parameter} dtid: uint3 : reg{{.+}}, piece 4 +; CHECK: {Line} [0x{{[0-9a-f]+}}][003] basic_var.hlsl:11 [main] +; CHECK: {Parameter} dtid: uint3 : reg{{.+}}, piece 4 +; CHECK: {Line} [0x{{[0-9a-f]+}}][003] basic_var.hlsl:14 [main] +; CHECK-DAG: {Parameter} dtid: uint3 : reg{{.+}}, piece 4 +; CHECK: {Line} [0x{{[0-9a-f]+}}][003] basic_var.hlsl:17 [main] +; CHECK-DAG: {Parameter} dtid: uint3 : reg{{.+}}, piece 4 +; CHECK-DAG: {Variable} my_var2: float : reg{{.+}} +; CHECK: {Line} [0x{{[0-9a-f]+}}][003] basic_var.hlsl:19 [main] +; CHECK-DAG: {Parameter} dtid: uint3 : reg{{.+}}, piece 4 +; CHECK-DAG: {Variable} my_var2: float : reg{{.+}} + +source_filename = "module" +target triple = "amdgcn-amd-amdpal" + +%dx.types.ResRet.f32 = type { float, float, float, float, i32 } + +; Function Attrs: memory(readwrite) +define dllexport amdgpu_cs void @_amdgpu_cs_main(i32 inreg noundef %globalTable, i32 inreg noundef %userdata4, <3 x i32> inreg noundef %WorkgroupId, i32 inreg noundef %MultiDispatchInfo, <3 x i32> noundef %LocalInvocationId) #0 !dbg !14 { + %LocalInvocationId.i0 = extractelement <3 x i32> %LocalInvocationId, i64 0, !dbg !28 + %WorkgroupId.i0 = extractelement <3 x i32> %WorkgroupId, i64 0, !dbg !28 + %1 = call i64 @llvm.amdgcn.s.getpc(), !dbg !28 + %2 = shl i32 %WorkgroupId.i0, 6, !dbg !28 + %3 = add i32 %LocalInvocationId.i0, %2, !dbg !28 + #dbg_value(i32 %3, !29, !DIExpression(DW_OP_LLVM_fragment, 0, 32), !28) + %4 = and i64 %1, -4294967296, !dbg !30 + %5 = zext i32 %userdata4 to i64, !dbg !30 + %6 = or disjoint i64 %4, %5, !dbg !30 + %7 = inttoptr i64 %6 to ptr addrspace(4), !dbg !30 + call void @llvm.assume(i1 true) [ "align"(ptr addrspace(4) %7, i32 4), "dereferenceable"(ptr addrspace(4) %7, i32 -1) ], !dbg !30 + %8 = load <4 x i32>, ptr addrspace(4) %7, align 4, !dbg !30, !invariant.load !2 + %9 = call float @llvm.amdgcn.struct.buffer.load.format.f32(<4 x i32> %8, i32 %3, i32 0, i32 0, i32 0), !dbg !30 + #dbg_value(%dx.types.ResRet.f32 poison, !31, !DIExpression(), !32) + %10 = fmul reassoc arcp contract afn float %9, 2.000000e+00, !dbg !33 + #dbg_value(float %10, !34, !DIExpression(), !35) + call void @llvm.assume(i1 true) [ "align"(ptr addrspace(4) %7, i32 4), "dereferenceable"(ptr addrspace(4) %7, i32 -1) ], !dbg !36 + %11 = getelementptr i8, ptr addrspace(4) %7, i64 32, !dbg !36 + %.upto01 = insertelement <4 x float> poison, float %10, i64 0, !dbg !36 + %12 = shufflevector <4 x float> %.upto01, <4 x float> poison, <4 x i32> zeroinitializer, !dbg !36 + %13 = load <4 x i32>, ptr addrspace(4) %11, align 4, !dbg !36, !invariant.load !2 + call void @llvm.amdgcn.struct.buffer.store.format.v4f32(<4 x float> %12, <4 x i32> %13, i32 %3, i32 0, i32 0, i32 0), !dbg !36 + ret void, !dbg !37 +} + +declare noundef i64 @llvm.amdgcn.s.getpc() #1 + +declare void @llvm.assume(i1 noundef) #2 + +declare void @llvm.amdgcn.struct.buffer.store.format.v4f32(<4 x float>, <4 x i32>, i32, i32, i32, i32 immarg) #3 + +declare float @llvm.amdgcn.struct.buffer.load.format.f32(<4 x i32>, i32, i32, i32, i32 immarg) #4 + +attributes #0 = { memory(readwrite) } +attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } +attributes #2 = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) } +attributes #3 = { nocallback nofree nosync nounwind willreturn memory(write) } +attributes #4 = { nocallback nofree nosync nounwind willreturn memory(read) } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!12, !13} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "dxcoob 1.7.2308.16 (52da17e29)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3) +!1 = !DIFile(filename: "tests\\basic_var.hlsl", directory: "") +!2 = !{} +!3 = !{!4, !10} +!4 = distinct !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) +!5 = !DIGlobalVariable(name: "u0", linkageName: "\01?u0@@3V?$RWBuffer@M@@A", scope: !0, file: !1, line: 2, type: !6, isLocal: false, isDefinition: true) +!6 = !DICompositeType(tag: DW_TAG_class_type, name: "RWBuffer", file: !1, line: 2, size: 32, align: 32, elements: !2, templateParams: !7) +!7 = !{!8} +!8 = !DITemplateTypeParameter(name: "element", type: !9) +!9 = !DIBasicType(name: "float", size: 32, align: 32, encoding: DW_ATE_float) +!10 = distinct !DIGlobalVariableExpression(var: !11, expr: !DIExpression()) +!11 = !DIGlobalVariable(name: "u1", linkageName: "\01?u1@@3V?$RWBuffer@M@@A", scope: !0, file: !1, line: 3, type: !6, isLocal: false, isDefinition: true) +!12 = !{i32 2, !"Dwarf Version", i32 5} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 7, type: !15, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0) +!15 = !DISubroutineType(types: !16) +!16 = !{null, !17} +!17 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint3", file: !1, baseType: !18) +!18 = !DICompositeType(tag: DW_TAG_class_type, name: "vector", file: !1, size: 96, align: 32, elements: !19, templateParams: !24) +!19 = !{!20, !22, !23} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !18, file: !1, baseType: !21, size: 32, align: 32, flags: DIFlagPublic) +!21 = !DIBasicType(name: "unsigned int", size: 32, align: 32, encoding: DW_ATE_unsigned) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !18, file: !1, baseType: !21, size: 32, align: 32, offset: 32, flags: DIFlagPublic) +!23 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !18, file: !1, baseType: !21, size: 32, align: 32, offset: 64, flags: DIFlagPublic) +!24 = !{!25, !26} +!25 = !DITemplateTypeParameter(name: "element", type: !21) +!26 = !DITemplateValueParameter(name: "element_count", type: !27, value: i32 3) +!27 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!28 = !DILocation(line: 7, column: 17, scope: !14) +!29 = !DILocalVariable(name: "dtid", arg: 1, scope: !14, file: !1, line: 7, type: !17) +!30 = !DILocation(line: 11, column: 18, scope: !14) +!31 = !DILocalVariable(name: "my_var", scope: !14, file: !1, line: 11, type: !9) +!32 = !DILocation(line: 11, column: 9, scope: !14) +!33 = !DILocation(line: 14, column: 26, scope: !14) +!34 = !DILocalVariable(name: "my_var2", scope: !14, file: !1, line: 14, type: !9) +!35 = !DILocation(line: 14, column: 9, scope: !14) +!36 = !DILocation(line: 17, column: 14, scope: !14) +!37 = !DILocation(line: 19, column: 1, scope: !14) diff --git a/llvm/tools/llvm-debuginfo-analyzer/Options.cpp b/llvm/tools/llvm-debuginfo-analyzer/Options.cpp index 3d1373896f234..417a5c8537992 100644 --- a/llvm/tools/llvm-debuginfo-analyzer/Options.cpp +++ b/llvm/tools/llvm-debuginfo-analyzer/Options.cpp @@ -254,6 +254,10 @@ cl::list cmdline::ReportOptions( clEnumValN(LVReportKind::Children, "children", "Selected elements are displayed in a tree view " "(Include children)"), + clEnumValN( + LVReportKind::Debugger, "debugger", + "Selected elements are displayed in a simulated debugger view " + "(Include parents and children."), clEnumValN(LVReportKind::List, "list", "Selected elements are displayed in a tabular format."), clEnumValN(LVReportKind::Parents, "parents",