Skip to content

Commit

Permalink
[DebugMetadata][DwarfDebug] Fix DWARF emisson of function-local impor…
Browse files Browse the repository at this point in the history
…ted entities (3/7)

RFC https://discourse.llvm.org/t/rfc-dwarfdebug-fix-and-improve-handling-imported-entities-types-and-static-local-in-subprogram-and-lexical-block-scopes/68544

Fixed PR51501 (tests from D112337).

1. Reuse of DISubprogram's 'retainedNodes' to track other function-local
   entities together with local variables and labels (this patch cares about
   function-local import while D144006 and D144008 use the same approach for
   local types and static variables). So, effectively this patch moves ownership
   of tracking local import from DICompileUnit's 'imports' field to DISubprogram's
   'retainedNodes' and adjusts DWARF emitter for the new layout. The old layout
   is considered unsupported (DwarfDebug would assert on such debug metadata).

   DICompileUnit's 'imports' field is supposed to track global imported
   declarations as it does before.

   This addresses various FIXMEs and simplifies the next part of the patch.

2. Postpone emission of function-local imported entities from
   `DwarfDebug::endFunctionImpl()` to `DwarfDebug::endModule()`.
   While in `DwarfDebug::endFunctionImpl()` we do not have all the
   information about a parent subprogram or a referring subprogram
   (whether a subprogram inlined or not), so we can't guarantee we emit
   an imported entity correctly and place it in a proper subprogram tree.
   So now, we just gather needed details about the import itself and its
   parent entity (either a Subprogram or a LexicalBlock) during
   processing in `DwarfDebug::endFunctionImpl()`, but all the real work is
   done in `DwarfDebug::endModule()` when we have all the required
   information to make proper emission.

Authored-by: Kristina Bessonova <kbessonova@accesssoftek.com>

Differential Revision: https://reviews.llvm.org/D144004
  • Loading branch information
dzhidzhoev committed Jun 15, 2023
1 parent e2e4f67 commit ed578f0
Show file tree
Hide file tree
Showing 35 changed files with 766 additions and 278 deletions.
41 changes: 20 additions & 21 deletions clang/test/CodeGenCXX/debug-info-namespace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,44 +81,43 @@ void C::c() {}
// CHECK: !DINamespace(scope: null)
// CHECK: [[CU:![0-9]+]] = distinct !DICompileUnit(
// CHECK-SAME: imports: [[MODULES:![0-9]*]]
// CHECK: [[MODULES]] = !{[[M1:![0-9]+]], [[M2:![0-9]+]], [[M3:![0-9]+]], [[M4:![0-9]+]], [[M5:![0-9]+]], [[M6:![0-9]+]], [[M7:![0-9]+]], [[M8:![0-9]+]], [[M9:![0-9]+]], [[M10:![0-9]+]], [[M11:![0-9]+]], [[M12:![0-9]+]], [[M13:![0-9]+]], [[M14:![0-9]+]], [[M15:![0-9]+]], [[M16:![0-9]+]], [[M17:![0-9]+]]
// CHECK: [[MODULES]] = !{[[M1:![0-9]+]], [[M2:![0-9]+]], [[M3:![0-9]+]], [[M4:![0-9]+]]}
// CHECK: [[M1]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[CTXT]], entity: [[NS]], file: [[FOOCPP]], line: 15)

// CHECK: [[M2]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[CU]], entity: [[CTXT]],
// CHECK: [[M3]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "E", scope: [[CU]], entity: [[CTXT]], file: [[FOOCPP]], line: 19)
// CHECK: [[M4]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[LEX2:![0-9]+]], entity: [[NS]], file: [[FOOCPP]], line: 23)
// CHECK: [[M4]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[CTXT]], entity: [[I]]
// CHECK: [[F1:![0-9]+]] = distinct !DISubprogram(name: "f1",{{.*}} line: 4
// CHECK-SAME: DISPFlagDefinition
// CHECK: [[FUNC:![0-9]+]] = distinct !DISubprogram(name: "func",{{.*}} DISPFlagDefinition
// CHECK-SAME: retainedNodes: [[FUNC_NODES:![0-9]*]]
// CHECK: [[FUNC_NODES]] = !{[[M5:![0-9]+]], [[M6:![0-9]+]], [[M7:![0-9]+]], [[M8:![0-9]+]], [[M9:![0-9]+]], [[M10:![0-9]+]], [[M11:![0-9]+]], [[M12:![0-9]+]], [[M13:![0-9]+]], [[M14:![0-9]+]], [[M15:![0-9]+]], [[M16:![0-9]+]], [[M17:![0-9]+]]}
// CHECK: [[M5]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[LEX2:![0-9]+]], entity: [[NS]], file: [[FOOCPP]], line: 23)
// CHECK: [[LEX2]] = distinct !DILexicalBlock(scope: [[LEX1:![0-9]+]], file: [[FOOCPP]],
// CHECK: [[LEX1]] = distinct !DILexicalBlock(scope: [[FUNC:![0-9]+]], file: [[FOOCPP]],

// CHECK: [[FUNC:![0-9]+]] = distinct !DISubprogram(name: "func",{{.*}} DISPFlagDefinition
// CHECK: [[M5]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[FUNC]], entity: [[CTXT:![0-9]+]],
// CHECK: [[M6]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FOO:![0-9]+]], file: [[FOOCPP]], line: 27)
// CHECK: [[M6]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[FUNC]], entity: [[CTXT]],
// CHECK: [[M7]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FOO:![0-9]+]], file: [[FOOCPP]], line: 27)
// CHECK: [[FOO]] = !DICompositeType(tag: DW_TAG_structure_type, name: "foo",
// CHECK-SAME: line: 5
// CHECK-SAME: DIFlagFwdDecl
// CHECK: [[M7]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[BAR:![0-9]+]]
// CHECK: [[M8]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[BAR:![0-9]+]]
// CHECK: [[BAR]] = !DICompositeType(tag: DW_TAG_structure_type, name: "bar",
// CHECK-SAME: line: 6
// CHECK-SAME: DIFlagFwdDecl

// CHECK: [[M8]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[F1:![0-9]+]]
// CHECK: [[F1:![0-9]+]] = distinct !DISubprogram(name: "f1",{{.*}} line: 4
// CHECK-SAME: DISPFlagDefinition
// CHECK: [[M9]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[I]]
// CHECK: [[M10]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[BAZ:![0-9]+]]
// CHECK: [[M9]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[F1]]
// CHECK: [[M10]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[I]]
// CHECK: [[M11]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[BAZ:![0-9]+]]
// CHECK: [[BAZ]] = !DIDerivedType(tag: DW_TAG_typedef, name: "baz", scope: [[NS]], file: [[FOOCPP]],
// CHECK-SAME: baseType: [[BAR]]
// CHECK: [[M11]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "X", scope: [[FUNC]], entity: [[CTXT]]
// CHECK: [[M12]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "Y", scope: [[FUNC]], entity: [[M11]]
// CHECK: [[M13]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[VAR_DECL:![0-9]+]]
// CHECK: [[M12]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "X", scope: [[FUNC]], entity: [[CTXT]]
// CHECK: [[M13]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "Y", scope: [[FUNC]], entity: [[M12]]
// CHECK: [[M14]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[VAR_DECL:![0-9]+]]
// CHECK: [[VAR_DECL]] = !DIGlobalVariable(name: "var_decl", linkageName: "{{[^"]*var_decl[^"]*}}", scope: [[NS]],{{.*}} line: 8,
// CHECK: [[M14]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_DECL:![0-9]+]]
// CHECK: [[M15]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_DECL:![0-9]+]]
// CHECK: [[FUNC_DECL]] = !DISubprogram(name: "func_decl",
// CHECK-SAME: scope: [[NS]], file: [[FOOCPP]], line: 9
// CHECK: [[M15]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[VAR_FWD:![0-9]+]]
// CHECK: [[M16]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_FWD:![0-9]+]]
// CHECK: [[M16]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[VAR_FWD:![0-9]+]]
// CHECK: [[M17]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_FWD:![0-9]+]]
// CHECK: [[FUNC_FWD]] = distinct !DISubprogram(name: "func_fwd",{{.*}} line: 53,{{.*}} DISPFlagDefinition
// CHECK: [[M17]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[CTXT]], entity: [[I]]
// CHECK: distinct !DISubprogram(name: "c",{{.*}}, scope: ![[C:[0-9]+]],{{.*}}, line: 60,{{.*}} DISPFlagDefinition
// CHECK: ![[C]] = !DINamespace(name: "C",

Expand Down
11 changes: 9 additions & 2 deletions llvm/include/llvm/IR/DIBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ namespace llvm {
SmallVector<TrackingMDNodeRef, 4> AllRetainTypes;
SmallVector<DISubprogram *, 4> AllSubprograms;
SmallVector<Metadata *, 4> AllGVs;
SmallVector<TrackingMDNodeRef, 4> AllImportedModules;
SmallVector<TrackingMDNodeRef, 4> ImportedModules;
/// Map Macro parent (which can be DIMacroFile or nullptr) to a list of
/// Metadata all of type DIMacroNode.
/// DIMacroNode's with nullptr parent are DICompileUnit direct children.
Expand All @@ -64,14 +64,21 @@ namespace llvm {
SmallVector<TrackingMDNodeRef, 4> UnresolvedNodes;
bool AllowUnresolvedNodes;

/// Each subprogram's preserved local variables and labels.
/// Each subprogram's preserved local variables, labels and imported
/// entities.
///
/// Do not use a std::vector. Some versions of libc++ apparently copy
/// instead of move on grow operations, and TrackingMDRef is expensive to
/// copy.
DenseMap<DISubprogram *, SmallVector<TrackingMDNodeRef, 4>>
SubprogramTrackedNodes;

SmallVectorImpl<TrackingMDNodeRef> &
getImportTrackingVector(const DIScope *S) {
return isa_and_nonnull<DILocalScope>(S)
? getSubprogramNodesTrackingVector(S)
: ImportedModules;
}
SmallVectorImpl<TrackingMDNodeRef> &
getSubprogramNodesTrackingVector(const DIScope *S) {
return SubprogramTrackedNodes[cast<DILocalScope>(S)->getSubprogram()];
Expand Down
84 changes: 84 additions & 0 deletions llvm/lib/Bitcode/Reader/MetadataLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
Expand Down Expand Up @@ -53,6 +54,7 @@
#include <deque>
#include <iterator>
#include <limits>
#include <map>
#include <optional>
#include <string>
#include <tuple>
Expand Down Expand Up @@ -463,6 +465,9 @@ class MetadataLoader::MetadataLoaderImpl {
bool NeedUpgradeToDIGlobalVariableExpression = false;
bool NeedDeclareExpressionUpgrade = false;

/// Map DILocalScope to the enclosing DISubprogram, if any.
DenseMap<DILocalScope *, DISubprogram *> ParentSubprogram;

/// True if metadata is being parsed for a module being ThinLTO imported.
bool IsImporting = false;

Expand Down Expand Up @@ -521,6 +526,84 @@ class MetadataLoader::MetadataLoaderImpl {
}
}

DISubprogram *findEnclosingSubprogram(DILocalScope *S) {
if (!S)
return nullptr;
if (auto *SP = ParentSubprogram[S]) {
return SP;
}

DILocalScope *InitialScope = S;
DenseSet<DILocalScope *> Visited;
while (S && !isa<DISubprogram>(S)) {
S = dyn_cast_or_null<DILocalScope>(S->getScope());
if (Visited.contains(S))
break;
Visited.insert(S);
}
ParentSubprogram[InitialScope] = llvm::dyn_cast_or_null<DISubprogram>(S);

return ParentSubprogram[InitialScope];
}

/// Move local imports from DICompileUnit's 'imports' field to
/// DISubprogram's retainedNodes.
void upgradeCULocals() {
if (NamedMDNode *CUNodes = TheModule.getNamedMetadata("llvm.dbg.cu")) {
for (unsigned I = 0, E = CUNodes->getNumOperands(); I != E; ++I) {
auto *CU = dyn_cast<DICompileUnit>(CUNodes->getOperand(I));
if (!CU)
continue;

if (auto *RawImported = CU->getRawImportedEntities()) {
// Collect a set of imported entities to be moved.
SmallPtrSet<Metadata *, 8> EntitiesToRemove;
for (Metadata *Op : CU->getImportedEntities()->operands()) {
auto *IE = cast<DIImportedEntity>(Op);
if (auto *S = dyn_cast_or_null<DILocalScope>(IE->getScope())) {
EntitiesToRemove.insert(IE);
}
}

if (!EntitiesToRemove.empty()) {
// Make a new list of CU's 'imports'.
SmallVector<Metadata *> NewImports;
for (Metadata *Op : CU->getImportedEntities()->operands()) {
if (!EntitiesToRemove.contains(cast<DIImportedEntity>(Op))) {
NewImports.push_back(Op);
}
}

// Find DISubprogram corresponding to each entity.
std::map<DISubprogram *, SmallVector<Metadata *>> SPToEntities;
for (auto *I : EntitiesToRemove) {
auto *Entity = cast<DIImportedEntity>(I);
if (auto *SP = findEnclosingSubprogram(
cast<DILocalScope>(Entity->getScope()))) {
SPToEntities[SP].push_back(Entity);
}
}

// Update DISubprograms' retainedNodes.
for (auto I = SPToEntities.begin(); I != SPToEntities.end(); ++I) {
auto *SP = I->first;
auto RetainedNodes = SP->getRetainedNodes();
SmallVector<Metadata *> MDs(RetainedNodes.begin(),
RetainedNodes.end());
MDs.append(I->second);
SP->replaceRetainedNodes(MDNode::get(Context, MDs));
}

// Remove entities with local scope from CU.
CU->replaceImportedEntities(MDTuple::get(Context, NewImports));
}
}
}
}

ParentSubprogram.clear();
}

/// Remove a leading DW_OP_deref from DIExpressions in a dbg.declare that
/// describes a function argument.
void upgradeDeclareExpressions(Function &F) {
Expand Down Expand Up @@ -625,6 +708,7 @@ class MetadataLoader::MetadataLoaderImpl {
void upgradeDebugInfo() {
upgradeCUSubprograms();
upgradeCUVariables();
upgradeCULocals();
}

void callMDTypeCallback(Metadata **Val, unsigned TypeID);
Expand Down
Loading

0 comments on commit ed578f0

Please sign in to comment.