[llvm] [llvm-debuginfo-analyzer] Remove `LVScope::Children` container (PR #144750)
Javier Lopez-Gomez via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 18 04:23:07 PDT 2025
https://github.com/jalopezg-git updated https://github.com/llvm/llvm-project/pull/144750
>From 234845626e894eaf10f69d83bfc018bd96ed2fbd Mon Sep 17 00:00:00 2001
From: Javier Lopez-Gomez <javier.lopez.gomez at proton.me>
Date: Thu, 18 Sep 2025 13:22:48 +0200
Subject: [PATCH] [llvm-debuginfo-analyzer] Remove `LVScope::Children`
container
Remove the `LVScope::Children` container and use `llvm::concat()`
instead to return a view over the types, symbols, and sub-scopes
contained in a given `LVScope`.
---
.../llvm/DebugInfo/LogicalView/Core/LVScope.h | 27 ++++---
.../DebugInfo/LogicalView/Core/LVScope.cpp | 76 +++++++++----------
.../01-dwarf-compare-logical-elements.test | 2 +-
.../pr-57040-incorrect-function-compare.test | 2 +-
.../01-wasm-compare-logical-elements.test | 2 +-
.../DebugInfo/LogicalView/DWARFReaderTest.cpp | 12 ++-
6 files changed, 60 insertions(+), 61 deletions(-)
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
index a453923d032e4..3c0f8cc5abba8 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
@@ -14,6 +14,7 @@
#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSCOPE_H
#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSCOPE_H
+#include "llvm/ADT/STLExtras.h"
#include "llvm/DebugInfo/LogicalView/Core/LVElement.h"
#include "llvm/DebugInfo/LogicalView/Core/LVLocation.h"
#include "llvm/DebugInfo/LogicalView/Core/LVSort.h"
@@ -94,6 +95,11 @@ class LLVM_ABI LVScope : public LVElement {
LVProperties<LVScopeKind> Kinds;
LVProperties<Property> Properties;
static LVScopeDispatch Dispatch;
+ // Empty containers used in `getChildren()` in case there is no Types,
+ // Symbols, or Scopes.
+ static const LVTypes EmptyTypes;
+ static const LVSymbols EmptySymbols;
+ static const LVScopes EmptyScopes;
// Size in bits if this scope represents also a compound type.
uint32_t BitSize = 0;
@@ -128,14 +134,6 @@ class LLVM_ABI LVScope : public LVElement {
std::unique_ptr<LVLines> Lines;
std::unique_ptr<LVLocations> Ranges;
- // Vector of elements (types, scopes and symbols).
- // It is the union of (*Types, *Symbols and *Scopes) to be used for
- // the following reasons:
- // - Preserve the order the logical elements are read in.
- // - To have a single container with all the logical elements, when
- // the traversal does not require any specific element kind.
- std::unique_ptr<LVElements> Children;
-
// Resolve the template parameters/arguments relationship.
void resolveTemplate();
void printEncodedArgs(raw_ostream &OS, bool Full) const;
@@ -213,7 +211,17 @@ class LLVM_ABI LVScope : public LVElement {
const LVScopes *getScopes() const { return Scopes.get(); }
const LVSymbols *getSymbols() const { return Symbols.get(); }
const LVTypes *getTypes() const { return Types.get(); }
- const LVElements *getChildren() const { return Children.get(); }
+ // Return view over union of child Types, Symbols, and Scopes.
+ auto getChildren() const {
+ return llvm::concat<LVElement *const>(Scopes ? *Scopes : EmptyScopes,
+ Types ? *Types : EmptyTypes,
+ Symbols ? *Symbols : EmptySymbols);
+ }
+ // Return view over union of child Types, Symbols, and Scopes that is sorted
+ // using `SortFunction`. This requires copy + sort; if order is not important,
+ // use `getChildren()` instead. See also: `LVOptions::setSortMode()`.
+ LVElements getSortedChildren(
+ LVSortFunction SortFunction = llvm::logicalview::getSortFunction()) const;
void addElement(LVElement *Element);
void addElement(LVLine *Line);
@@ -222,7 +230,6 @@ class LLVM_ABI LVScope : public LVElement {
void addElement(LVType *Type);
void addObject(LVLocation *Location);
void addObject(LVAddress LowerAddress, LVAddress UpperAddress);
- void addToChildren(LVElement *Element);
// Add the missing elements from the given 'Reference', which is the
// scope associated with any DW_AT_specification, DW_AT_abstract_origin.
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
index 64f1bfc015380..e03932622b259 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
@@ -107,10 +107,16 @@ LVScopeDispatch LVScope::Dispatch = {
{LVScopeKind::IsTryBlock, &LVScope::getIsTryBlock},
{LVScopeKind::IsUnion, &LVScope::getIsUnion}};
-void LVScope::addToChildren(LVElement *Element) {
- if (!Children)
- Children = std::make_unique<LVElements>();
- Children->push_back(Element);
+const LVTypes LVScope::EmptyTypes{};
+const LVSymbols LVScope::EmptySymbols{};
+const LVScopes LVScope::EmptyScopes{};
+
+LVElements LVScope::getSortedChildren(LVSortFunction SortFunction) const {
+ const auto UnsortedChildren = getChildren();
+ LVElements Elements{UnsortedChildren.begin(), UnsortedChildren.end()};
+ if (SortFunction)
+ llvm::stable_sort(Elements, SortFunction);
+ return Elements;
}
void LVScope::addElement(LVElement *Element) {
@@ -175,7 +181,6 @@ void LVScope::addElement(LVScope *Scope) {
// Add it to parent.
Scopes->push_back(Scope);
- addToChildren(Scope);
Scope->setParent(this);
// Notify the reader about the new element being added.
@@ -202,7 +207,6 @@ void LVScope::addElement(LVSymbol *Symbol) {
// Add it to parent.
Symbols->push_back(Symbol);
- addToChildren(Symbol);
Symbol->setParent(this);
// Notify the reader about the new element being added.
@@ -229,7 +233,6 @@ void LVScope::addElement(LVType *Type) {
// Add it to parent.
Types->push_back(Type);
- addToChildren(Type);
Type->setParent(this);
// Notify the reader about the new element being added.
@@ -277,15 +280,12 @@ bool LVScope::removeElement(LVElement *Element) {
if (Element->getIsLine())
return RemoveElement(Lines);
- if (RemoveElement(Children)) {
- if (Element->getIsSymbol())
- return RemoveElement(Symbols);
- if (Element->getIsType())
- return RemoveElement(Types);
- if (Element->getIsScope())
- return RemoveElement(Scopes);
- llvm_unreachable("Invalid element.");
- }
+ if (Element->getIsSymbol())
+ return RemoveElement(Symbols);
+ if (Element->getIsType())
+ return RemoveElement(Types);
+ if (Element->getIsScope())
+ return RemoveElement(Scopes);
return false;
}
@@ -356,9 +356,8 @@ void LVScope::updateLevel(LVScope *Parent, bool Moved) {
setLevel(Parent->getLevel() + 1);
// Update the children.
- if (Children)
- for (LVElement *Element : *Children)
- Element->updateLevel(this, Moved);
+ for (LVElement *Element : getChildren())
+ Element->updateLevel(this, Moved);
// Update any lines.
if (Lines)
@@ -374,13 +373,12 @@ void LVScope::resolve() {
LVElement::resolve();
// Resolve the children.
- if (Children)
- for (LVElement *Element : *Children) {
- if (getIsGlobalReference())
- // If the scope is a global reference, mark all its children as well.
- Element->setIsGlobalReference();
- Element->resolve();
- }
+ for (LVElement *Element : getChildren()) {
+ if (getIsGlobalReference())
+ // If the scope is a global reference, mark all its children as well.
+ Element->setIsGlobalReference();
+ Element->resolve();
+ }
}
void LVScope::resolveName() {
@@ -633,14 +631,13 @@ Error LVScope::doPrint(bool Split, bool Match, bool Print, raw_ostream &OS,
options().getPrintFormatting() &&
getLevel() < options().getOutputLevel()) {
// Print the children.
- if (Children)
- for (const LVElement *Element : *Children) {
- if (Match && !Element->getHasPattern())
- continue;
- if (Error Err =
- Element->doPrint(Split, Match, Print, *StreamSplit, Full))
- return Err;
- }
+ for (const LVElement *Element : getSortedChildren()) {
+ if (Match && !Element->getHasPattern())
+ continue;
+ if (Error Err =
+ Element->doPrint(Split, Match, Print, *StreamSplit, Full))
+ return Err;
+ }
// Print the line records.
if (Lines)
@@ -692,7 +689,6 @@ void LVScope::sort() {
Traverse(Parent->Symbols, SortFunction);
Traverse(Parent->Scopes, SortFunction);
Traverse(Parent->Ranges, compareRange);
- Traverse(Parent->Children, SortFunction);
if (Parent->Scopes)
for (LVScope *Scope : *Parent->Scopes)
@@ -978,9 +974,8 @@ bool LVScope::equals(const LVScopes *References, const LVScopes *Targets) {
void LVScope::report(LVComparePass Pass) {
getComparator().printItem(this, Pass);
getComparator().push(this);
- if (Children)
- for (LVElement *Element : *Children)
- Element->report(Pass);
+ for (LVElement *Element : getSortedChildren())
+ Element->report(Pass);
if (Lines)
for (LVLine *Line : *Lines)
@@ -1656,9 +1651,8 @@ void LVScopeCompileUnit::printMatchedElements(raw_ostream &OS,
// Print the view for the matched scopes.
for (const LVScope *Scope : MatchedScopes) {
Scope->print(OS);
- if (const LVElements *Elements = Scope->getChildren())
- for (LVElement *Element : *Elements)
- Element->print(OS);
+ for (LVElement *Element : Scope->getSortedChildren())
+ Element->print(OS);
}
}
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-compare-logical-elements.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-compare-logical-elements.test
index a076887140c28..1b790eeb3b691 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-compare-logical-elements.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-compare-logical-elements.test
@@ -35,8 +35,8 @@
; ONE-NEXT: [002] 1 {TypeAlias} 'INTPTR' -> '* const int'
; ONE-NEXT: [002] 2 {Function} extern not_inlined 'foo' -> 'int'
; ONE-NEXT: [003] {Block}
-; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER'
; ONE-NEXT: +[004] 4 {TypeAlias} 'INTEGER' -> 'int'
+; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER'
; ONE-NEXT: [003] 2 {Parameter} 'ParamBool' -> 'bool'
; ONE-NEXT: [003] 2 {Parameter} 'ParamPtr' -> 'INTPTR'
; ONE-NEXT: [003] 2 {Parameter} 'ParamUnsigned' -> 'unsigned int'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-incorrect-function-compare.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-incorrect-function-compare.test
index 278d4f4850f5f..78604d9164c0f 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-incorrect-function-compare.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-incorrect-function-compare.test
@@ -55,8 +55,8 @@
; ONE-NEXT: [002] 1 {TypeAlias} 'INTPTR' -> '* const int'
; ONE-NEXT: [002] 2 {Function} extern not_inlined 'foo' -> 'int'
; ONE-NEXT: [003] {Block}
-; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER'
; ONE-NEXT: +[004] 4 {TypeAlias} 'INTEGER' -> 'int'
+; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER'
; ONE-NEXT: [003] 2 {Parameter} 'ParamBool' -> 'bool'
; ONE-NEXT: [003] 2 {Parameter} 'ParamPtr' -> 'INTPTR'
; ONE-NEXT: [003] 2 {Parameter} 'ParamUnsigned' -> 'unsigned int'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-compare-logical-elements.test b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-compare-logical-elements.test
index f52c9c7cc7164..98fc47e3d3c80 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-compare-logical-elements.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-compare-logical-elements.test
@@ -38,8 +38,8 @@
; ONE-NEXT: [002] 1 {TypeAlias} 'INTPTR' -> '* const int'
; ONE-NEXT: [002] 2 {Function} extern not_inlined 'foo' -> 'int'
; ONE-NEXT: [003] {Block}
-; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER'
; ONE-NEXT: +[004] 4 {TypeAlias} 'INTEGER' -> 'int'
+; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER'
; ONE-NEXT: [003] 2 {Parameter} 'ParamBool' -> 'bool'
; ONE-NEXT: [003] 2 {Parameter} 'ParamPtr' -> 'INTPTR'
; ONE-NEXT: [003] 2 {Parameter} 'ParamUnsigned' -> 'unsigned int'
diff --git a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
index 78dc8502e9676..003d454b12a38 100644
--- a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
+++ b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
@@ -163,13 +163,12 @@ void checkUnspecifiedParameters(LVReader *Reader) {
LVPublicNames::const_iterator IterNames = PublicNames.cbegin();
LVScope *Function = (*IterNames).first;
EXPECT_EQ(Function->getName(), "foo_printf");
- const LVElements *Elements = Function->getChildren();
- ASSERT_NE(Elements, nullptr);
+ const auto Elements = Function->getChildren();
// foo_printf is a variadic function whose prototype is
// `int foo_printf(const char *, ...)`, where the '...' is represented by a
// DW_TAG_unspecified_parameters, i.e. we expect to find at least one child
// for which getIsUnspecified() returns true.
- EXPECT_TRUE(llvm::any_of(*Elements, [](const LVElement *elt) {
+ EXPECT_TRUE(llvm::any_of(Elements, [](const LVElement *elt) {
return elt->getIsSymbol() &&
static_cast<const LVSymbol *>(elt)->getIsUnspecified();
}));
@@ -183,10 +182,9 @@ void checkScopeModule(LVReader *Reader) {
EXPECT_EQ(Root->getFileFormatName(), "Mach-O 64-bit x86-64");
EXPECT_EQ(Root->getName(), DwarfClangModule);
- ASSERT_NE(CompileUnit->getChildren(), nullptr);
- LVElement *FirstChild = *(CompileUnit->getChildren()->begin());
- EXPECT_EQ(FirstChild->getIsScope(), 1);
- LVScopeModule *Module = static_cast<LVScopeModule *>(FirstChild);
+ ASSERT_NE(CompileUnit->getScopes(), nullptr);
+ LVElement *FirstScope = *(CompileUnit->getScopes()->begin());
+ LVScopeModule *Module = static_cast<LVScopeModule *>(FirstScope);
EXPECT_EQ(Module->getIsModule(), 1);
EXPECT_EQ(Module->getName(), "DebugModule");
}
More information about the llvm-commits
mailing list