Skip to content

Commit 2ef18fb

Browse files
committed
Reland "[utils] Implement the llvm-locstats tool"
The tool reports verbose output for the DWARF debug location coverage. The llvm-locstats for each variable or formal parameter DIE computes what percentage from the code section bytes, where it is in scope, it has location description. The line 0 shows the number (and the percentage) of DIEs with no location information, but the line 100 shows the number (and the percentage) of DIEs where there is location information in all code section bytes (where the variable or parameter is in the scope). The line 50..59 shows the number (and the percentage) of DIEs where the location information is in between 50 and 59 percentage of its scope covered. Differential Revision: https://reviews.llvm.org/D66526 The cause of the test failure was resolved. llvm-svn: 373427
1 parent 60e9df3 commit 2ef18fb

File tree

8 files changed

+481
-0
lines changed

8 files changed

+481
-0
lines changed

llvm/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -1097,3 +1097,7 @@ if (LLVM_INCLUDE_BENCHMARKS)
10971097
add_subdirectory(utils/benchmark)
10981098
add_subdirectory(benchmarks)
10991099
endif()
1100+
1101+
if (LLVM_INCLUDE_UTILS AND LLVM_INCLUDE_TOOLS)
1102+
add_subdirectory(utils/llvm-locstats)
1103+
endif()

llvm/docs/CommandGuide/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,4 @@ Developer Tools
7474
llvm-build
7575
llvm-exegesis
7676
llvm-pdbutil
77+
llvm-locstats
+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
llvm-locstats - calculate statistics on DWARF debug location
2+
============================================================
3+
4+
.. program:: llvm-locstats
5+
6+
SYNOPSIS
7+
--------
8+
9+
:program:`llvm-locstats` [*options*] [*filename*]
10+
11+
DESCRIPTION
12+
-----------
13+
14+
:program:`llvm-locstats` works like a wrapper around :program:`llvm-dwarfdump`.
15+
It parses :program:`llvm-dwarfdump` statistics regarding debug location by
16+
pretty printing it in a more human readable way.
17+
18+
The line 0% shows the number and the percentage of DIEs with no location
19+
information, but the line 100% shows the information for DIEs where there is
20+
location information in all code section bytes (where the variable or parameter
21+
is in the scope). The line 50-59% shows the number and the percentage of DIEs
22+
where the location information is between 50 and 59 percentage of its scope
23+
covered.
24+
25+
OPTIONS
26+
-------
27+
28+
.. option:: -only-variables
29+
30+
Calculate the location statistics only for local variables.
31+
32+
.. option:: -only-formal-parameters
33+
34+
Calculate the location statistics only for formal parameters.
35+
36+
.. option:: -ignore-debug-entry-values
37+
38+
Ignore the location statistics on locations containing the
39+
debug entry values DWARF operation.
40+
41+
EXIT STATUS
42+
-----------
43+
44+
:program:`llvm-locstats` returns 0 if the input file were parsed
45+
successfully. Otherwise, it returns 1.
46+
47+
OUTPUT EXAMPLE
48+
--------------
49+
50+
.. code-block:: none
51+
52+
=================================================
53+
Debug Location Statistics
54+
=================================================
55+
cov% samples percentage(~)
56+
-------------------------------------------------
57+
0% 1 16%
58+
1-9% 0 0%
59+
10-19% 0 0%
60+
20-29% 0 0%
61+
30-39% 0 0%
62+
40-49% 0 0%
63+
50-99% 1 16%
64+
60-69% 0 0%
65+
70-79% 0 0%
66+
80-89% 1 16%
67+
90-99% 0 0%
68+
100% 3 50%
69+
=================================================
70+
-the number of debug variables processed: 6
71+
-PC ranges covered: 81%
72+
-------------------------------------------------
73+
-total availability: 83%
74+
=================================================
75+
76+
SEE ALSO
77+
--------
78+
79+
:manpage:`llvm-dwarfdump(1)`

llvm/test/lit.cfg.py

+5
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ def get_asan_rtlib():
124124

125125
opt_viewer_cmd = '%s %s/tools/opt-viewer/opt-viewer.py' % (sys.executable, config.llvm_src_root)
126126

127+
llvm_locstats_tool = os.path.join(config.llvm_tools_dir, 'llvm-locstats')
128+
config.substitutions.append(
129+
('%llvm-locstats', "'%s' %s" % (config.python_executable, llvm_locstats_tool)))
130+
config.llvm_locstats_used = os.path.exists(llvm_locstats_tool)
131+
127132
tools = [
128133
ToolSubst('%lli', FindTool('lli'), post='.', extra_args=lli_args),
129134
ToolSubst('%llc_dwarf', FindTool('llc'), extra_args=llc_args),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
if not config.llvm_locstats_used:
2+
config.unsupported = True
+175
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
; UNSUPPORTED: system-windows
2+
; REQUIRES: x86-registered-target
3+
; RUN: llc %s -o %t0.o -filetype=obj
4+
; RUN: %llvm-locstats %t0.o | FileCheck %s --check-prefix=LOCSTATS
5+
;
6+
; Test the llvm-locstats output.
7+
; LOCSTATS: 0% 0 0%
8+
; LOCSTATS: 1-9% 0 0%
9+
; LOCSTATS: 10-19% 0 0%
10+
; LOCSTATS: 20-29% 1 11%
11+
; LOCSTATS: 30-39% 0 0%
12+
; LOCSTATS: 40-49% 1 11%
13+
; LOCSTATS: 50-59% 1 11%
14+
; LOCSTATS: 60-69% 1 11%
15+
; LOCSTATS: 70-79% 0 0%
16+
; LOCSTATS: 80-89% 2 22%
17+
; LOCSTATS: 90-99% 1 11%
18+
; LOCSTATS: 100% 2 22%
19+
;
20+
; The source code of the test case:
21+
;extern int fn2 (int);
22+
;
23+
;__attribute__((noinline))
24+
;int
25+
;fn1 (int *x, int *y)
26+
;{
27+
; int a = *x;
28+
; int b = *y;
29+
; int local = a + b;
30+
; if (a > 1) {
31+
; local += 2;
32+
; ++local;
33+
; if (local > 200)
34+
; local -= fn2(a);
35+
; } else {
36+
; local += 3;
37+
; ++local;
38+
; local += fn2(a);
39+
; }
40+
; if (b > 4)
41+
; local += a;
42+
; int local2 = 7;
43+
; local -= fn2 (local2);
44+
; return local;
45+
;}
46+
;
47+
;__attribute__((noinline))
48+
;int f()
49+
;{
50+
; int l, k;
51+
; int res = 0;
52+
; res += fn1 (&l, &k);
53+
; return res;
54+
;}
55+
;
56+
; ModuleID = 'locstats.c'
57+
source_filename = "locstats.c"
58+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
59+
target triple = "x86_64-unknown-linux-gnu"
60+
61+
; Function Attrs: noinline nounwind uwtable
62+
define dso_local i32 @fn1(i32* nocapture readonly %0, i32* nocapture readonly %1) local_unnamed_addr !dbg !7 {
63+
call void @llvm.dbg.value(metadata i32* %0, metadata !13, metadata !DIExpression()), !dbg !19
64+
call void @llvm.dbg.value(metadata i32* %1, metadata !14, metadata !DIExpression()), !dbg !19
65+
%3 = load i32, i32* %0, align 4, !dbg !20
66+
call void @llvm.dbg.value(metadata i32 %3, metadata !15, metadata !DIExpression()), !dbg !19
67+
%4 = load i32, i32* %1, align 4, !dbg !20
68+
call void @llvm.dbg.value(metadata i32 %4, metadata !16, metadata !DIExpression()), !dbg !19
69+
%5 = add nsw i32 %4, %3, !dbg !20
70+
call void @llvm.dbg.value(metadata i32 %5, metadata !17, metadata !DIExpression()), !dbg !19
71+
%6 = icmp sgt i32 %3, 1, !dbg !20
72+
br i1 %6, label %7, label %13, !dbg !22
73+
74+
7: ; preds = %2
75+
call void @llvm.dbg.value(metadata i32 %5, metadata !17, metadata !DIExpression(DW_OP_plus_uconst, 2, DW_OP_stack_value)), !dbg !19
76+
%8 = add nsw i32 %5, 3, !dbg !23
77+
call void @llvm.dbg.value(metadata i32 %8, metadata !17, metadata !DIExpression()), !dbg !19
78+
%9 = icmp sgt i32 %8, 200, !dbg !25
79+
br i1 %9, label %10, label %17, !dbg !27
80+
81+
10: ; preds = %7
82+
%11 = tail call i32 @fn2(i32 %3), !dbg !27
83+
%12 = sub nsw i32 %8, %11, !dbg !27
84+
call void @llvm.dbg.value(metadata i32 %12, metadata !17, metadata !DIExpression()), !dbg !19
85+
br label %17, !dbg !27
86+
87+
13: ; preds = %2
88+
call void @llvm.dbg.value(metadata i32 %5, metadata !17, metadata !DIExpression(DW_OP_plus_uconst, 3, DW_OP_stack_value)), !dbg !19
89+
%14 = add nsw i32 %5, 4, !dbg !28
90+
call void @llvm.dbg.value(metadata i32 %14, metadata !17, metadata !DIExpression()), !dbg !19
91+
%15 = tail call i32 @fn2(i32 %3), !dbg !30
92+
%16 = add nsw i32 %14, %15, !dbg !30
93+
call void @llvm.dbg.value(metadata i32 %16, metadata !17, metadata !DIExpression()), !dbg !19
94+
br label %17
95+
96+
17: ; preds = %7, %10, %13
97+
%18 = phi i32 [ %12, %10 ], [ %8, %7 ], [ %16, %13 ], !dbg !31
98+
call void @llvm.dbg.value(metadata i32 %18, metadata !17, metadata !DIExpression()), !dbg !19
99+
%19 = icmp sgt i32 %4, 4, !dbg !32
100+
%20 = select i1 %19, i32 %3, i32 0, !dbg !34
101+
%21 = add nsw i32 %18, %20, !dbg !34
102+
call void @llvm.dbg.value(metadata i32 %21, metadata !17, metadata !DIExpression()), !dbg !19
103+
call void @llvm.dbg.value(metadata i32 7, metadata !18, metadata !DIExpression()), !dbg !19
104+
%22 = tail call i32 @fn2(i32 7), !dbg !34
105+
%23 = sub i32 %21, %22, !dbg !34
106+
call void @llvm.dbg.value(metadata i32 %23, metadata !17, metadata !DIExpression()), !dbg !19
107+
ret i32 %23, !dbg !34
108+
}
109+
110+
declare dso_local i32 @fn2(i32) local_unnamed_addr
111+
112+
; Function Attrs: noinline nounwind uwtable
113+
define dso_local i32 @f() local_unnamed_addr !dbg !35 {
114+
%1 = alloca i32, align 4
115+
%2 = alloca i32, align 4
116+
%3 = bitcast i32* %1 to i8*, !dbg !42
117+
%4 = bitcast i32* %2 to i8*, !dbg !42
118+
call void @llvm.dbg.value(metadata i32 0, metadata !41, metadata !DIExpression()), !dbg !42
119+
call void @llvm.dbg.value(metadata i32* %1, metadata !39, metadata !DIExpression(DW_OP_deref)), !dbg !42
120+
call void @llvm.dbg.value(metadata i32* %2, metadata !40, metadata !DIExpression(DW_OP_deref)), !dbg !42
121+
%5 = call i32 @fn1(i32* nonnull %1, i32* nonnull %2), !dbg !42
122+
call void @llvm.dbg.value(metadata i32 %5, metadata !41, metadata !DIExpression()), !dbg !42
123+
ret i32 %5, !dbg !42
124+
}
125+
126+
; Function Attrs: nounwind readnone speculatable willreturn
127+
declare void @llvm.dbg.value(metadata, metadata, metadata)
128+
129+
!llvm.dbg.cu = !{!0}
130+
!llvm.module.flags = !{!3, !4, !5}
131+
!llvm.ident = !{!6}
132+
133+
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
134+
!1 = !DIFile(filename: "locstats.c", directory: "/dir")
135+
!2 = !{}
136+
!3 = !{i32 2, !"Dwarf Version", i32 4}
137+
!4 = !{i32 2, !"Debug Info Version", i32 3}
138+
!5 = !{i32 1, !"wchar_size", i32 4}
139+
!6 = !{!"clang version 10.0.0"}
140+
!7 = distinct !DISubprogram(name: "fn1", scope: !1, file: !1, line: 5, type: !8, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)
141+
!8 = !DISubroutineType(types: !9)
142+
!9 = !{!10, !11, !11}
143+
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
144+
!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64)
145+
!12 = !{!13, !14, !15, !16, !17, !18}
146+
!13 = !DILocalVariable(name: "x", arg: 1, scope: !7, file: !1, line: 5, type: !11)
147+
!14 = !DILocalVariable(name: "y", arg: 2, scope: !7, file: !1, line: 5, type: !11)
148+
!15 = !DILocalVariable(name: "a", scope: !7, file: !1, line: 7, type: !10)
149+
!16 = !DILocalVariable(name: "b", scope: !7, file: !1, line: 8, type: !10)
150+
!17 = !DILocalVariable(name: "local", scope: !7, file: !1, line: 9, type: !10)
151+
!18 = !DILocalVariable(name: "local2", scope: !7, file: !1, line: 22, type: !10)
152+
!19 = !DILocation(line: 0, scope: !7)
153+
!20 = !DILocation(line: 7, column: 11, scope: !7)
154+
!21 = distinct !DILexicalBlock(scope: !7, file: !1, line: 10, column: 7)
155+
!22 = !DILocation(line: 10, column: 7, scope: !7)
156+
!23 = !DILocation(line: 12, column: 5, scope: !24)
157+
!24 = distinct !DILexicalBlock(scope: !21, file: !1, line: 10, column: 14)
158+
!25 = !DILocation(line: 13, column: 15, scope: !26)
159+
!26 = distinct !DILexicalBlock(scope: !24, file: !1, line: 13, column: 9)
160+
!27 = !DILocation(line: 13, column: 9, scope: !24)
161+
!28 = !DILocation(line: 17, column: 5, scope: !26)
162+
!29 = distinct !DILexicalBlock(scope: !21, file: !1, line: 15, column: 10)
163+
!30 = !DILocation(line: 18, column: 14, scope: !29)
164+
!31 = !DILocation(line: 0, scope: !21)
165+
!32 = !DILocation(line: 20, column: 9, scope: !33)
166+
!33 = distinct !DILexicalBlock(scope: !7, file: !1, line: 20, column: 7)
167+
!34 = !DILocation(line: 20, column: 7, scope: !7)
168+
!35 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 28, type: !36, scopeLine: 29, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !38)
169+
!36 = !DISubroutineType(types: !37)
170+
!37 = !{!10}
171+
!38 = !{!39, !40, !41}
172+
!39 = !DILocalVariable(name: "l", scope: !35, file: !1, line: 30, type: !10)
173+
!40 = !DILocalVariable(name: "k", scope: !35, file: !1, line: 30, type: !10)
174+
!41 = !DILocalVariable(name: "res", scope: !35, file: !1, line: 31, type: !10)
175+
!42 = !DILocation(line: 30, column: 3, scope: !35)
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
if (LLVM_BUILD_UTILS AND LLVM_BUILD_TOOLS)
2+
add_custom_target(llvm-locstats ALL
3+
COMMAND ${CMAKE_COMMAND} -E copy ${LLVM_MAIN_SRC_DIR}/utils/llvm-locstats/llvm-locstats.py ${LLVM_TOOLS_BINARY_DIR}/llvm-locstats
4+
COMMENT "Copying llvm-locstats into ${LLVM_TOOLS_BINARY_DIR}"
5+
)
6+
set_target_properties(llvm-locstats PROPERTIES FOLDER "Tools")
7+
endif()

0 commit comments

Comments
 (0)