Skip to content

Commit

Permalink
[DWARF] Fix debug info generation for function static variables, type…
Browse files Browse the repository at this point in the history
…defs, and records

Function static variables, typedefs and records (class, struct or union) declared inside
a lexical scope were associated with the function as their parent scope, rather than the
lexical scope they are defined or declared in.

This fixes PR19238

Patch by: [email protected]
Differential Revision: http://reviews.llvm.org/D9758

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@241153 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
Michael Kuperstein committed Jul 1, 2015
1 parent 5020a91 commit 37cb5f1
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 35 deletions.
3 changes: 3 additions & 0 deletions include/llvm/ADT/iterator_range.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,7 @@ template <typename T> iterator_range<T> make_range(std::pair<T, T> p) {
}
}

template <typename R>
bool empty(const R& r) { return begin(r) == end(r); }

#endif
29 changes: 19 additions & 10 deletions lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ static const ConstantExpr *getMergedGlobalExpr(const Value *V) {

/// getOrCreateGlobalVariableDIE - get or create global variable DIE.
DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE(
const DIGlobalVariable *GV) {
const DIGlobalVariable *GV, DIE *ContextDIE) {
// Check for pre-existence.
if (DIE *Die = getDIE(GV))
return Die;
Expand All @@ -113,7 +113,8 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE(

// Construct the context before querying for the existence of the DIE in
// case such construction creates the DIE.
DIE *ContextDIE = getOrCreateContextDIE(GVContext);
if (ContextDIE == nullptr)
ContextDIE = getOrCreateContextDIE(GVContext);

// Add to map.
DIE *VariableDIE = &createAndAddDIE(GV->getTag(), *ContextDIE, GV);
Expand Down Expand Up @@ -335,24 +336,32 @@ void DwarfCompileUnit::constructScopeDIE(
// null and the children will be added to the scope DIE.
createScopeChildrenDIE(Scope, Children, &ChildScopeCount);

// Skip imported directives in gmlt-like data.
if (!includeMinimalInlineScopes()) {
// There is no need to emit empty lexical block DIE.
for (const auto &E : DD->findImportedEntitiesForScope(DS))
Children.push_back(
constructImportedEntityDIE(cast<DIImportedEntity>(E.second)));
}

DwarfDebug::LocalDeclMapRange LocalDeclNodeRangeForScope(nullptr, nullptr);
// Skip local decls in gmlt-like data.
if (!includeMinimalInlineScopes())
LocalDeclNodeRangeForScope = DD->findLocalDeclNodesForScope(DS);

// If there are only other scopes as children, put them directly in the
// parent instead, as this scope would serve no purpose.
if (Children.size() == ChildScopeCount) {
if (Children.size() == ChildScopeCount &&
empty(LocalDeclNodeRangeForScope)) {
FinalChildren.insert(FinalChildren.end(),
std::make_move_iterator(Children.begin()),
std::make_move_iterator(Children.end()));
return;
}
ScopeDIE = constructLexicalScopeDIE(Scope);
assert(ScopeDIE && "Scope DIE should not be null.");

for (const auto &DI : LocalDeclNodeRangeForScope) {
if (auto *IE = dyn_cast<DIImportedEntity>(DI.second))
Children.push_back(constructImportedEntityDIE(IE));
else if (auto *GV = dyn_cast<DIGlobalVariable>(DI.second))
getOrCreateGlobalVariableDIE(GV, ScopeDIE);
else if (auto *RT = dyn_cast<DIType>(DI.second))
getOrCreateTypeDIE(RT, ScopeDIE);
}
}

// Add children
Expand Down
7 changes: 5 additions & 2 deletions lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,11 @@ class DwarfCompileUnit : public DwarfUnit {
/// Apply the DW_AT_stmt_list from this compile unit to the specified DIE.
void applyStmtList(DIE &D);

/// getOrCreateGlobalVariableDIE - get or create global variable DIE.
DIE *getOrCreateGlobalVariableDIE(const DIGlobalVariable *GV);
/// Get or create global variable DIE.
/// \param GV Global Variable Node
/// \param ContextDIE DIE scope for GV Node, if available.
DIE *getOrCreateGlobalVariableDIE(const DIGlobalVariable *GV,
DIE *ContextDIE = nullptr);

/// addLabelAddress - Add a dwarf label attribute data and value using
/// either DW_FORM_addr or DW_FORM_GNU_addr_index.
Expand Down
29 changes: 20 additions & 9 deletions lib/CodeGen/AsmPrinter/DwarfDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,14 +449,14 @@ void DwarfDebug::beginModule() {
auto *CUNode = cast<DICompileUnit>(N);
DwarfCompileUnit &CU = constructDwarfCompileUnit(CUNode);
for (auto *IE : CUNode->getImportedEntities())
ScopesWithImportedEntities.push_back(std::make_pair(IE->getScope(), IE));
// Stable sort to preserve the order of appearance of imported entities.
// This is to avoid out-of-order processing of interdependent declarations
// within the same scope, e.g. { namespace A = base; namespace B = A; }
std::stable_sort(ScopesWithImportedEntities.begin(),
ScopesWithImportedEntities.end(), less_first());
for (auto *GV : CUNode->getGlobalVariables())
CU.getOrCreateGlobalVariableDIE(GV);
ScopesWithLocalDeclNodes.push_back(std::make_pair(IE->getScope(), IE));
for (auto *GV : CUNode->getGlobalVariables()) {
auto *Context = GV->getScope();
if (Context && isa<DILexicalBlockBase>(Context))
ScopesWithLocalDeclNodes.push_back(std::make_pair(Context, GV));
else
CU.getOrCreateGlobalVariableDIE(GV);
}
for (auto *SP : CUNode->getSubprograms())
SPMap.insert(std::make_pair(SP, &CU));
for (auto *Ty : CUNode->getEnumTypes()) {
Expand All @@ -467,12 +467,23 @@ void DwarfDebug::beginModule() {
for (auto *Ty : CUNode->getRetainedTypes()) {
// The retained types array by design contains pointers to
// MDNodes rather than DIRefs. Unique them here.
CU.getOrCreateTypeDIE(cast<DIType>(resolve(Ty->getRef())));
DIType *RT = cast<DIType>(resolve(Ty->getRef()));
auto *Context = resolve(Ty->getScope());
if (Context && isa<DILexicalBlockBase>(Context))
ScopesWithLocalDeclNodes.push_back(std::make_pair(Context, RT));
else
CU.getOrCreateTypeDIE(RT);
}
// Emit imported_modules last so that the relevant context is already
// available.
for (auto *IE : CUNode->getImportedEntities())
constructAndAddImportedEntityDIE(CU, IE);

// Stable sort to preserve the order of appearance of imported entities.
// This is to avoid out-of-order processing of interdependent declarations
// within the same scope, e.g. { namespace A = base; namespace B = A; }
std::stable_sort(ScopesWithLocalDeclNodes.begin(),
ScopesWithLocalDeclNodes.end(), less_first());
}

// Tell MMI that we have debug info.
Expand Down
17 changes: 8 additions & 9 deletions lib/CodeGen/AsmPrinter/DwarfDebug.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,13 +278,10 @@ class DwarfDebug : public AsmPrinterHandler {
// Holder for the file specific debug information.
DwarfFile InfoHolder;

// Holders for the various debug information flags that we might need to
// have exposed. See accessor functions below for description.

// Holder for imported entities.
// Holder for local declaration DI nodes per scope.
typedef SmallVector<std::pair<const MDNode *, const MDNode *>, 32>
ImportedEntityMap;
ImportedEntityMap ScopesWithImportedEntities;
LocalDeclMap;
LocalDeclMap ScopesWithLocalDeclNodes;

// Map from MDNodes for user-defined types to the type units that describe
// them.
Expand Down Expand Up @@ -619,10 +616,12 @@ class DwarfDebug : public AsmPrinterHandler {

const MachineFunction *getCurrentFunction() const { return CurFn; }

iterator_range<ImportedEntityMap::const_iterator>
findImportedEntitiesForScope(const MDNode *Scope) const {
typedef iterator_range<LocalDeclMap::const_iterator> LocalDeclMapRange;

LocalDeclMapRange findLocalDeclNodesForScope(const MDNode *Scope) const {
assert(DILexicalBlockBase::classof(Scope) && "Expected LexicalBlock scope");
return make_range(std::equal_range(
ScopesWithImportedEntities.begin(), ScopesWithImportedEntities.end(),
ScopesWithLocalDeclNodes.begin(), ScopesWithLocalDeclNodes.end(),
std::pair<const MDNode *, const MDNode *>(Scope, nullptr),
less_first()));
}
Expand Down
11 changes: 7 additions & 4 deletions lib/CodeGen/AsmPrinter/DwarfUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,7 @@ DIE *DwarfUnit::createTypeDIE(const DICompositeType *Ty) {
return &TyDIE;
}

DIE *DwarfUnit::getOrCreateTypeDIE(const MDNode *TyNode) {
DIE *DwarfUnit::getOrCreateTypeDIE(const MDNode *TyNode, DIE *ContextDIE) {
if (!TyNode)
return nullptr;

Expand All @@ -714,17 +714,20 @@ DIE *DwarfUnit::getOrCreateTypeDIE(const MDNode *TyNode) {

// DW_TAG_restrict_type is not supported in DWARF2
if (Ty->getTag() == dwarf::DW_TAG_restrict_type && DD->getDwarfVersion() <= 2)
return getOrCreateTypeDIE(resolve(cast<DIDerivedType>(Ty)->getBaseType()));
return getOrCreateTypeDIE(resolve(cast<DIDerivedType>(Ty)->getBaseType()),
ContextDIE);

// Construct the context before querying for the existence of the DIE in case
// such construction creates the DIE.
auto *Context = resolve(Ty->getScope());
DIE *ContextDIE = getOrCreateContextDIE(Context);
assert(ContextDIE);
if (ContextDIE == nullptr)
ContextDIE = getOrCreateContextDIE(Context);

if (DIE *TyDIE = getDIE(Ty))
return TyDIE;

assert(ContextDIE);

// Create new type.
DIE &TyDIE = createAndAddDIE(Ty->getTag(), *ContextDIE, Ty);

Expand Down
4 changes: 3 additions & 1 deletion lib/CodeGen/AsmPrinter/DwarfUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,9 @@ class DwarfUnit {
bool Minimal = false);

/// \brief Find existing DIE or create new DIE for the given type.
DIE *getOrCreateTypeDIE(const MDNode *N);
/// \param N Type Node
/// \param ContextDIE DIE scope for N Node, if available.
DIE *getOrCreateTypeDIE(const MDNode *N, DIE *ContextDIE = nullptr);

/// \brief Get context owner's DIE.
DIE *createTypeDIE(const DICompositeType *Ty);
Expand Down
129 changes: 129 additions & 0 deletions test/DebugInfo/lexical-block.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
; RUN: llc -mtriple=x86_64-unknown-linux-gnu -filetype=obj -O0 < %s | llvm-dwarfdump -debug-dump=info - | FileCheck %s

;; This test checks the following:
;; 1. Useless lexical block entry is not emitted
;; 2. Function static variable, typedef, records (structure, class and union)
;; that are defined in lexical basic block are emitted as children to
;; these lexical blocks.
;; * For typedef and record check that both are emitted in lexical block
;; where they are declared and not in the one where they are used.
;;
;; This test was generated by running following command:
;; clang -cc1 -O0 -g -emit-llvm foo.cpp
;; Where foo.cpp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;int foo(void) {
;; {
;; {
;; struct X {
;; int x;
;; };
;; typedef int Y;
;; {
;; X a;
;; Y b;
;; static int c;
;; return a.x + b + c;
;; }
;; }
;; }
;;}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


; CHECK: DW_TAG_subprogram
; CHECK-NOT: DW_TAG
; CHECK: DW_AT_name {{.*}} "foo"
; CHECK-NOT: NULL
; CHECK: DW_TAG_lexical_block

; CHECK-NOT: {{DW_TAG|NULL}}
; CHECK: DW_TAG_structure_type
; CHECK-NOT: {{DW_TAG|NULL}}
; CHECK: DW_AT_name {{.*}} "X"
; CHECK: NULL

; CHECK-NOT: {{DW_TAG|NULL}}
; CHECK: DW_TAG_typedef
; CHECK-NOT: {{DW_TAG|NULL}}
; CHECK: DW_AT_name {{.*}} "Y"

; CHECK-NOT: {{DW_TAG|NULL}}
; CHECK: DW_TAG_lexical_block

; CHECK-NOT: {{DW_TAG|NULL}}
; CHECK: DW_TAG_variable
; CHECK-NOT: {{DW_TAG|NULL}}
; CHECK: DW_AT_name {{.*}} "c"

; CHECK-NOT: {{DW_TAG|NULL}}
; CHECK: DW_TAG_variable
; CHECK-NOT: {{DW_TAG|NULL}}
; CHECK: DW_AT_name {{.*}} "a"

; CHECK-NOT: {{DW_TAG|NULL}}
; CHECK: DW_TAG_variable
; CHECK-NOT: {{DW_TAG|NULL}}
; CHECK: DW_AT_name {{.*}} "b"

; CHECK-NOT: {{DW_TAG}}
; CHECK: NULL


%struct.X = type { i32 }

@_ZZ3foovE1c = internal global i32 0, align 4

; Function Attrs: nounwind
define i32 @_Z3foov() #0 {
entry:
%a = alloca %struct.X, align 4
%b = alloca i32, align 4
call void @llvm.dbg.declare(metadata %struct.X* %a, metadata !21, metadata !22), !dbg !23
call void @llvm.dbg.declare(metadata i32* %b, metadata !24, metadata !22), !dbg !25
%x = getelementptr inbounds %struct.X, %struct.X* %a, i32 0, i32 0, !dbg !26
%0 = load i32, i32* %x, align 4, !dbg !26
%1 = load i32, i32* %b, align 4, !dbg !26
%add = add nsw i32 %0, %1, !dbg !26
%2 = load i32, i32* @_ZZ3foovE1c, align 4, !dbg !26
%add1 = add nsw i32 %add, %2, !dbg !26
ret i32 %add1, !dbg !26
}

; Function Attrs: nounwind readnone
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1

attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind readnone }

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!18, !19}
!llvm.ident = !{!20}

!0 = !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.7.0 (trunk 237245)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !14, globals: !15, imports: !2)
!1 = !DIFile(filename: "foo.cpp", directory: "/")
!2 = !{}
!3 = !{!4, !13}
!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "X", scope: !5, file: !1, line: 4, size: 32, align: 32, elements: !11)
!5 = distinct !DILexicalBlock(scope: !6, file: !1, line: 3)
!6 = distinct !DILexicalBlock(scope: !7, file: !1, line: 2)
!7 = !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, function: i32 ()* @_Z3foov, variables: !2)
!8 = !DISubroutineType(types: !9)
!9 = !{!10}
!10 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
!11 = !{!12}
!12 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !4, file: !1, line: 5, baseType: !10, size: 32, align: 32)
!13 = !DIDerivedType(tag: DW_TAG_typedef, name: "Y", scope: !5, file: !1, line: 7, baseType: !10)
!14 = !{!7}
!15 = !{!16}
!16 = !DIGlobalVariable(name: "c", scope: !17, file: !1, line: 11, type: !10, isLocal: true, isDefinition: true, variable: i32* @_ZZ3foovE1c)
!17 = distinct !DILexicalBlock(scope: !5, file: !1, line: 8)
!18 = !{i32 2, !"Dwarf Version", i32 4}
!19 = !{i32 2, !"Debug Info Version", i32 3}
!20 = !{!"clang version 3.7.0 (trunk 237245)"}
!21 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "a", scope: !17, file: !1, line: 9, type: !4)
!22 = !DIExpression()
!23 = !DILocation(line: 9, scope: !17)
!24 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "b", scope: !17, file: !1, line: 10, type: !13)
!25 = !DILocation(line: 10, scope: !17)
!26 = !DILocation(line: 12, scope: !17)

0 comments on commit 37cb5f1

Please sign in to comment.