[llvm] r342776 - llvm-dwarfdump --statistics: Unique abstract origins across multiple CUs.

Adrian Prantl via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 1 14:14:43 PDT 2018



> On Oct 1, 2018, at 1:51 PM, David Blaikie <dblaikie at gmail.com> wrote:
> 
> Have you done some data gathering to see how true this sort of thing holds?
> 
> 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?
> 
> Not 100% sure - just a possibility/curious.

I've been testing this on clang itself and on that data set it's a very large improvement, since every CU comes with its own copy of, e.g., StringRef. Generally, dwarfdump --statistics is a best effort and the purpose is not to yield absolute data, but something that is stable enough to track trends over time. When the devmeeting comes around, I hope to have a bot running that compiles the same source code with every revision and dumps this data into LNT, so we can get notified when the debug info quality changes in either direction.

> 
> Not sure there's anything you could do about that, though... so maybe this is as good as it gets.

We could run the same analysis on an input compiled with -O0 and use that as a baseline, but that would be a lot more complex to setup for the end-user.

> 
> 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?
> 

I tried that at first, but I didn't immediately succeed so I went with the simple template instead. I didn't spend the time to figure out what the difference was though.

-- adrian

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

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20181001/f3fc0b1d/attachment.html>


More information about the llvm-commits mailing list