Skip to content

Commit

Permalink
Reland [DWARF] Location-less inlined variables should not have DW_TAG…
Browse files Browse the repository at this point in the history
…_variable

Originally landed in ddc2f1e and reverted in d32deaa because of
a Generic test objecting. That was fixed up in 0136139. Original
landing commit message follows:

[DWARF] Location-less inlined variables should not have DW_TAG_variable

Discussed in this thread:

  https://lists.llvm.org/pipermail/llvm-dev/2021-January/148139.html

DwarfDebug::collectEntityInfo accidentally distinguishes between variable
locations that never have a location specified, and variable locations that
have an empty location specified. The latter leads to the creation of an
empty variable referring to the abstract origin.

Fix this by seeking a non-empty location before producing a concrete
entity, to guarantee a DW_AT_location will be produced. Other loops in
collectEntityInfo and endFunctionImpl take care of examining the
retainedNodes collection and ensuring optimised-out variables are created.

Differential Revision: https://reviews.llvm.org/D95617
  • Loading branch information
jmorse committed Feb 10, 2021
1 parent 5ea2d4f commit 1d68e0a
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 39 deletions.
4 changes: 4 additions & 0 deletions llvm/include/llvm/CodeGen/DbgEntityHistoryCalculator.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ class DbgValueHistoryMap {
return Entries[Index];
}

/// Test whether a vector of entries features any non-empty locations. It
/// could have no entries, or only DBG_VALUE $noreg entries.
bool hasNonEmptyLocation(const Entries &Entries) const;

/// Drop location ranges which exist entirely outside each variable's scope.
void trimLocationRanges(const MachineFunction &MF, LexicalScopes &LScopes,
const InstructionOrdering &Ordering);
Expand Down
17 changes: 17 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,23 @@ void DbgValueHistoryMap::trimLocationRanges(
}
}

bool DbgValueHistoryMap::hasNonEmptyLocation(const Entries &Entries) const {
for (const auto &Entry : Entries) {
if (!Entry.isDbgValue())
continue;

const MachineInstr *MI = Entry.getInstr();
assert(MI->isDebugValue());
// A DBG_VALUE $noreg is an empty variable location
if (MI->getOperand(0).isReg() && MI->getOperand(0).getReg() == 0)
continue;

return true;
}

return false;
}

void DbgLabelInstrMap::addInstr(InlinedEntity Label, const MachineInstr &MI) {
assert(MI.isDebugLabel() && "not a DBG_LABEL");
LabelInstr[Label] = &MI;
Expand Down
5 changes: 4 additions & 1 deletion llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1783,7 +1783,10 @@ void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU,

// Instruction ranges, specifying where IV is accessible.
const auto &HistoryMapEntries = I.second;
if (HistoryMapEntries.empty())

// Try to find any non-empty variable location. Do not create a concrete
// entity if there are no locations.
if (!DbgValues.hasNonEmptyLocation(HistoryMapEntries))
continue;

LexicalScope *Scope = nullptr;
Expand Down
136 changes: 136 additions & 0 deletions llvm/test/DebugInfo/Generic/no-empty-child-vars.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
; RUN: %llc_dwarf %s -o - -filetype=obj | llvm-dwarfdump - | FileCheck %s -implicit-check-not=DW_TAG
;
; This tests that we do not create concrete variable DIEs for variables that
; have no location -- for both ways that LLVM-IR can express a variable with
; no location. It's possible to:
; 1) Omit all dbg.values and place the variable in the subprograms retained
; nodes list,
; 2) Have a dbg.value with an undef operand, and none with "real" operands.
; Both of these should produce the same DWARF. In the two functions below
; (qux and croix) I've modified the IR to represent both scenarios.
;
; Original C, LLVM-IR modified afterwards:
;
; int foo(int bar) {
; int baz = 12 + bar;
; return baz;
; }
;
; int qux(int quux) {
; int xyzzy = foo(quux);
; return xyzzy;
; }
;
; int croix(int quux) {
; int xyzzy = foo(quux);
; return xyzzy;
; }
;
;; Note the implicit DW_TAG check-not in the FileCheck command line.
; CHECK: DW_TAG_compile_unit
;;
;; First subprogram is attached to the plain "foo" function in the output
;; object. It should have locations for the two variables in the function,
;; let's be non-specific as to how.
; CHECK: DW_TAG_subprogram
; CHECK: DW_AT_abstract_origin (0x{{[0-9a-f]*}} "foo")
; CHECK: DW_TAG_formal_parameter
; CHECK: DW_AT_location
; CHECK: DW_TAG_variable
; CHECK: DW_AT_location
;
;; Abstract subprogram; should have plain variable declarations
; CHECK: DW_TAG_subprogram
; CHECK: DW_AT_name ("foo")
; CHECK: DW_TAG_formal_parameter
; CHECK: DW_AT_name ("bar")
; CHECK: DW_TAG_variable
; CHECK: DW_AT_name ("baz")
;
; CHECK: DW_TAG_base_type
;
;; The copy of "foo" inlined into "qux" should have no children.
; CHECK: DW_TAG_subprogram
; CHECK: DW_AT_name ("qux")
; CHECK: DW_TAG_formal_parameter
; CHECK: DW_TAG_variable
; CHECK: DW_TAG_inlined_subroutine
; CHECK: NULL
;
;; Same for the copy of foo inlined into "croix"
; CHECK: DW_TAG_subprogram
; CHECK: DW_AT_name ("croix")
; CHECK: DW_TAG_formal_parameter
; CHECK: DW_TAG_variable
; CHECK: DW_TAG_inlined_subroutine
; CHECK: NULL

; Function Attrs: norecurse nounwind readnone uwtable willreturn
define dso_local i32 @foo(i32 %bar) local_unnamed_addr !dbg !7 {
entry:
call void @llvm.dbg.value(metadata i32 %bar, metadata !12, metadata !DIExpression()), !dbg !14
%add = add nsw i32 %bar, 12, !dbg !15
call void @llvm.dbg.value(metadata i32 %add, metadata !13, metadata !DIExpression()), !dbg !14
ret i32 %add, !dbg !16
}

; Function Attrs: norecurse nounwind readnone uwtable willreturn
define dso_local i32 @qux(i32 %quux) local_unnamed_addr !dbg !17 {
entry:
%add.i = add nsw i32 %quux, 12, !dbg !24
ret i32 %add.i, !dbg !25
}

; Function Attrs: norecurse nounwind readnone uwtable willreturn
define dso_local i32 @croix(i32 %quux) local_unnamed_addr !dbg !26 {
entry:
call void @llvm.dbg.value(metadata i32 undef, metadata !28, metadata !DIExpression()), !dbg !30
call void @llvm.dbg.value(metadata i32 undef, metadata !12, metadata !DIExpression()), !dbg !31
%add.i = add nsw i32 %quux, 12, !dbg !33
call void @llvm.dbg.value(metadata i32 undef, metadata !13, metadata !DIExpression()), !dbg !31
call void @llvm.dbg.value(metadata i32 undef, metadata !29, metadata !DIExpression()), !dbg !30
ret i32 %add.i, !dbg !34
}

; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
declare void @llvm.dbg.value(metadata, metadata, metadata)

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5}
!llvm.ident = !{!6}

!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "test.c", directory: ".")
!2 = !{}
!3 = !{i32 7, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{!"clang"}
!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
!8 = !DISubroutineType(types: !9)
!9 = !{!10, !10}
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!11 = !{!12, !13}
!12 = !DILocalVariable(name: "bar", arg: 1, scope: !7, file: !1, line: 1, type: !10)
!13 = !DILocalVariable(name: "baz", scope: !7, file: !1, line: 2, type: !10)
!14 = !DILocation(line: 0, scope: !7)
!15 = !DILocation(line: 2, column: 16, scope: !7)
!16 = !DILocation(line: 3, column: 3, scope: !7)
!17 = distinct !DISubprogram(name: "qux", scope: !1, file: !1, line: 6, type: !8, scopeLine: 6, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !18)
!18 = !{!19, !20}
!19 = !DILocalVariable(name: "quux", arg: 1, scope: !17, file: !1, line: 6, type: !10)
!20 = !DILocalVariable(name: "xyzzy", scope: !17, file: !1, line: 7, type: !10)
!21 = !DILocation(line: 0, scope: !17)
!22 = !DILocation(line: 0, scope: !7, inlinedAt: !23)
!23 = distinct !DILocation(line: 7, column: 15, scope: !17)
!24 = !DILocation(line: 2, column: 16, scope: !7, inlinedAt: !23)
!25 = !DILocation(line: 8, column: 3, scope: !17)
!26 = distinct !DISubprogram(name: "croix", scope: !1, file: !1, line: 11, type: !8, scopeLine: 11, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !27)
!27 = !{!28, !29}
!28 = !DILocalVariable(name: "quux", arg: 1, scope: !26, file: !1, line: 11, type: !10)
!29 = !DILocalVariable(name: "xyzzy", scope: !26, file: !1, line: 12, type: !10)
!30 = !DILocation(line: 0, scope: !26)
!31 = !DILocation(line: 0, scope: !7, inlinedAt: !32)
!32 = distinct !DILocation(line: 12, column: 15, scope: !26)
!33 = !DILocation(line: 2, column: 16, scope: !7, inlinedAt: !32)
!34 = !DILocation(line: 13, column: 3, scope: !26)
15 changes: 8 additions & 7 deletions llvm/test/DebugInfo/NVPTX/debug-addr-class.ll
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata)
!14 = !{i32 4, !"nvvm-reflect-ftz", i32 0}
!15 = !{i32 7, !"PIC Level", i32 2}
!16 = !{!"clang version 9.0.0 (trunk 351969) (llvm/trunk 351973)"}
!17 = distinct !DISubprogram(name: "test", linkageName: "test", scope: !8, file: !8, line: 6, type: !18, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4)
!17 = distinct !DISubprogram(name: "test", linkageName: "test", scope: !8, file: !8, line: 6, type: !18, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !40)
!18 = !DISubroutineType(types: !19)
!19 = !{null, !20, !21, !21, !9}
!20 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
Expand All @@ -81,6 +81,7 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata)
!37 = !DILocation(line: 8, column: 10, scope: !17)
!38 = !DILocation(line: 9, column: 10, scope: !17)
!39 = !DILocation(line: 10, column: 1, scope: !17)
!40 = !{!22, !24, !26, !28}

; CHECK: .section .debug_abbrev
; CHECK-NEXT: {
Expand Down Expand Up @@ -319,29 +320,27 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata)
; CHECK-NEXT:.b8 0
; CHECK-NEXT:.b8 1 // DW_AT_decl_file
; CHECK-NEXT:.b8 6 // DW_AT_decl_line
; CHECK-NEXT:.b32 234 // DW_AT_type
; CHECK-NEXT:.b32 229 // DW_AT_type
; CHECK-NEXT:.b8 5 // Abbrev [5] 0xc9:0x9 DW_TAG_formal_parameter
; CHECK-NEXT:.b8 120 // DW_AT_name
; CHECK-NEXT:.b8 0
; CHECK-NEXT:.b8 1 // DW_AT_decl_file
; CHECK-NEXT:.b8 6 // DW_AT_decl_line
; CHECK-NEXT:.b32 229 // DW_AT_type
; CHECK-NEXT:.b32 238 // DW_AT_type
; CHECK-NEXT:.b8 5 // Abbrev [5] 0xd2:0x9 DW_TAG_formal_parameter
; CHECK-NEXT:.b8 121 // DW_AT_name
; CHECK-NEXT:.b8 0
; CHECK-NEXT:.b8 1 // DW_AT_decl_file
; CHECK-NEXT:.b8 6 // DW_AT_decl_line
; CHECK-NEXT:.b32 229 // DW_AT_type
; CHECK-NEXT:.b32 238 // DW_AT_type
; CHECK-NEXT:.b8 5 // Abbrev [5] 0xdb:0x9 DW_TAG_formal_parameter
; CHECK-NEXT:.b8 105 // DW_AT_name
; CHECK-NEXT:.b8 0
; CHECK-NEXT:.b8 1 // DW_AT_decl_file
; CHECK-NEXT:.b8 6 // DW_AT_decl_line
; CHECK-NEXT:.b32 127 // DW_AT_type
; CHECK-NEXT:.b8 0 // End Of Children Mark
; CHECK-NEXT:.b8 6 // Abbrev [6] 0xe5:0x5 DW_TAG_pointer_type
; CHECK-NEXT:.b32 234 // DW_AT_type
; CHECK-NEXT:.b8 3 // Abbrev [3] 0xea:0x9 DW_TAG_base_type
; CHECK-NEXT:.b8 3 // Abbrev [3] 0xe5:0x9 DW_TAG_base_type
; CHECK-NEXT:.b8 102 // DW_AT_name
; CHECK-NEXT:.b8 108
; CHECK-NEXT:.b8 111
Expand All @@ -350,6 +349,8 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata)
; CHECK-NEXT:.b8 0
; CHECK-NEXT:.b8 4 // DW_AT_encoding
; CHECK-NEXT:.b8 4 // DW_AT_byte_size
; CHECK-NEXT:.b8 6 // Abbrev [6] 0xee:0x5 DW_TAG_pointer_type
; CHECK-NEXT:.b32 229 // DW_AT_type
; CHECK-NEXT:.b8 0 // End Of Children Mark
; CHECK-NEXT: }
; CHECK-NEXT: .section .debug_loc { }
Expand Down
12 changes: 4 additions & 8 deletions llvm/test/DebugInfo/NVPTX/debug-info.ll
Original file line number Diff line number Diff line change
Expand Up @@ -702,12 +702,12 @@ if.end: ; preds = %if.then, %entry
; CHECK-NEXT: }
; CHECK-NEXT: .section .debug_info
; CHECK-NEXT: {
; CHECK-NEXT:.b32 10039 // Length of Unit
; CHECK-NEXT:.b32 10029 // Length of Unit
; CHECK-NEXT:.b8 2 // DWARF version number
; CHECK-NEXT:.b8 0
; CHECK-NEXT:.b32 .debug_abbrev // Offset Into Abbrev. Section
; CHECK-NEXT:.b8 8 // Address Size (in bytes)
; CHECK-NEXT:.b8 1 // Abbrev [1] 0xb:0x2730 DW_TAG_compile_unit
; CHECK-NEXT:.b8 1 // Abbrev [1] 0xb:0x2726 DW_TAG_compile_unit
; CHECK-NEXT:.b8 0 // DW_AT_producer
; CHECK-NEXT:.b8 4 // DW_AT_language
; CHECK-NEXT:.b8 0
Expand Down Expand Up @@ -8306,7 +8306,7 @@ if.end: ; preds = %if.then, %entry
; CHECK-NEXT:.b8 3 // DW_AT_decl_line
; CHECK-NEXT:.b32 3345 // DW_AT_type
; CHECK-NEXT:.b8 0 // End Of Children Mark
; CHECK-NEXT:.b8 40 // Abbrev [40] 0x2671:0xc9 DW_TAG_subprogram
; CHECK-NEXT:.b8 40 // Abbrev [40] 0x2671:0xbf DW_TAG_subprogram
; CHECK-NEXT:.b64 Lfunc_begin0 // DW_AT_low_pc
; CHECK-NEXT:.b64 Lfunc_end0 // DW_AT_high_pc
; CHECK-NEXT:.b8 1 // DW_AT_frame_base
Expand Down Expand Up @@ -8386,19 +8386,15 @@ if.end: ; preds = %if.then, %entry
; CHECK-NEXT:.b8 12 // DW_AT_call_file
; CHECK-NEXT:.b8 6 // DW_AT_call_line
; CHECK-NEXT:.b8 37 // DW_AT_call_column
; CHECK-NEXT:.b8 43 // Abbrev [43] 0x2711:0x28 DW_TAG_inlined_subroutine
; CHECK-NEXT:.b8 43 // Abbrev [43] 0x2711:0x1e DW_TAG_inlined_subroutine
; CHECK-NEXT:.b32 9791 // DW_AT_abstract_origin
; CHECK-NEXT:.b64 Ltmp9 // DW_AT_low_pc
; CHECK-NEXT:.b64 Ltmp10 // DW_AT_high_pc
; CHECK-NEXT:.b8 12 // DW_AT_call_file
; CHECK-NEXT:.b8 8 // DW_AT_call_line
; CHECK-NEXT:.b8 5 // DW_AT_call_column
; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2729:0x5 DW_TAG_formal_parameter
; CHECK-NEXT:.b32 9811 // DW_AT_abstract_origin
; CHECK-NEXT:.b8 44 // Abbrev [44] 0x272e:0x5 DW_TAG_formal_parameter
; CHECK-NEXT:.b32 9820 // DW_AT_abstract_origin
; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2733:0x5 DW_TAG_formal_parameter
; CHECK-NEXT:.b32 9829 // DW_AT_abstract_origin
; CHECK-NEXT:.b8 0 // End Of Children Mark
; CHECK-NEXT:.b8 0 // End Of Children Mark
; CHECK-NEXT:.b8 0 // End Of Children Mark
Expand Down
Loading

0 comments on commit 1d68e0a

Please sign in to comment.