[llvm] [llvm-debuginfo-analyzer] Remove `LVScope::Children` container (PR #144750)
Javier Lopez-Gomez via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 20 08:09:34 PDT 2025
https://github.com/jalopezg-git updated https://github.com/llvm/llvm-project/pull/144750
>From 6af2cf5c65ede8573ee5a1ad275b220e4e01774d Mon Sep 17 00:00:00 2001
From: Javier Lopez-Gomez <javier.lopez.gomez at proton.me>
Date: Fri, 20 Jun 2025 17:09:11 +0200
Subject: [PATCH 1/2] [ADT] Fix llvm::concat_iterator for `ValueT ==
common_base_class *`
Fix llvm::concat_iterator for the case of `ValueT` being a pointer
to a common base class to which the result of dereferencing any
iterator in `ItersT` can be casted to.
---
llvm/include/llvm/ADT/STLExtras.h | 22 +++++++++++++++-------
llvm/unittests/ADT/STLExtrasTest.cpp | 14 ++++++++++++++
2 files changed, 29 insertions(+), 7 deletions(-)
diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h
index eea06cfb99ba2..31804b4c13d08 100644
--- a/llvm/include/llvm/ADT/STLExtras.h
+++ b/llvm/include/llvm/ADT/STLExtras.h
@@ -1032,13 +1032,17 @@ class concat_iterator
static constexpr bool ReturnsByValue =
!(std::is_reference_v<decltype(*std::declval<IterTs>())> && ...);
+ static constexpr bool ReturnsConvertiblePointer =
+ std::is_pointer_v<ValueT> &&
+ (std::is_convertible_v<decltype(*std::declval<IterTs>()), ValueT> && ...);
using reference_type =
- typename std::conditional_t<ReturnsByValue, ValueT, ValueT &>;
+ typename std::conditional_t<ReturnsByValue || ReturnsConvertiblePointer,
+ ValueT, ValueT &>;
- using handle_type =
- typename std::conditional_t<ReturnsByValue, std::optional<ValueT>,
- ValueT *>;
+ using handle_type = typename std::conditional_t<
+ ReturnsConvertiblePointer, ValueT,
+ std::conditional_t<ReturnsByValue, std::optional<ValueT>, ValueT *>>;
/// We store both the current and end iterators for each concatenated
/// sequence in a tuple of pairs.
@@ -1088,7 +1092,7 @@ class concat_iterator
if (Begin == End)
return {};
- if constexpr (ReturnsByValue)
+ if constexpr (ReturnsByValue || ReturnsConvertiblePointer)
return *Begin;
else
return &*Begin;
@@ -1105,8 +1109,12 @@ class concat_iterator
// Loop over them, and return the first result we find.
for (auto &GetHelperFn : GetHelperFns)
- if (auto P = (this->*GetHelperFn)())
- return *P;
+ if (auto P = (this->*GetHelperFn)()) {
+ if constexpr (ReturnsConvertiblePointer)
+ return P;
+ else
+ return *P;
+ }
llvm_unreachable("Attempted to get a pointer from an end concat iterator!");
}
diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp
index 286cfa745fd14..7e9b6f19a3d32 100644
--- a/llvm/unittests/ADT/STLExtrasTest.cpp
+++ b/llvm/unittests/ADT/STLExtrasTest.cpp
@@ -398,6 +398,8 @@ struct some_struct {
std::string swap_val;
};
+struct derives_from_some_struct : some_struct {};
+
std::vector<int>::const_iterator begin(const some_struct &s) {
return s.data.begin();
}
@@ -532,6 +534,18 @@ TEST(STLExtrasTest, ConcatRangeADL) {
EXPECT_THAT(concat<const int>(S0, S1), ElementsAre(1, 2, 3, 4));
}
+TEST(STLExtrasTest, ConcatRangePtrToDerivedClass) {
+ some_namespace::some_struct S0{};
+ some_namespace::derives_from_some_struct S1{};
+ SmallVector<some_namespace::some_struct *> V0{&S0};
+ SmallVector<some_namespace::derives_from_some_struct *> V1{&S1, &S1};
+
+ // Use concat over ranges of pointers to different (but related) types.
+ EXPECT_THAT(concat<some_namespace::some_struct *>(V0, V1),
+ ElementsAre(&S0, static_cast<some_namespace::some_struct *>(&S1),
+ static_cast<some_namespace::some_struct *>(&S1)));
+}
+
TEST(STLExtrasTest, MakeFirstSecondRangeADL) {
// Make sure that we use the `begin`/`end` functions from `some_namespace`,
// using ADL.
>From 5a31ab893c8b8efb02a4b72c45430513524b62b3 Mon Sep 17 00:00:00 2001
From: Javier Lopez-Gomez <javier.lopez.gomez at proton.me>
Date: Fri, 20 Jun 2025 17:09:11 +0200
Subject: [PATCH 2/2] [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 | 21 ++++----
.../DebugInfo/LogicalView/Core/LVScope.cpp | 49 ++++++++-----------
.../DebugInfo/LogicalView/DWARFReaderTest.cpp | 12 ++---
3 files changed, 37 insertions(+), 45 deletions(-)
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
index a453923d032e4..7f02654daeece 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,11 @@ 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(); }
+ auto getChildren() const {
+ return llvm::concat<LVElement *const>(Types ? *Types : EmptyTypes,
+ Symbols ? *Symbols : EmptySymbols,
+ Scopes ? *Scopes : EmptyScopes);
+ }
void addElement(LVElement *Element);
void addElement(LVLine *Line);
@@ -222,7 +224,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 55880fab5e88e..70422555ea27e 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
@@ -107,11 +107,9 @@ 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{};
void LVScope::addElement(LVElement *Element) {
assert(Element && "Invalid element.");
@@ -175,7 +173,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 +199,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 +225,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 +272,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,8 +348,8 @@ void LVScope::updateLevel(LVScope *Parent, bool Moved) {
setLevel(Parent->getLevel() + 1);
// Update the children.
- if (Children)
- for (LVElement *Element : *Children)
+ if (auto Elements = getChildren(); Elements.begin() != Elements.end())
+ for (LVElement *Element : Elements)
Element->updateLevel(this, Moved);
// Update any lines.
@@ -374,8 +366,8 @@ void LVScope::resolve() {
LVElement::resolve();
// Resolve the children.
- if (Children)
- for (LVElement *Element : *Children) {
+ if (auto Elements = getChildren(); Elements.begin() != Elements.end())
+ for (LVElement *Element : Elements) {
if (getIsGlobalReference())
// If the scope is a global reference, mark all its children as well.
Element->setIsGlobalReference();
@@ -633,8 +625,9 @@ 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 (const auto Elements = getChildren();
+ Elements.begin() != Elements.end())
+ for (const LVElement *Element : Elements) {
if (Match && !Element->getHasPattern())
continue;
if (Error Err =
@@ -692,7 +685,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,8 +970,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)
+ if (auto Elements = getChildren(); Elements.begin() != Elements.end())
+ for (LVElement *Element : Elements)
Element->report(Pass);
if (Lines)
@@ -1656,8 +1648,9 @@ 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)
+ if (const auto Elements = Scope->getChildren();
+ Elements.begin() != Elements.end())
+ for (LVElement *Element : Elements)
Element->print(OS);
}
}
diff --git a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
index 544c39a3c7b2e..ba6df7489b750 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