<div dir="ltr">Have you done some data gathering to see how true this sort of thing holds?<br><br>I'd worry hat at different optimization levels, some compilers (clang... ) might lose variables entirely & thus omit their scopes, so the scope counts wouldn't be consistent between different object files/optimization levels, perhaps?<br><br>Not 100% sure - just a possibility/curious.<br><br>Not sure there's anything you could do about that, though... so maybe this is as good as it gets.<br><br>The test case looks maybe a bit more complicated than it needs to be - does it not reproduce with a non-template inline function, for example?</div><br><div class="gmail_quote"><div dir="ltr">On Fri, Sep 21, 2018 at 3:00 PM Adrian Prantl via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: adrian<br>
Date: Fri Sep 21 14:59:34 2018<br>
New Revision: 342776<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=342776&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=342776&view=rev</a><br>
Log:<br>
llvm-dwarfdump --statistics: Unique abstract origins across multiple CUs.<br>
<br>
Instead of indexing local variables by DIE offset, use the variable<br>
name + the path through the lexical block tree. This makes the lookup<br>
key consistent across duplicate abstract origins in different CUs.<br>
<br>
Added:<br>
    llvm/trunk/test/tools/llvm-dwarfdump/X86/stats-inlining-multi-cu.ll<br>
    llvm/trunk/test/tools/llvm-dwarfdump/X86/stats-inlining-single-cu.ll<br>
Modified:<br>
    llvm/trunk/tools/llvm-dwarfdump/Statistics.cpp<br>
<br>
Added: llvm/trunk/test/tools/llvm-dwarfdump/X86/stats-inlining-multi-cu.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-dwarfdump/X86/stats-inlining-multi-cu.ll?rev=342776&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-dwarfdump/X86/stats-inlining-multi-cu.ll?rev=342776&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/tools/llvm-dwarfdump/X86/stats-inlining-multi-cu.ll (added)<br>
+++ llvm/trunk/test/tools/llvm-dwarfdump/X86/stats-inlining-multi-cu.ll Fri Sep 21 14:59:34 2018<br>
@@ -0,0 +1,193 @@<br>
+; RUN: llc -O0 %s -o - -filetype=obj \<br>
+; RUN:   | llvm-dwarfdump -statistics - | FileCheck %s<br>
+<br>
+; Test that abstract origins in multiple CUs are uniqued.<br>
+<br>
+; CHECK:      "source functions":4,<br>
+; CHECK-SAME: "inlined functions":5,<br>
+; CHECK-SAME: "unique source variables":4<br>
+; CHECK-SAME: "source variables":6<br>
+; CHECK-SAME: "variables with location":6<br>
+<br>
+;header.h:<br>
+;extern "C" int getchar();<br>
+;template<typename T> T __attribute__((always_inline)) inlined() {<br>
+;  if (getchar()=='a') {<br>
+;    int i = getchar();<br>
+;    return i;<br>
+;  } else {<br>
+;    int i = 'a';<br>
+;    return i;<br>
+;  }<br>
+;}<br>
+;b.cpp:<br>
+;#include <header.h><br>
+;int b() {<br>
+;  int b = inlined<int>();<br>
+;  return b+1;<br>
+;}<br>
+;a.cpp<br>
+;#include <header.h><br>
+;int b();<br>
+;int a() {<br>
+;  int a = inlined<int>();<br>
+;  return a+1;<br>
+;}<br>
+; <br>
+;int main() {<br>
+;  return a() + b();<br>
+;}<br>
+<br>
+; ModuleID = 'linked.ll'<br>
+source_filename = "llvm-link"<br>
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"<br>
+target triple = "x86_64-apple-macosx10.14.0"<br>
+<br>
+; Function Attrs: noinline optnone ssp uwtable<br>
+define i32 @_Z1av() #0 !dbg !10 {<br>
+entry:<br>
+  %retval.i = alloca i32, align 4<br>
+  %i.i = alloca i32, align 4<br>
+  call void @llvm.dbg.declare(metadata i32* %i.i, metadata !14, metadata !DIExpression()), !dbg !21<br>
+  %i2.i = alloca i32, align 4<br>
+  call void @llvm.dbg.declare(metadata i32* %i2.i, metadata !23, metadata !DIExpression()), !dbg !25<br>
+  %a = alloca i32, align 4<br>
+  call void @llvm.dbg.declare(metadata i32* %a, metadata !26, metadata !DIExpression()), !dbg !27<br>
+  %call.i = call i32 @getchar(), !dbg !28<br>
+  %cmp.i = icmp eq i32 %call.i, 97, !dbg !28<br>
+  br i1 %cmp.i, label %if.then.i, label %if.else.i, !dbg !29<br>
+<br>
+if.then.i:                                        ; preds = %entry<br>
+  %call1.i = call i32 @getchar(), !dbg !21<br>
+  store i32 %call1.i, i32* %i.i, align 4, !dbg !21<br>
+  %0 = load i32, i32* %i.i, align 4, !dbg !30<br>
+  store i32 %0, i32* %retval.i, align 4, !dbg !30<br>
+  br label %_Z7inlinedIiET_v.exit, !dbg !30<br>
+<br>
+if.else.i:                                        ; preds = %entry<br>
+  store i32 97, i32* %i2.i, align 4, !dbg !25<br>
+  %1 = load i32, i32* %i2.i, align 4, !dbg !31<br>
+  store i32 %1, i32* %retval.i, align 4, !dbg !31<br>
+  br label %_Z7inlinedIiET_v.exit, !dbg !31<br>
+<br>
+_Z7inlinedIiET_v.exit:                            ; preds = %if.else.i, %if.then.i<br>
+  %2 = load i32, i32* %retval.i, align 4, !dbg !32<br>
+  store i32 %2, i32* %a, align 4, !dbg !27<br>
+  %3 = load i32, i32* %a, align 4, !dbg !33<br>
+  %add = add nsw i32 %3, 1, !dbg !33<br>
+  ret i32 %add, !dbg !33<br>
+}<br>
+<br>
+; Function Attrs: nounwind readnone speculatable<br>
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1<br>
+<br>
+declare i32 @getchar()<br>
+<br>
+; Function Attrs: noinline norecurse optnone ssp uwtable<br>
+define i32 @main() #3 !dbg !34 {<br>
+entry:<br>
+  %retval = alloca i32, align 4<br>
+  store i32 0, i32* %retval, align 4<br>
+  %call = call i32 @_Z1av(), !dbg !35<br>
+  %call1 = call i32 @_Z1bv(), !dbg !35<br>
+  %add = add nsw i32 %call, %call1, !dbg !35<br>
+  ret i32 %add, !dbg !35<br>
+}<br>
+<br>
+; Function Attrs: noinline optnone ssp uwtable<br>
+define i32 @_Z1bv() #0 !dbg !36 {<br>
+entry:<br>
+  %retval.i = alloca i32, align 4<br>
+  %i.i = alloca i32, align 4<br>
+  call void @llvm.dbg.declare(metadata i32* %i.i, metadata !37, metadata !DIExpression()), !dbg !41<br>
+  %i2.i = alloca i32, align 4<br>
+  call void @llvm.dbg.declare(metadata i32* %i2.i, metadata !43, metadata !DIExpression()), !dbg !45<br>
+  %b = alloca i32, align 4<br>
+  call void @llvm.dbg.declare(metadata i32* %b, metadata !46, metadata !DIExpression()), !dbg !47<br>
+  %call.i = call i32 @getchar(), !dbg !48<br>
+  %cmp.i = icmp eq i32 %call.i, 97, !dbg !48<br>
+  br i1 %cmp.i, label %if.then.i, label %if.else.i, !dbg !49<br>
+<br>
+if.then.i:                                        ; preds = %entry<br>
+  %call1.i = call i32 @getchar(), !dbg !41<br>
+  store i32 %call1.i, i32* %i.i, align 4, !dbg !41<br>
+  %0 = load i32, i32* %i.i, align 4, !dbg !50<br>
+  store i32 %0, i32* %retval.i, align 4, !dbg !50<br>
+  br label %_Z7inlinedIiET_v.exit, !dbg !50<br>
+<br>
+if.else.i:                                        ; preds = %entry<br>
+  store i32 97, i32* %i2.i, align 4, !dbg !45<br>
+  %1 = load i32, i32* %i2.i, align 4, !dbg !51<br>
+  store i32 %1, i32* %retval.i, align 4, !dbg !51<br>
+  br label %_Z7inlinedIiET_v.exit, !dbg !51<br>
+<br>
+_Z7inlinedIiET_v.exit:                            ; preds = %if.else.i, %if.then.i<br>
+  %2 = load i32, i32* %retval.i, align 4, !dbg !52<br>
+  store i32 %2, i32* %b, align 4, !dbg !47<br>
+  %3 = load i32, i32* %b, align 4, !dbg !53<br>
+  %add = add nsw i32 %3, 1, !dbg !53<br>
+  ret i32 %add, !dbg !53<br>
+}<br>
+<br>
+attributes #0 = { noinline optnone ssp uwtable }<br>
+attributes #1 = { nounwind readnone speculatable }<br>
+attributes #3 = { noinline norecurse optnone ssp uwtable }<br>
+<br>
+!<a href="http://llvm.dbg.cu" rel="noreferrer" target="_blank">llvm.dbg.cu</a> = !{!0, !3}<br>
+!llvm.ident = !{!5, !5}<br>
+!llvm.module.flags = !{!6, !7, !8, !9}<br>
+<br>
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 8.0.0 (trunk 340541) (llvm/trunk 340540)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)<br>
+!1 = !DIFile(filename: "a.cpp", directory: "/tmp")<br>
+!2 = !{}<br>
+!3 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !4, producer: "clang version 8.0.0 (trunk 340541) (llvm/trunk 340540)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)<br>
+!4 = !DIFile(filename: "b.cpp", directory: "/tmp")<br>
+!5 = !{!"clang version 8.0.0 (trunk 340541) (llvm/trunk 340540)"}<br>
+!6 = !{i32 2, !"Dwarf Version", i32 4}<br>
+!7 = !{i32 2, !"Debug Info Version", i32 3}<br>
+!8 = !{i32 1, !"wchar_size", i32 4}<br>
+!9 = !{i32 7, !"PIC Level", i32 2}<br>
+!10 = distinct !DISubprogram(name: "a", linkageName: "_Z1av", scope: !1, file: !1, line: 3, type: !11, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)<br>
+!11 = !DISubroutineType(types: !12)<br>
+!12 = !{!13}<br>
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)<br>
+!14 = !DILocalVariable(name: "i", scope: !15, file: !16, line: 4, type: !13)<br>
+!15 = distinct !DILexicalBlock(scope: !17, file: !16, line: 3)<br>
+!16 = !DIFile(filename: "./header.h", directory: "/tmp")<br>
+!17 = distinct !DILexicalBlock(scope: !18, file: !16, line: 3)<br>
+!18 = distinct !DISubprogram(name: "inlined<int>", linkageName: "_Z7inlinedIiET_v", scope: !16, file: !16, line: 2, type: !11, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !0, templateParams: !19, retainedNodes: !2)<br>
+!19 = !{!20}<br>
+!20 = !DITemplateTypeParameter(name: "T", type: !13)<br>
+!21 = !DILocation(line: 4, scope: !15, inlinedAt: !22)<br>
+!22 = distinct !DILocation(line: 4, scope: !10)<br>
+!23 = !DILocalVariable(name: "i", scope: !24, file: !16, line: 7, type: !13)<br>
+!24 = distinct !DILexicalBlock(scope: !17, file: !16, line: 6)<br>
+!25 = !DILocation(line: 7, scope: !24, inlinedAt: !22)<br>
+!26 = !DILocalVariable(name: "a", scope: !10, file: !1, line: 4, type: !13)<br>
+!27 = !DILocation(line: 4, scope: !10)<br>
+!28 = !DILocation(line: 3, scope: !17, inlinedAt: !22)<br>
+!29 = !DILocation(line: 3, scope: !18, inlinedAt: !22)<br>
+!30 = !DILocation(line: 5, scope: !15, inlinedAt: !22)<br>
+!31 = !DILocation(line: 8, scope: !24, inlinedAt: !22)<br>
+!32 = !DILocation(line: 10, scope: !18, inlinedAt: !22)<br>
+!33 = !DILocation(line: 5, scope: !10)<br>
+!34 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 12, type: !11, isLocal: false, isDefinition: true, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)<br>
+!35 = !DILocation(line: 13, scope: !34)<br>
+!36 = distinct !DISubprogram(name: "b", linkageName: "_Z1bv", scope: !4, file: !4, line: 2, type: !11, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !3, retainedNodes: !2)<br>
+!37 = !DILocalVariable(name: "i", scope: !38, file: !16, line: 4, type: !13)<br>
+!38 = distinct !DILexicalBlock(scope: !39, file: !16, line: 3)<br>
+!39 = distinct !DILexicalBlock(scope: !40, file: !16, line: 3)<br>
+!40 = distinct !DISubprogram(name: "inlined<int>", linkageName: "_Z7inlinedIiET_v", scope: !16, file: !16, line: 2, type: !11, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !3, templateParams: !19, retainedNodes: !2)<br>
+!41 = !DILocation(line: 4, scope: !38, inlinedAt: !42)<br>
+!42 = distinct !DILocation(line: 3, scope: !36)<br>
+!43 = !DILocalVariable(name: "i", scope: !44, file: !16, line: 7, type: !13)<br>
+!44 = distinct !DILexicalBlock(scope: !39, file: !16, line: 6)<br>
+!45 = !DILocation(line: 7, scope: !44, inlinedAt: !42)<br>
+!46 = !DILocalVariable(name: "b", scope: !36, file: !4, line: 3, type: !13)<br>
+!47 = !DILocation(line: 3, scope: !36)<br>
+!48 = !DILocation(line: 3, scope: !39, inlinedAt: !42)<br>
+!49 = !DILocation(line: 3, scope: !40, inlinedAt: !42)<br>
+!50 = !DILocation(line: 5, scope: !38, inlinedAt: !42)<br>
+!51 = !DILocation(line: 8, scope: !44, inlinedAt: !42)<br>
+!52 = !DILocation(line: 10, scope: !40, inlinedAt: !42)<br>
+!53 = !DILocation(line: 4, scope: !36)<br>
<br>
Added: llvm/trunk/test/tools/llvm-dwarfdump/X86/stats-inlining-single-cu.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-dwarfdump/X86/stats-inlining-single-cu.ll?rev=342776&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-dwarfdump/X86/stats-inlining-single-cu.ll?rev=342776&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/tools/llvm-dwarfdump/X86/stats-inlining-single-cu.ll (added)<br>
+++ llvm/trunk/test/tools/llvm-dwarfdump/X86/stats-inlining-single-cu.ll Fri Sep 21 14:59:34 2018<br>
@@ -0,0 +1,185 @@<br>
+; RUN: llc -O0 %s -o - -filetype=obj \<br>
+; RUN:   | llvm-dwarfdump -statistics - | FileCheck %s<br>
+<br>
+; This test serves as a baseline / sanity-check for stats-inlining-multi-cu.ll<br>
+; The results for both tests should be identical.<br>
+<br>
+; CHECK:      "source functions":4,<br>
+; CHECK-SAME: "inlined functions":5,<br>
+; CHECK-SAME: "unique source variables":4<br>
+; CHECK-SAME: "source variables":6<br>
+; CHECK-SAME: "variables with location":6<br>
+<br>
+;header.h:<br>
+;extern "C" int getchar();<br>
+;template<typename T> T __attribute__((always_inline)) inlined() {<br>
+;  if (getchar()=='a') {<br>
+;    int i = getchar();<br>
+;    return i;<br>
+;  } else {<br>
+;    int i = 'a';<br>
+;    return i;<br>
+;  }<br>
+;}<br>
+;ab.cpp<br>
+;#include <header.h><br>
+;int b();<br>
+;int a() {<br>
+;  int a = inlined<int>();<br>
+;  return a+1;<br>
+;}<br>
+; <br>
+;int b() {<br>
+;  int b = inlined<int>();<br>
+;  return b+1;<br>
+;}<br>
+;int main() {<br>
+;  return a() + b();<br>
+;}<br>
+<br>
+<br>
+; ModuleID = 'a.cpp'<br>
+source_filename = "a.cpp"<br>
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"<br>
+target triple = "x86_64-apple-macosx10.14.0"<br>
+<br>
+; Function Attrs: noinline optnone ssp uwtable<br>
+define i32 @_Z1av() #0 !dbg !8 {<br>
+entry:<br>
+  %retval.i = alloca i32, align 4<br>
+  %i.i = alloca i32, align 4<br>
+  call void @llvm.dbg.declare(metadata i32* %i.i, metadata !12, metadata !DIExpression()), !dbg !19<br>
+  %i2.i = alloca i32, align 4<br>
+  call void @llvm.dbg.declare(metadata i32* %i2.i, metadata !21, metadata !DIExpression()), !dbg !23<br>
+  %a = alloca i32, align 4<br>
+  call void @llvm.dbg.declare(metadata i32* %a, metadata !24, metadata !DIExpression()), !dbg !25<br>
+  %call.i = call i32 @getchar(), !dbg !26<br>
+  %cmp.i = icmp eq i32 %call.i, 97, !dbg !26<br>
+  br i1 %cmp.i, label %if.then.i, label %if.else.i, !dbg !27<br>
+<br>
+if.then.i:                                        ; preds = %entry<br>
+  %call1.i = call i32 @getchar(), !dbg !19<br>
+  store i32 %call1.i, i32* %i.i, align 4, !dbg !19<br>
+  %0 = load i32, i32* %i.i, align 4, !dbg !28<br>
+  store i32 %0, i32* %retval.i, align 4, !dbg !28<br>
+  br label %_Z7inlinedIiET_v.exit, !dbg !28<br>
+<br>
+if.else.i:                                        ; preds = %entry<br>
+  store i32 97, i32* %i2.i, align 4, !dbg !23<br>
+  %1 = load i32, i32* %i2.i, align 4, !dbg !29<br>
+  store i32 %1, i32* %retval.i, align 4, !dbg !29<br>
+  br label %_Z7inlinedIiET_v.exit, !dbg !29<br>
+<br>
+_Z7inlinedIiET_v.exit:                            ; preds = %if.then.i, %if.else.i<br>
+  %2 = load i32, i32* %retval.i, align 4, !dbg !30<br>
+  store i32 %2, i32* %a, align 4, !dbg !25<br>
+  %3 = load i32, i32* %a, align 4, !dbg !31<br>
+  %add = add nsw i32 %3, 1, !dbg !31<br>
+  ret i32 %add, !dbg !31<br>
+}<br>
+<br>
+; Function Attrs: nounwind readnone speculatable<br>
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1<br>
+<br>
+; Function Attrs: noinline optnone ssp uwtable<br>
+define i32 @_Z1bv() #0 !dbg !32 {<br>
+entry:<br>
+  %retval.i = alloca i32, align 4<br>
+  %i.i = alloca i32, align 4<br>
+  call void @llvm.dbg.declare(metadata i32* %i.i, metadata !12, metadata !DIExpression()), !dbg !33<br>
+  %i2.i = alloca i32, align 4<br>
+  call void @llvm.dbg.declare(metadata i32* %i2.i, metadata !21, metadata !DIExpression()), !dbg !35<br>
+  %b = alloca i32, align 4<br>
+  call void @llvm.dbg.declare(metadata i32* %b, metadata !36, metadata !DIExpression()), !dbg !37<br>
+  %call.i = call i32 @getchar(), !dbg !38<br>
+  %cmp.i = icmp eq i32 %call.i, 97, !dbg !38<br>
+  br i1 %cmp.i, label %if.then.i, label %if.else.i, !dbg !39<br>
+<br>
+if.then.i:                                        ; preds = %entry<br>
+  %call1.i = call i32 @getchar(), !dbg !33<br>
+  store i32 %call1.i, i32* %i.i, align 4, !dbg !33<br>
+  %0 = load i32, i32* %i.i, align 4, !dbg !40<br>
+  store i32 %0, i32* %retval.i, align 4, !dbg !40<br>
+  br label %_Z7inlinedIiET_v.exit, !dbg !40<br>
+<br>
+if.else.i:                                        ; preds = %entry<br>
+  store i32 97, i32* %i2.i, align 4, !dbg !35<br>
+  %1 = load i32, i32* %i2.i, align 4, !dbg !41<br>
+  store i32 %1, i32* %retval.i, align 4, !dbg !41<br>
+  br label %_Z7inlinedIiET_v.exit, !dbg !41<br>
+<br>
+_Z7inlinedIiET_v.exit:                            ; preds = %if.then.i, %if.else.i<br>
+  %2 = load i32, i32* %retval.i, align 4, !dbg !42<br>
+  store i32 %2, i32* %b, align 4, !dbg !37<br>
+  %3 = load i32, i32* %b, align 4, !dbg !43<br>
+  %add = add nsw i32 %3, 1, !dbg !43<br>
+  ret i32 %add, !dbg !43<br>
+}<br>
+<br>
+; Function Attrs: noinline norecurse optnone ssp uwtable<br>
+define i32 @main() #2 !dbg !44 {<br>
+entry:<br>
+  %retval = alloca i32, align 4<br>
+  store i32 0, i32* %retval, align 4<br>
+  %call = call i32 @_Z1av(), !dbg !45<br>
+  %call1 = call i32 @_Z1bv(), !dbg !45<br>
+  %add = add nsw i32 %call, %call1, !dbg !45<br>
+  ret i32 %add, !dbg !45<br>
+}<br>
+<br>
+declare i32 @getchar()<br>
+<br>
+attributes #0 = { noinline optnone ssp uwtable }<br>
+attributes #1 = { nounwind readnone speculatable }<br>
+attributes #2 = { noinline norecurse optnone ssp uwtable }<br>
+<br>
+!<a href="http://llvm.dbg.cu" rel="noreferrer" target="_blank">llvm.dbg.cu</a> = !{!0}<br>
+!llvm.module.flags = !{!3, !4, !5, !6}<br>
+!llvm.ident = !{!7}<br>
+<br>
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 8.0.0 (trunk 340541) (llvm/trunk 340540)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)<br>
+!1 = !DIFile(filename: "a.cpp", directory: "/tmp")<br>
+!2 = !{}<br>
+!3 = !{i32 2, !"Dwarf Version", i32 4}<br>
+!4 = !{i32 2, !"Debug Info Version", i32 3}<br>
+!5 = !{i32 1, !"wchar_size", i32 4}<br>
+!6 = !{i32 7, !"PIC Level", i32 2}<br>
+!7 = !{!"clang version 8.0.0 (trunk 340541) (llvm/trunk 340540)"}<br>
+!8 = distinct !DISubprogram(name: "a", linkageName: "_Z1av", scope: !1, file: !1, line: 3, type: !9, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)<br>
+!9 = !DISubroutineType(types: !10)<br>
+!10 = !{!11}<br>
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)<br>
+!12 = !DILocalVariable(name: "i", scope: !13, file: !14, line: 4, type: !11)<br>
+!13 = distinct !DILexicalBlock(scope: !15, file: !14, line: 3)<br>
+!14 = !DIFile(filename: "./header.h", directory: "/tmp")<br>
+!15 = distinct !DILexicalBlock(scope: !16, file: !14, line: 3)<br>
+!16 = distinct !DISubprogram(name: "inlined<int>", linkageName: "_Z7inlinedIiET_v", scope: !14, file: !14, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !0, templateParams: !17, retainedNodes: !2)<br>
+!17 = !{!18}<br>
+!18 = !DITemplateTypeParameter(name: "T", type: !11)<br>
+!19 = !DILocation(line: 4, scope: !13, inlinedAt: !20)<br>
+!20 = distinct !DILocation(line: 4, scope: !8)<br>
+!21 = !DILocalVariable(name: "i", scope: !22, file: !14, line: 7, type: !11)<br>
+!22 = distinct !DILexicalBlock(scope: !15, file: !14, line: 6)<br>
+!23 = !DILocation(line: 7, scope: !22, inlinedAt: !20)<br>
+!24 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 4, type: !11)<br>
+!25 = !DILocation(line: 4, scope: !8)<br>
+!26 = !DILocation(line: 3, scope: !15, inlinedAt: !20)<br>
+!27 = !DILocation(line: 3, scope: !16, inlinedAt: !20)<br>
+!28 = !DILocation(line: 5, scope: !13, inlinedAt: !20)<br>
+!29 = !DILocation(line: 8, scope: !22, inlinedAt: !20)<br>
+!30 = !DILocation(line: 10, scope: !16, inlinedAt: !20)<br>
+!31 = !DILocation(line: 5, scope: !8)<br>
+!32 = distinct !DISubprogram(name: "b", linkageName: "_Z1bv", scope: !1, file: !1, line: 8, type: !9, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)<br>
+!33 = !DILocation(line: 4, scope: !13, inlinedAt: !34)<br>
+!34 = distinct !DILocation(line: 9, scope: !32)<br>
+!35 = !DILocation(line: 7, scope: !22, inlinedAt: !34)<br>
+!36 = !DILocalVariable(name: "b", scope: !32, file: !1, line: 9, type: !11)<br>
+!37 = !DILocation(line: 9, scope: !32)<br>
+!38 = !DILocation(line: 3, scope: !15, inlinedAt: !34)<br>
+!39 = !DILocation(line: 3, scope: !16, inlinedAt: !34)<br>
+!40 = !DILocation(line: 5, scope: !13, inlinedAt: !34)<br>
+!41 = !DILocation(line: 8, scope: !22, inlinedAt: !34)<br>
+!42 = !DILocation(line: 10, scope: !16, inlinedAt: !34)<br>
+!43 = !DILocation(line: 10, scope: !32)<br>
+!44 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 12, type: !9, isLocal: false, isDefinition: true, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)<br>
+!45 = !DILocation(line: 13, scope: !44)<br>
<br>
Modified: llvm/trunk/tools/llvm-dwarfdump/Statistics.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-dwarfdump/Statistics.cpp?rev=342776&r1=342775&r2=342776&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-dwarfdump/Statistics.cpp?rev=342776&r1=342775&r2=342776&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-dwarfdump/Statistics.cpp (original)<br>
+++ llvm/trunk/tools/llvm-dwarfdump/Statistics.cpp Fri Sep 21 14:59:34 2018<br>
@@ -1,4 +1,6 @@<br>
 #include "llvm/ADT/DenseMap.h"<br>
+#include "llvm/ADT/StringExtras.h"<br>
+#include "llvm/ADT/StringSet.h"<br>
 #include "llvm/DebugInfo/DIContext.h"<br>
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"<br>
 #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"<br>
@@ -18,7 +20,7 @@ struct PerFunctionStats {<br>
   /// Number of constants with location across all inlined instances.<br>
   unsigned ConstantMembers = 0;<br>
   /// List of all Variables in this function.<br>
-  SmallDenseSet<uint32_t, 4> VarsInFunction;<br>
+  StringSet<> VarsInFunction;<br>
   /// Compile units also cover a PC range, but have this flag set to false.<br>
   bool IsFunction = false;<br>
 };<br>
@@ -46,19 +48,31 @@ static uint64_t getLowPC(DWARFDie Die) {<br>
 }<br>
<br>
 /// Collect debug info quality metrics for one DIE.<br>
-static void collectStatsForDie(DWARFDie Die, std::string Prefix,<br>
-                               uint64_t ScopeLowPC, uint64_t BytesInScope,<br>
+static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,<br>
+                               std::string VarPrefix, uint64_t ScopeLowPC,<br>
+                               uint64_t BytesInScope,<br>
                                StringMap<PerFunctionStats> &FnStatMap,<br>
                                GlobalStats &GlobalStats) {<br>
   bool HasLoc = false;<br>
   uint64_t BytesCovered = 0;<br>
   uint64_t OffsetToFirstDefinition = 0;<br>
+<br>
+  if (Die.getTag() != dwarf::DW_TAG_formal_parameter &&<br>
+      Die.getTag() != dwarf::DW_TAG_variable &&<br>
+      Die.getTag() != dwarf::DW_TAG_member) {<br>
+    // Not a variable or constant member.<br>
+    return;<br>
+  }<br>
+<br>
   if (Die.find(dwarf::DW_AT_const_value)) {<br>
     // This catches constant members *and* variables.<br>
     HasLoc = true;<br>
     BytesCovered = BytesInScope;<br>
-  } else if (Die.getTag() == dwarf::DW_TAG_variable ||<br>
-             Die.getTag() == dwarf::DW_TAG_formal_parameter) {<br>
+  } else {<br>
+    if (Die.getTag() == dwarf::DW_TAG_member) {<br>
+      // Non-const member.<br>
+      return;<br>
+    }<br>
     // Handle variables and function arguments.<br>
     auto FormValue = Die.find(dwarf::DW_AT_location);<br>
     HasLoc = FormValue.hasValue();<br>
@@ -86,19 +100,17 @@ static void collectStatsForDie(DWARFDie<br>
         BytesCovered = BytesInScope;<br>
       }<br>
     }<br>
-  } else {<br>
-    // Not a variable or constant member.<br>
-    return;<br>
   }<br>
<br>
   // Collect PC range coverage data.<br>
-  auto &FnStats = FnStatMap[Prefix];<br>
+  auto &FnStats = FnStatMap[FnPrefix];<br>
   if (DWARFDie D =<br>
           Die.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin))<br>
     Die = D;<br>
-  // This is a unique ID for the variable inside the current object file.<br>
-  unsigned CanonicalDieOffset = Die.getOffset();<br>
-  FnStats.VarsInFunction.insert(CanonicalDieOffset);<br>
+  // By using the variable name + the path through the lexical block tree, the<br>
+  // keys are consistent across duplicate abstract origins in different CUs.<br>
+  std::string VarName = StringRef(Die.getName(DINameKind::ShortName));<br>
+  FnStats.VarsInFunction.insert(VarPrefix+VarName);<br>
   if (BytesInScope) {<br>
     FnStats.TotalVarWithLoc += (unsigned)HasLoc;<br>
     // Adjust for the fact the variables often start their lifetime in the<br>
@@ -115,14 +127,21 @@ static void collectStatsForDie(DWARFDie<br>
 }<br>
<br>
 /// Recursively collect debug info quality metrics.<br>
-static void collectStatsRecursive(DWARFDie Die, std::string Prefix,<br>
-                                  uint64_t ScopeLowPC, uint64_t BytesInScope,<br>
+static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix,<br>
+                                  std::string VarPrefix, uint64_t ScopeLowPC,<br>
+                                  uint64_t BytesInScope,<br>
                                   StringMap<PerFunctionStats> &FnStatMap,<br>
                                   GlobalStats &GlobalStats) {<br>
   // Handle any kind of lexical scope.<br>
   if (Die.getTag() == dwarf::DW_TAG_subprogram ||<br>
       Die.getTag() == dwarf::DW_TAG_inlined_subroutine ||<br>
       Die.getTag() == dwarf::DW_TAG_lexical_block) {<br>
+<br>
+    // Reset VarPrefix when entering a new function.<br>
+    if (Die.getTag() == dwarf::DW_TAG_subprogram ||<br>
+        Die.getTag() == dwarf::DW_TAG_inlined_subroutine)<br>
+      VarPrefix = "v";<br>
+  <br>
     // Ignore forward declarations.<br>
     if (Die.find(dwarf::DW_AT_declaration))<br>
       return;<br>
@@ -132,7 +151,7 @@ static void collectStatsRecursive(DWARFD<br>
       StringRef Name = Die.getName(DINameKind::LinkageName);<br>
       if (Name.empty())<br>
         Name = Die.getName(DINameKind::ShortName);<br>
-      Prefix = Name;<br>
+      FnPrefix = Name;<br>
       // Skip over abstract origins.<br>
       if (Die.find(dwarf::DW_AT_inline))<br>
         return;<br>
@@ -159,15 +178,20 @@ static void collectStatsRecursive(DWARFD<br>
       BytesInScope = BytesInThisScope;<br>
   } else {<br>
     // Not a scope, visit the Die itself. It could be a variable.<br>
-    collectStatsForDie(Die, Prefix, ScopeLowPC, BytesInScope, FnStatMap,<br>
-                       GlobalStats);<br>
+    collectStatsForDie(Die, FnPrefix, VarPrefix, ScopeLowPC, BytesInScope,<br>
+                       FnStatMap, GlobalStats);<br>
   }<br>
<br>
   // Traverse children.<br>
+  unsigned LexicalBlockIndex = 0;<br>
   DWARFDie Child = Die.getFirstChild();<br>
   while (Child) {<br>
-    collectStatsRecursive(Child, Prefix, ScopeLowPC, BytesInScope, FnStatMap,<br>
-                          GlobalStats);<br>
+    std::string ChildVarPrefix = VarPrefix;<br>
+    if (Child.getTag() == dwarf::DW_TAG_lexical_block)<br>
+      ChildVarPrefix += toHex(LexicalBlockIndex++) + '.';<br>
+<br>
+    collectStatsRecursive(Child, FnPrefix, ChildVarPrefix, ScopeLowPC,<br>
+                          BytesInScope, FnStatMap, GlobalStats);<br>
     Child = Child.getSibling();<br>
   }<br>
 }<br>
@@ -200,7 +224,7 @@ bool collectStatsForObjectFile(ObjectFil<br>
   StringMap<PerFunctionStats> Statistics;<br>
   for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units())<br>
     if (DWARFDie CUDie = CU->getUnitDIE(false))<br>
-      collectStatsRecursive(CUDie, "/", 0, 0, Statistics, GlobalStats);<br>
+      collectStatsRecursive(CUDie, "/", "g", 0, 0, Statistics, GlobalStats);<br>
<br>
   /// The version number should be increased every time the algorithm is changed<br>
   /// (including bug fixes). New metrics may be added without increasing the<br>
@@ -218,9 +242,8 @@ bool collectStatsForObjectFile(ObjectFil<br>
     VarWithLoc += Stats.TotalVarWithLoc + Constants;<br>
     VarTotal += TotalVars + Constants;<br>
     VarUnique += Stats.VarsInFunction.size();<br>
-    LLVM_DEBUG(for (auto V<br>
-                    : Stats.VarsInFunction) llvm::dbgs()<br>
-               << Entry.getKey() << ": " << V << "\n");<br>
+    LLVM_DEBUG(for (auto &V : Stats.VarsInFunction) llvm::dbgs()<br>
+               << Entry.getKey() << ": " << V.getKey() << "\n");<br>
     NumFunctions += Stats.IsFunction;<br>
     NumInlinedFunctions += Stats.IsFunction * Stats.NumFnInlined;<br>
   }<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div>