Skip to content

Commit ca9fbb5

Browse files
authored
[llvm-debuginfo-analyzer] Remove LVScope::Children container (#144750)
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`. Fixes #69160.
1 parent d995c41 commit ca9fbb5

File tree

9 files changed

+157
-91
lines changed

9 files changed

+157
-91
lines changed

llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ using LVScopes = SmallVector<LVScope *, 8>;
8282
using LVSymbols = SmallVector<LVSymbol *, 8>;
8383
using LVTypes = SmallVector<LVType *, 8>;
8484

85+
using LVElementsView = detail::concat_range<LVElement *const, const LVScopes &,
86+
const LVTypes &, const LVSymbols &>;
8587
using LVOffsets = SmallVector<LVOffset, 8>;
8688

8789
// The following DWARF documents detail the 'tombstone' concept:

llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSCOPE_H
1515
#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSCOPE_H
1616

17+
#include "llvm/ADT/STLExtras.h"
1718
#include "llvm/DebugInfo/LogicalView/Core/LVElement.h"
1819
#include "llvm/DebugInfo/LogicalView/Core/LVLocation.h"
1920
#include "llvm/DebugInfo/LogicalView/Core/LVSort.h"
@@ -94,6 +95,11 @@ class LLVM_ABI LVScope : public LVElement {
9495
LVProperties<LVScopeKind> Kinds;
9596
LVProperties<Property> Properties;
9697
static LVScopeDispatch Dispatch;
98+
// Empty containers used in `getChildren()` in case there is no Types,
99+
// Symbols, or Scopes.
100+
static const LVTypes EmptyTypes;
101+
static const LVSymbols EmptySymbols;
102+
static const LVScopes EmptyScopes;
97103

98104
// Size in bits if this scope represents also a compound type.
99105
uint32_t BitSize = 0;
@@ -128,14 +134,6 @@ class LLVM_ABI LVScope : public LVElement {
128134
std::unique_ptr<LVLines> Lines;
129135
std::unique_ptr<LVLocations> Ranges;
130136

131-
// Vector of elements (types, scopes and symbols).
132-
// It is the union of (*Types, *Symbols and *Scopes) to be used for
133-
// the following reasons:
134-
// - Preserve the order the logical elements are read in.
135-
// - To have a single container with all the logical elements, when
136-
// the traversal does not require any specific element kind.
137-
std::unique_ptr<LVElements> Children;
138-
139137
// Resolve the template parameters/arguments relationship.
140138
void resolveTemplate();
141139
void printEncodedArgs(raw_ostream &OS, bool Full) const;
@@ -213,7 +211,23 @@ class LLVM_ABI LVScope : public LVElement {
213211
const LVScopes *getScopes() const { return Scopes.get(); }
214212
const LVSymbols *getSymbols() const { return Symbols.get(); }
215213
const LVTypes *getTypes() const { return Types.get(); }
216-
const LVElements *getChildren() const { return Children.get(); }
214+
// Return view over union of child Scopes, Types, and Symbols, in that order.
215+
//
216+
// Calling `LVScope::sort()` ensures that each of groups is sorted according
217+
// to the given criteria (see also `LVOptions::setSortMode()`). Because
218+
// `getChildren()` iterates over the concatenation, the result returned by
219+
// this function is not necessarily sorted. If order is important, use
220+
// `getSortedChildren()`.
221+
LVElementsView getChildren() const {
222+
return llvm::concat<LVElement *const>(Scopes ? *Scopes : EmptyScopes,
223+
Types ? *Types : EmptyTypes,
224+
Symbols ? *Symbols : EmptySymbols);
225+
}
226+
// Return vector of child Scopes, Types, and Symbols that is sorted using
227+
// `SortFunction`. This requires copy + sort; if order is not important,
228+
// use `getChildren()` instead.
229+
LVElements getSortedChildren(
230+
LVSortFunction SortFunction = llvm::logicalview::getSortFunction()) const;
217231

218232
void addElement(LVElement *Element);
219233
void addElement(LVLine *Line);
@@ -222,7 +236,6 @@ class LLVM_ABI LVScope : public LVElement {
222236
void addElement(LVType *Type);
223237
void addObject(LVLocation *Location);
224238
void addObject(LVAddress LowerAddress, LVAddress UpperAddress);
225-
void addToChildren(LVElement *Element);
226239

227240
// Add the missing elements from the given 'Reference', which is the
228241
// scope associated with any DW_AT_specification, DW_AT_abstract_origin.

llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp

Lines changed: 35 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,16 @@ LVScopeDispatch LVScope::Dispatch = {
107107
{LVScopeKind::IsTryBlock, &LVScope::getIsTryBlock},
108108
{LVScopeKind::IsUnion, &LVScope::getIsUnion}};
109109

110-
void LVScope::addToChildren(LVElement *Element) {
111-
if (!Children)
112-
Children = std::make_unique<LVElements>();
113-
Children->push_back(Element);
110+
const LVTypes LVScope::EmptyTypes{};
111+
const LVSymbols LVScope::EmptySymbols{};
112+
const LVScopes LVScope::EmptyScopes{};
113+
114+
LVElements LVScope::getSortedChildren(LVSortFunction SortFunction) const {
115+
const auto UnsortedChildren = getChildren();
116+
LVElements Elements{UnsortedChildren.begin(), UnsortedChildren.end()};
117+
if (SortFunction)
118+
llvm::stable_sort(Elements, SortFunction);
119+
return Elements;
114120
}
115121

116122
void LVScope::addElement(LVElement *Element) {
@@ -175,7 +181,6 @@ void LVScope::addElement(LVScope *Scope) {
175181

176182
// Add it to parent.
177183
Scopes->push_back(Scope);
178-
addToChildren(Scope);
179184
Scope->setParent(this);
180185

181186
// Notify the reader about the new element being added.
@@ -202,7 +207,6 @@ void LVScope::addElement(LVSymbol *Symbol) {
202207

203208
// Add it to parent.
204209
Symbols->push_back(Symbol);
205-
addToChildren(Symbol);
206210
Symbol->setParent(this);
207211

208212
// Notify the reader about the new element being added.
@@ -229,7 +233,6 @@ void LVScope::addElement(LVType *Type) {
229233

230234
// Add it to parent.
231235
Types->push_back(Type);
232-
addToChildren(Type);
233236
Type->setParent(this);
234237

235238
// Notify the reader about the new element being added.
@@ -277,15 +280,12 @@ bool LVScope::removeElement(LVElement *Element) {
277280
if (Element->getIsLine())
278281
return RemoveElement(Lines);
279282

280-
if (RemoveElement(Children)) {
281-
if (Element->getIsSymbol())
282-
return RemoveElement(Symbols);
283-
if (Element->getIsType())
284-
return RemoveElement(Types);
285-
if (Element->getIsScope())
286-
return RemoveElement(Scopes);
287-
llvm_unreachable("Invalid element.");
288-
}
283+
if (Element->getIsSymbol())
284+
return RemoveElement(Symbols);
285+
if (Element->getIsType())
286+
return RemoveElement(Types);
287+
if (Element->getIsScope())
288+
return RemoveElement(Scopes);
289289

290290
return false;
291291
}
@@ -356,9 +356,8 @@ void LVScope::updateLevel(LVScope *Parent, bool Moved) {
356356
setLevel(Parent->getLevel() + 1);
357357

358358
// Update the children.
359-
if (Children)
360-
for (LVElement *Element : *Children)
361-
Element->updateLevel(this, Moved);
359+
for (LVElement *Element : getChildren())
360+
Element->updateLevel(this, Moved);
362361

363362
// Update any lines.
364363
if (Lines)
@@ -374,13 +373,12 @@ void LVScope::resolve() {
374373
LVElement::resolve();
375374

376375
// Resolve the children.
377-
if (Children)
378-
for (LVElement *Element : *Children) {
379-
if (getIsGlobalReference())
380-
// If the scope is a global reference, mark all its children as well.
381-
Element->setIsGlobalReference();
382-
Element->resolve();
383-
}
376+
for (LVElement *Element : getChildren()) {
377+
if (getIsGlobalReference())
378+
// If the scope is a global reference, mark all its children as well.
379+
Element->setIsGlobalReference();
380+
Element->resolve();
381+
}
384382
}
385383

386384
void LVScope::resolveName() {
@@ -633,14 +631,13 @@ Error LVScope::doPrint(bool Split, bool Match, bool Print, raw_ostream &OS,
633631
options().getPrintFormatting() &&
634632
getLevel() < options().getOutputLevel()) {
635633
// Print the children.
636-
if (Children)
637-
for (const LVElement *Element : *Children) {
638-
if (Match && !Element->getHasPattern())
639-
continue;
640-
if (Error Err =
641-
Element->doPrint(Split, Match, Print, *StreamSplit, Full))
642-
return Err;
643-
}
634+
for (const LVElement *Element : getSortedChildren()) {
635+
if (Match && !Element->getHasPattern())
636+
continue;
637+
if (Error Err =
638+
Element->doPrint(Split, Match, Print, *StreamSplit, Full))
639+
return Err;
640+
}
644641

645642
// Print the line records.
646643
if (Lines)
@@ -692,7 +689,6 @@ void LVScope::sort() {
692689
Traverse(Parent->Symbols, SortFunction);
693690
Traverse(Parent->Scopes, SortFunction);
694691
Traverse(Parent->Ranges, compareRange);
695-
Traverse(Parent->Children, SortFunction);
696692

697693
if (Parent->Scopes)
698694
for (LVScope *Scope : *Parent->Scopes)
@@ -978,9 +974,8 @@ bool LVScope::equals(const LVScopes *References, const LVScopes *Targets) {
978974
void LVScope::report(LVComparePass Pass) {
979975
getComparator().printItem(this, Pass);
980976
getComparator().push(this);
981-
if (Children)
982-
for (LVElement *Element : *Children)
983-
Element->report(Pass);
977+
for (LVElement *Element : getSortedChildren())
978+
Element->report(Pass);
984979

985980
if (Lines)
986981
for (LVLine *Line : *Lines)
@@ -1656,9 +1651,8 @@ void LVScopeCompileUnit::printMatchedElements(raw_ostream &OS,
16561651
// Print the view for the matched scopes.
16571652
for (const LVScope *Scope : MatchedScopes) {
16581653
Scope->print(OS);
1659-
if (const LVElements *Elements = Scope->getChildren())
1660-
for (LVElement *Element : *Elements)
1661-
Element->print(OS);
1654+
for (LVElement *Element : Scope->getSortedChildren())
1655+
Element->print(OS);
16621656
}
16631657
}
16641658

llvm/test/tools/llvm-debuginfo-analyzer/COFF/01-coff-print-basic-details.test

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,31 +18,14 @@
1818
; sorted by the debug information internal offset; it includes its lexical
1919
; level and debug info format.
2020

21-
; RUN: llvm-debuginfo-analyzer --attribute=level,format \
22-
; RUN: --output-sort=offset \
23-
; RUN: --print=scopes,symbols,types,lines,instructions \
24-
; RUN: %p/Inputs/test-codeview-clang.o 2>&1 | \
25-
; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
26-
27-
; If `--output-sort=id`, elements are iterated in the order in which they were
28-
; added (which matches the increasing offset of the reference output).
2921
; RUN: llvm-debuginfo-analyzer --attribute=level,format \
3022
; RUN: --output-sort=id \
3123
; RUN: --print=scopes,symbols,types,lines,instructions \
3224
; RUN: %p/Inputs/test-codeview-clang.o 2>&1 | \
3325
; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
3426

35-
; If `--output-sort=none`, `LVScope::Children` is not sorted; it, however,
36-
; reflects the order in which elements were added (same as `--output-sort=id`).
37-
; This is expected to change once #69160 is resolved though.
38-
; RUN: llvm-debuginfo-analyzer --attribute=level,format \
39-
; RUN: --output-sort=none \
40-
; RUN: --print=scopes,symbols,types,lines,instructions \
41-
; RUN: %p/Inputs/test-codeview-clang.o 2>&1 | \
42-
; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
43-
4427
; RUN: llvm-debuginfo-analyzer --attribute=level,format \
45-
; RUN: --output-sort=offset \
28+
; RUN: --output-sort=id \
4629
; RUN: --print=elements \
4730
; RUN: %p/Inputs/test-codeview-clang.o 2>&1 | \
4831
; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
@@ -80,3 +63,43 @@
8063
; ONE-NEXT: [003] {Code} 'addq $0x20, %rsp'
8164
; ONE-NEXT: [003] {Code} 'retq'
8265
; ONE-NEXT: [002] {TypeAlias} 'INTPTR' -> '* const int'
66+
67+
; RUN: llvm-debuginfo-analyzer --attribute=level,format \
68+
; RUN: --output-sort=none \
69+
; RUN: --print=scopes,symbols,types,lines,instructions \
70+
; RUN: %p/Inputs/test-codeview-clang.o 2>&1 | \
71+
; RUN: FileCheck --strict-whitespace -check-prefix=ONE-NOSORT %s
72+
73+
; ONE-NOSORT: Logical View:
74+
; ONE-NOSORT-NEXT: [000] {File} 'test-codeview-clang.o' -> COFF-x86-64
75+
; ONE-NOSORT-EMPTY:
76+
; ONE-NOSORT-NEXT: [001] {CompileUnit} 'test.cpp'
77+
; ONE-NOSORT-NEXT: [002] {Function} extern not_inlined 'foo' -> 'int'
78+
; ONE-NOSORT-NEXT: [003] {Block}
79+
; ONE-NOSORT-NEXT: [004] {Variable} 'CONSTANT' -> 'const int'
80+
; ONE-NOSORT-NEXT: [004] 5 {Line}
81+
; ONE-NOSORT-NEXT: [004] {Code} 'movl $0x7, 0x4(%rsp)'
82+
; ONE-NOSORT-NEXT: [004] 6 {Line}
83+
; ONE-NOSORT-NEXT: [004] {Code} 'movl $0x7, 0x1c(%rsp)'
84+
; ONE-NOSORT-NEXT: [004] {Code} 'jmp 0x8'
85+
; ONE-NOSORT-NEXT: [003] {TypeAlias} 'INTEGER' -> 'int'
86+
; ONE-NOSORT-NEXT: [003] {Parameter} 'ParamPtr' -> '* const int'
87+
; ONE-NOSORT-NEXT: [003] {Parameter} 'ParamUnsigned' -> 'unsigned'
88+
; ONE-NOSORT-NEXT: [003] {Parameter} 'ParamBool' -> 'bool'
89+
; ONE-NOSORT-NEXT: [003] 2 {Line}
90+
; ONE-NOSORT-NEXT: [003] {Code} 'subq $0x20, %rsp'
91+
; ONE-NOSORT-NEXT: [003] {Code} 'andb $0x1, %r8b'
92+
; ONE-NOSORT-NEXT: [003] {Code} 'movb %r8b, 0x1b(%rsp)'
93+
; ONE-NOSORT-NEXT: [003] {Code} 'movl %edx, 0x14(%rsp)'
94+
; ONE-NOSORT-NEXT: [003] {Code} 'movq %rcx, 0x8(%rsp)'
95+
; ONE-NOSORT-NEXT: [003] 3 {Line}
96+
; ONE-NOSORT-NEXT: [003] {Code} 'testb $0x1, 0x1b(%rsp)'
97+
; ONE-NOSORT-NEXT: [003] {Code} 'je 0x15'
98+
; ONE-NOSORT-NEXT: [003] 8 {Line}
99+
; ONE-NOSORT-NEXT: [003] {Code} 'movl 0x14(%rsp), %eax'
100+
; ONE-NOSORT-NEXT: [003] {Code} 'movl %eax, 0x1c(%rsp)'
101+
; ONE-NOSORT-NEXT: [003] 9 {Line}
102+
; ONE-NOSORT-NEXT: [003] {Code} 'movl 0x1c(%rsp), %eax'
103+
; ONE-NOSORT-NEXT: [003] {Code} 'addq $0x20, %rsp'
104+
; ONE-NOSORT-NEXT: [003] {Code} 'retq'
105+
; ONE-NOSORT-NEXT: [002] {TypeAlias} 'INTPTR' -> '* const int'

llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-compare-logical-elements.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535
; ONE-NEXT: [002] 1 {TypeAlias} 'INTPTR' -> '* const int'
3636
; ONE-NEXT: [002] 2 {Function} extern not_inlined 'foo' -> 'int'
3737
; ONE-NEXT: [003] {Block}
38-
; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER'
3938
; ONE-NEXT: +[004] 4 {TypeAlias} 'INTEGER' -> 'int'
39+
; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER'
4040
; ONE-NEXT: [003] 2 {Parameter} 'ParamBool' -> 'bool'
4141
; ONE-NEXT: [003] 2 {Parameter} 'ParamPtr' -> 'INTPTR'
4242
; ONE-NEXT: [003] 2 {Parameter} 'ParamUnsigned' -> 'unsigned int'

0 commit comments

Comments
 (0)