[llvm] b6db47d - [llvm-dwarfdump][locstats] Unify handling of inlined vars with no loc
Djordje Todorovic via llvm-commits
llvm-commits at lists.llvm.org
Fri Feb 19 05:38:33 PST 2021
Author: Djordje Todorovic
Date: 2021-02-19T05:38:01-08:00
New Revision: b6db47d7e044730dc3c9b35dae6697eee0885dbf
URL: https://github.com/llvm/llvm-project/commit/b6db47d7e044730dc3c9b35dae6697eee0885dbf
DIFF: https://github.com/llvm/llvm-project/commit/b6db47d7e044730dc3c9b35dae6697eee0885dbf.diff
LOG: [llvm-dwarfdump][locstats] Unify handling of inlined vars with no loc
The presence or absence of an inline variable (as well as formal
parameter) with only an abstract_origin ref (without DW_AT_location)
should not change the location coverage.
It means, for both:
DW_TAG_inlined_subroutine
DW_AT_abstract_origin (0x0000004e "f")
DW_AT_low_pc (0x0000000000000010)
DW_AT_high_pc (0x0000000000000013)
DW_TAG_formal_parameter
DW_AT_abstract_origin (0x0000005a "b")
and,
DW_TAG_inlined_subroutine
DW_AT_abstract_origin (0x0000004e "f")
DW_AT_low_pc (0x0000000000000010)
DW_AT_high_pc (0x0000000000000013)
we should report 0% location coverage. If we add DW_AT_location,
for both cases the coverage should be improved.
Differential Revision: https://reviews.llvm.org/D96045
Added:
llvm/test/tools/llvm-dwarfdump/X86/locstats-for-inlined-vars.yaml
Modified:
llvm/test/tools/llvm-dwarfdump/X86/statistics-dwo.test
llvm/test/tools/llvm-dwarfdump/X86/statistics-v3.test
llvm/test/tools/llvm-dwarfdump/X86/statistics.ll
llvm/test/tools/llvm-dwarfdump/X86/stats-scope-bytes-covered.yaml
llvm/tools/llvm-dwarfdump/Statistics.cpp
Removed:
################################################################################
diff --git a/llvm/test/tools/llvm-dwarfdump/X86/locstats-for-inlined-vars.yaml b/llvm/test/tools/llvm-dwarfdump/X86/locstats-for-inlined-vars.yaml
new file mode 100644
index 000000000000..9c3728d6238c
--- /dev/null
+++ b/llvm/test/tools/llvm-dwarfdump/X86/locstats-for-inlined-vars.yaml
@@ -0,0 +1,412 @@
+# RUN: yaml2obj %s | llvm-dwarfdump --statistics - | FileCheck %s
+
+## Check that zero coverage was reported for inlined variable with
+## DW_AT_abstract_origin with no location attribute as well as
+## for the variable that has not been generated within the inlined subroutine.
+##
+## The yaml represents DWARF as:
+##
+## DW_TAG_compile_unit
+## DW_AT_low_pc (0x0000000000000000)
+## DW_TAG_subprogram <-- (0x00000014)
+## DW_AT_decl_file (0x01)
+## DW_AT_decl_line (1)
+## DW_AT_inline (DW_INL_inlined)
+## DW_TAG_formal_parameter <-- (0x00000018)
+## DW_AT_decl_file (0x01)
+## DW_AT_decl_line (1)
+## DW_TAG_formal_parameter <-- (0x0000001b)
+## DW_AT_decl_file (0x01)
+## DW_AT_decl_line (1)
+## DW_TAG_variable <-- (0x0000001e)
+## DW_AT_decl_file (0x01)
+## DW_AT_decl_line (1)
+## DW_TAG_subprogram
+## DW_AT_decl_file (0x01)
+## DW_AT_decl_line (1)
+## DW_AT_low_pc (0x0000000000000000)
+## DW_AT_high_pc (0x000000000000000b)
+## DW_TAG_inlined_subroutine
+## DW_AT_abstract_origin (0x00000014)
+## DW_AT_low_pc (0x0000000000000000)
+## DW_AT_high_pc (0x0000000000000007)
+## DW_AT_call_file (0x01)
+## DW_AT_call_line (1)
+## DW_AT_call_column (0x01)
+## DW_TAG_formal_parameter
+## DW_AT_abstract_origin (0x00000018)
+## DW_TAG_variable
+## DW_AT_abstract_origin (0x0000001e)
+## DW_AT_location ()
+## DW_TAG_inlined_subroutine
+## DW_AT_abstract_origin (0x00000014)
+## DW_AT_low_pc (0x0000000000000000)
+## DW_AT_high_pc (0x0000000000000007)
+## DW_AT_call_file (0x01)
+## DW_AT_call_line (1)
+## DW_AT_call_column (0x01)
+## DW_TAG_formal_parameter
+## DW_AT_abstract_origin (0x00000018)
+## DW_AT_location ()
+## DW_TAG_variable
+## DW_AT_abstract_origin (0x0000001e)
+## DW_AT_location ()
+## DW_TAG_inlined_subroutine
+## DW_AT_abstract_origin (0x00000014)
+## DW_AT_low_pc (0x0000000000000000)
+## DW_AT_high_pc (0x0000000000000007)
+## DW_AT_call_file (0x01)
+## DW_AT_call_line (1)
+## DW_AT_call_column (0x01)
+## DW_TAG_inlined_subroutine
+## DW_AT_abstract_origin (0x00000014)
+## DW_AT_low_pc (0x0000000000000002)
+## DW_AT_high_pc (0x000000000000000a)
+## DW_AT_call_file (0x01)
+## DW_AT_call_line (3)
+## DW_AT_call_column (0x03)
+## DW_TAG_inlined_subroutine
+## DW_AT_abstract_origin (0x000000e5)
+## DW_AT_low_pc (0x0000000000000006)
+## DW_AT_high_pc (0x0000000000000010)
+## DW_AT_call_file (0x01)
+## DW_AT_call_line (3)
+## DW_AT_call_column (0x03)
+## DW_TAG_inlined_subroutine
+## DW_AT_abstract_origin (0x000000e5)
+## DW_AT_low_pc (0x0000000000000006)
+## DW_AT_high_pc (0x0000000000000010)
+## DW_AT_call_file (0x01)
+## DW_AT_call_line (3)
+## DW_AT_call_column (0x03)
+## DW_TAG_formal_parameter
+## DW_AT_abstract_origin (0x000000e9)
+## DW_AT_location ()
+## DW_TAG_inlined_subroutine
+## DW_AT_abstract_origin (0x000000f0)
+## DW_AT_low_pc (0x0000000000000010)
+## DW_AT_high_pc (0x000000000000001a)
+## DW_AT_call_file (0x01)
+## DW_AT_call_line (3)
+## DW_AT_call_column (0x03)
+## DW_TAG_formal_parameter
+## DW_AT_abstract_origin (0x000000f4)
+## DW_TAG_lexical_block
+## DW_AT_low_pc (0x00000000000000bc)
+## DW_AT_high_pc (0x00000000000000bc)
+## DW_TAG_variable
+## DW_AT_abstract_origin (0x000000f8)
+## DW_TAG_subprogram <-- (0x000000e5)
+## DW_AT_decl_file (0x01)
+## DW_AT_decl_line (3)
+## DW_AT_inline (DW_INL_inlined)
+## DW_TAG_formal_parameter <-- (0x000000e9)
+## DW_AT_decl_file (0x01)
+## DW_AT_decl_line (1)
+## DW_TAG_variable <-- (0x000000be)
+## DW_AT_decl_file (0x01)
+## DW_AT_decl_line (1)
+## DW_TAG_subprogram <-- (0x000000f0)
+## DW_AT_decl_file (0x01)
+## DW_AT_decl_line (3)
+## DW_AT_inline (DW_INL_inlined)
+## DW_TAG_formal_parameter <--(0x000000f4)
+## DW_AT_decl_file (0x01)
+## DW_AT_decl_line (1)
+## DW_TAG_lexical_block
+## DW_TAG_variable <--(0x000000f8)
+## DW_AT_decl_file (0x01)
+## DW_AT_decl_line (1)
+
+# CHECK: "version": 7,
+# CHECK: "#variables processed by location statistics": 15,
+# CHECK: "#variables with 0% of parent scope covered by DW_AT_location": 11,
+# CHECK: "#variables with 100% of parent scope covered by DW_AT_location": 4,
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+DWARF:
+ debug_abbrev:
+ - Table:
+ - Code: 1
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Code: 2
+ Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_decl_file
+ Form: DW_FORM_data1
+ - Attribute: DW_AT_decl_line
+ Form: DW_FORM_data1
+ - Attribute: DW_AT_inline
+ Form: DW_FORM_data1
+ - Code: 3
+ Tag: DW_TAG_formal_parameter
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_decl_file
+ Form: DW_FORM_data1
+ - Attribute: DW_AT_decl_line
+ Form: DW_FORM_data1
+ - Code: 4
+ Tag: DW_TAG_formal_parameter
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_decl_file
+ Form: DW_FORM_data1
+ - Attribute: DW_AT_decl_line
+ Form: DW_FORM_data1
+ - Code: 5
+ Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_decl_file
+ Form: DW_FORM_data1
+ - Attribute: DW_AT_decl_line
+ Form: DW_FORM_data1
+ - Code: 6
+ Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_decl_file
+ Form: DW_FORM_data1
+ - Attribute: DW_AT_decl_line
+ Form: DW_FORM_data1
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_data4
+ - Code: 7
+ Tag: DW_TAG_inlined_subroutine
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_abstract_origin
+ Form: DW_FORM_ref4
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_call_file
+ Form: DW_FORM_data1
+ - Attribute: DW_AT_call_line
+ Form: DW_FORM_data1
+ - Attribute: DW_AT_call_column
+ Form: DW_FORM_data1
+ - Code: 8
+ Tag: DW_TAG_formal_parameter
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_abstract_origin
+ Form: DW_FORM_ref4
+ - Code: 9
+ Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_abstract_origin
+ Form: DW_FORM_ref4
+ - Attribute: DW_AT_location
+ Form: DW_FORM_exprloc
+ - Code: 10
+ Tag: DW_TAG_formal_parameter
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_abstract_origin
+ Form: DW_FORM_ref4
+ - Attribute: DW_AT_location
+ Form: DW_FORM_exprloc
+ - Code: 11
+ Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_decl_file
+ Form: DW_FORM_data1
+ - Attribute: DW_AT_decl_line
+ Form: DW_FORM_data1
+ - Attribute: DW_AT_inline
+ Form: DW_FORM_data1
+ - Code: 12
+ Tag: DW_TAG_formal_parameter
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_decl_file
+ Form: DW_FORM_data1
+ - Attribute: DW_AT_decl_line
+ Form: DW_FORM_data1
+ - Code: 13
+ Tag: DW_TAG_lexical_block
+ Children: DW_CHILDREN_yes
+ - Code: 14
+ Tag: DW_TAG_lexical_block
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_data4
+ - Code: 15
+ Tag: DW_TAG_formal_parameter
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_abstract_origin
+ Form: DW_FORM_ref4
+ - Code: 16
+ Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_abstract_origin
+ Form: DW_FORM_ref4
+ debug_info:
+ - Version: 4
+ AbbrOffset: 0x00
+ Entries:
+ - AbbrCode: 1 ## DW_TAG_compile_unit
+ Values:
+ - Value: 0x00 ## DW_AT_producer
+ - AbbrCode: 2 ## DW_TAG_subprogram
+ Values:
+ - Value: 1 ## DW_AT_decl_file
+ - Value: 1 ## DW_AT_decl_line
+ - Value: 1 ## DW_AT_inline
+ - AbbrCode: 3 ## DW_TAG_formal_parameter
+ Values:
+ - Value: 1 ## DW_AT_decl_file
+ - Value: 1 ## DW_AT_decl_line
+ - AbbrCode: 4 ## DW_TAG_formal_parameter
+ Values:
+ - Value: 1 ## DW_AT_decl_file
+ - Value: 1 ## DW_AT_decl_line
+ - AbbrCode: 5 ## DW_TAG_variable
+ Values:
+ - Value: 1 ## DW_AT_decl_file
+ - Value: 1 ## DW_AT_decl_line
+ - AbbrCode: 0 ## NULL
+ - AbbrCode: 6 ## DW_TAG_subprogram
+ Values:
+ - Value: 1 ## DW_AT_decl_file
+ - Value: 1 ## DW_AT_decl_line
+ - Value: 0x00 ## DW_AT_low_pc
+ - Value: 0x0b ## DW_AT_high_pc
+ - AbbrCode: 7 ## DW_TAG_inlined_subroutine
+ Values:
+ - Value: 0x14 ## DW_AT_abstract_origin
+ - Value: 0x00 ## DW_AT_low_pc
+ - Value: 0x07 ## DW_AT_high_pc
+ - Value: 1 ## DW_AT_call_file
+ - Value: 1 ## DW_AT_call_line
+ - Value: 1 ## DW_AT_call_column
+ - AbbrCode: 8 ## DW_TAG_formal_parameter
+ Values:
+ - Value: 0x18 ## DW_AT_abstract_origin
+ - AbbrCode: 9 ## DW_TAG_formal_parameter
+ Values:
+ - Value: 0x1e ## DW_AT_abstract_origin
+ - Value: 0x0 ## DW_AT_location
+ - AbbrCode: 0 ## NULL
+ - AbbrCode: 7 ## DW_TAG_inlined_subroutine
+ Values:
+ - Value: 0x14 ## DW_AT_abstract_origin
+ - Value: 0x02 ## DW_AT_low_pc
+ - Value: 0x08 ## DW_AT_high_pc
+ - Value: 1 ## DW_AT_call_file
+ - Value: 2 ## DW_AT_call_line
+ - Value: 2 ## DW_AT_call_column
+ - AbbrCode: 10 ## DW_TAG_formal_parameter
+ Values:
+ - Value: 0x18 ## DW_AT_abstract_origin
+ - Value: 0x0 ## DW_AT_location
+ - AbbrCode: 9 ## DW_TAG_variable
+ Values:
+ - Value: 0x1e ## DW_AT_abstract_origin
+ - Value: 0x0 ## DW_AT_location
+ - AbbrCode: 0 ## NULL
+ - AbbrCode: 7 ## DW_TAG_inlined_subroutine
+ Values:
+ - Value: 0x14 ## DW_AT_abstract_origin
+ - Value: 0x02 ## DW_AT_low_pc
+ - Value: 0x08 ## DW_AT_high_pc
+ - Value: 1 ## DW_AT_call_file
+ - Value: 3 ## DW_AT_call_line
+ - Value: 3 ## DW_AT_call_column
+ - AbbrCode: 0 ## NULL
+ - AbbrCode: 7 ## DW_TAG_inlined_subroutine
+ Values:
+ - Value: 0xe5 ## DW_AT_abstract_origin
+ - Value: 0x06 ## DW_AT_low_pc
+ - Value: 0x0a ## DW_AT_high_pc
+ - Value: 1 ## DW_AT_call_file
+ - Value: 3 ## DW_AT_call_line
+ - Value: 3 ## DW_AT_call_column
+ - AbbrCode: 0 ## NULL
+ - AbbrCode: 7 ## DW_TAG_inlined_subroutine
+ Values:
+ - Value: 0xe5 ## DW_AT_abstract_origin
+ - Value: 0x06 ## DW_AT_low_pc
+ - Value: 0x0a ## DW_AT_high_pc
+ - Value: 1 ## DW_AT_call_file
+ - Value: 3 ## DW_AT_call_line
+ - Value: 3 ## DW_AT_call_column
+ - AbbrCode: 10 ## DW_TAG_formal_parameter
+ Values:
+ - Value: 0xe9 ## DW_AT_abstract_origin
+ - Value: 0x0 ## DW_AT_location
+ - AbbrCode: 0 ## NULL
+ - AbbrCode: 7 ## DW_TAG_inlined_subroutine
+ Values:
+ - Value: 0xf0 ## DW_AT_abstract_origin
+ - Value: 0x10 ## DW_AT_low_pc
+ - Value: 0x0a ## DW_AT_high_pc
+ - Value: 1 ## DW_AT_call_file
+ - Value: 3 ## DW_AT_call_line
+ - Value: 3 ## DW_AT_call_column
+ - AbbrCode: 15 ## DW_TAG_formal_parameter
+ Values:
+ - Value: 0xf4 ## DW_AT_abstract_origin
+ - AbbrCode: 14 ## DW_TAG_lexical_block
+ Values:
+ - Value: 0xbc ## DW_AT_low_pc
+ - Value: 0x0 ## DW_AT_high_pc
+ - AbbrCode: 16 ## DW_TAG_variable
+ Values:
+ - Value: 0xf8 ## DW_AT_abstract_origin
+ - AbbrCode: 0 ## NULL
+ - AbbrCode: 0 ## NULL
+ - AbbrCode: 0 ## NULL
+ - AbbrCode: 2 ## DW_TAG_subprogram
+ Values:
+ - Value: 1 ## DW_AT_decl_file
+ - Value: 3 ## DW_AT_decl_line
+ - Value: 1 ## DW_AT_inline
+ - AbbrCode: 3 ## DW_TAG_formal_parameter
+ Values:
+ - Value: 1 ## DW_AT_decl_file
+ - Value: 1 ## DW_AT_decl_line
+ - AbbrCode: 5 ## DW_TAG_variable
+ Values:
+ - Value: 1 ## DW_AT_decl_file
+ - Value: 1 ## DW_AT_decl_line
+ - AbbrCode: 0 ## NULL
+ - AbbrCode: 11 ## DW_TAG_subprogram
+ Values:
+ - Value: 1 ## DW_AT_decl_file
+ - Value: 3 ## DW_AT_decl_line
+ - Value: 1 ## DW_AT_inline
+ - AbbrCode: 3 ## DW_TAG_formal_parameter
+ Values:
+ - Value: 1 ## DW_AT_decl_file
+ - Value: 1 ## DW_AT_decl_line
+ - AbbrCode: 13 ## DW_TAG_lexical_block
+ - AbbrCode: 5 ## DW_TAG_variable
+ Values:
+ - Value: 1 ## DW_AT_decl_file
+ - Value: 1 ## DW_AT_decl_line
+ - AbbrCode: 0 ## NULL
+ - AbbrCode: 0 ## NULL
+ - AbbrCode: 0 ## NULL
diff --git a/llvm/test/tools/llvm-dwarfdump/X86/statistics-dwo.test b/llvm/test/tools/llvm-dwarfdump/X86/statistics-dwo.test
index a5b716802f75..b0a0315cba0a 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/statistics-dwo.test
+++ b/llvm/test/tools/llvm-dwarfdump/X86/statistics-dwo.test
@@ -69,7 +69,7 @@ RUN: llvm-dwarfdump --statistics statistics-fib.split-dwarf.o | FileCheck %s
# }
#
-CHECK: "version": 6,
+CHECK: "version": 7,
CHECK: "#functions": 3,
CHECK: "#functions with location": 3,
CHECK: "#inlined functions": 7,
diff --git a/llvm/test/tools/llvm-dwarfdump/X86/statistics-v3.test b/llvm/test/tools/llvm-dwarfdump/X86/statistics-v3.test
index bb7d3dec710b..a13a6bc761d5 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/statistics-v3.test
+++ b/llvm/test/tools/llvm-dwarfdump/X86/statistics-v3.test
@@ -64,7 +64,7 @@ RUN: llvm-dwarfdump --statistics %t-statistics-fib.o | FileCheck %s
# }
#
-CHECK: "version": 6,
+CHECK: "version": 7,
CHECK: "#functions": 3,
CHECK: "#functions with location": 3,
CHECK: "#inlined functions": 8,
diff --git a/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll b/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll
index 546775eb552b..8bf029a8944a 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll
+++ b/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll
@@ -1,6 +1,6 @@
; RUN: llc -O0 %s -o - -filetype=obj \
; RUN: | llvm-dwarfdump -statistics - | FileCheck %s
-; CHECK: "version": 6,
+; CHECK: "version": 7,
; namespace test {
; extern int a;
diff --git a/llvm/test/tools/llvm-dwarfdump/X86/stats-scope-bytes-covered.yaml b/llvm/test/tools/llvm-dwarfdump/X86/stats-scope-bytes-covered.yaml
index 1e99fd5debce..4b8a3f5d4425 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/stats-scope-bytes-covered.yaml
+++ b/llvm/test/tools/llvm-dwarfdump/X86/stats-scope-bytes-covered.yaml
@@ -33,7 +33,7 @@
## DW_AT_location (0x00000023:
## [0x0000000000000003, 0x0000000000000005): DW_OP_reg2 RCX)
-# CHECK: "version": 6,
+# CHECK: "version": 7,
# CHECK: "sum_all_variables(#bytes in parent scope)": 12,
# CHECK: "sum_all_variables(#bytes in any scope covered by DW_AT_location)": 8
# CHECK: "sum_all_variables(#bytes in parent scope covered by DW_AT_location)": 4
diff --git a/llvm/tools/llvm-dwarfdump/Statistics.cpp b/llvm/tools/llvm-dwarfdump/Statistics.cpp
index 82da06eab1d6..43d7c3c4ccad 100644
--- a/llvm/tools/llvm-dwarfdump/Statistics.cpp
+++ b/llvm/tools/llvm-dwarfdump/Statistics.cpp
@@ -8,9 +8,7 @@
#include "llvm-dwarfdump.h"
#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"
#include "llvm/Object/ObjectFile.h"
@@ -21,13 +19,23 @@ using namespace llvm;
using namespace llvm::dwarfdump;
using namespace llvm::object;
+namespace {
/// This represents the number of categories of debug location coverage being
/// calculated. The first category is the number of variables with 0% location
/// coverage, but the last category is the number of variables with 100%
/// location coverage.
constexpr int NumOfCoverageCategories = 12;
-namespace {
+/// This is used for zero location coverage bucket.
+constexpr unsigned ZeroCoverageBucket = 0;
+
+/// This represents variables DIE offsets.
+using InlinedVarsTy = llvm::SmallVector<uint64_t>;
+/// This maps function DIE offset to its variables.
+using InlinedVarsTyMap = llvm::DenseMap<uint64_t, InlinedVarsTy>;
+/// This represents inlined_subroutine DIE offsets.
+using InlinedFnInstacesTy = llvm::SmallVector<uint64_t>;
+
/// Holds statistics for one function (or other entity that has a PC range and
/// contains variables, such as a compile unit).
struct PerFunctionStats {
@@ -164,12 +172,14 @@ static void collectLocStats(uint64_t ScopeBytesCovered, uint64_t BytesInScope,
};
unsigned CoverageBucket = getCoverageBucket();
+
VarParamLocStats[CoverageBucket]++;
if (IsParam)
ParamLocStats[CoverageBucket]++;
else if (IsLocalVar)
LocalVarLocStats[CoverageBucket]++;
}
+
/// Construct an identifier for a given DIE from its Prefix, Name, DeclFileName
/// and DeclLine. The identifier aims to be unique for any unique entities,
/// but keeping the same among
diff erent instances of the same entity.
@@ -215,7 +225,8 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,
uint32_t InlineDepth,
StringMap<PerFunctionStats> &FnStatMap,
GlobalStats &GlobalStats,
- LocationStats &LocStats) {
+ LocationStats &LocStats,
+ InlinedVarsTy *InlinedVariables) {
bool HasLoc = false;
bool HasSrcLoc = false;
bool HasType = false;
@@ -228,6 +239,10 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,
bool IsConstantMember = Die.getTag() == dwarf::DW_TAG_member &&
Die.find(dwarf::DW_AT_const_value);
+ // For zero covered inlined variables the locstats will be
+ // calculated later.
+ bool DeferLocStats = false;
+
if (Die.getTag() == dwarf::DW_TAG_call_site ||
Die.getTag() == dwarf::DW_TAG_GNU_call_site) {
GlobalStats.CallSiteDIEs++;
@@ -256,6 +271,23 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,
if (Die.findRecursively(dwarf::DW_AT_type))
HasType = true;
+ // Check if it is an inlined variable.
+ if (Die.find(dwarf::DW_AT_abstract_origin)) {
+ if (Die.find(dwarf::DW_AT_location) ||
+ Die.find(dwarf::DW_AT_const_value)) {
+ if (InlinedVariables) {
+ auto Offset = Die.find(dwarf::DW_AT_abstract_origin);
+ // Do not track this inlined var any more, since it has location
+ // coverage.
+ llvm::erase_value(*InlinedVariables, (*Offset).getRawUValue());
+ }
+ } else {
+ // The locstats will be handled at the end of
+ // the collectStatsRecursive().
+ DeferLocStats = true;
+ }
+ }
+
auto IsEntryValue = [&](ArrayRef<uint8_t> D) -> bool {
DWARFUnit *U = Die.getDwarfUnit();
DataExtractor Data(toStringRef(D),
@@ -315,7 +347,7 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,
}
// Calculate the debug location statistics.
- if (BytesInScope) {
+ if (BytesInScope && !DeferLocStats) {
LocStats.NumVarParam++;
if (IsParam)
LocStats.NumParam++;
@@ -389,13 +421,33 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,
}
}
+/// Recursively collect variables from subprogram with
+/// DW_AT_inline attribute.
+static void collectInlinedFnInfo(DWARFDie Die,
+ uint64_t SPOffset,
+ InlinedVarsTyMap &GlobalInlinedFnInfo) {
+ DWARFDie Child = Die.getFirstChild();
+ while (Child) {
+ const dwarf::Tag ChildTag = Child.getTag();
+ if (ChildTag == dwarf::DW_TAG_formal_parameter ||
+ ChildTag == dwarf::DW_TAG_variable)
+ GlobalInlinedFnInfo[SPOffset].push_back(Child.getOffset());
+ else if (ChildTag == dwarf::DW_TAG_lexical_block)
+ collectInlinedFnInfo(Child, SPOffset, GlobalInlinedFnInfo);
+ Child = Child.getSibling();
+ }
+}
+
/// Recursively collect debug info quality metrics.
static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix,
std::string VarPrefix, uint64_t BytesInScope,
uint32_t InlineDepth,
StringMap<PerFunctionStats> &FnStatMap,
GlobalStats &GlobalStats,
- LocationStats &LocStats) {
+ LocationStats &LocStats,
+ InlinedVarsTyMap &GlobalInlinedFnInfo,
+ InlinedFnInstacesTy &InlinedFnsToBeProcessed,
+ InlinedVarsTy *InlinedVarsPtr = nullptr) {
const dwarf::Tag Tag = Die.getTag();
// Skip function types.
if (Tag == dwarf::DW_TAG_subroutine_type)
@@ -405,11 +457,28 @@ static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix,
const bool IsFunction = Tag == dwarf::DW_TAG_subprogram;
const bool IsBlock = Tag == dwarf::DW_TAG_lexical_block;
const bool IsInlinedFunction = Tag == dwarf::DW_TAG_inlined_subroutine;
- if (IsFunction || IsInlinedFunction || IsBlock) {
+ InlinedVarsTy InlinedVars;
+ // Get the vars of the inlined fn, so the locstats
+ // reports the missing vars (with coverage 0%).
+ if (IsInlinedFunction) {
+ auto OffsetFn = Die.find(dwarf::DW_AT_abstract_origin);
+ if (OffsetFn) {
+ uint64_t OffsetOfInlineFnCopy = (*OffsetFn).getRawUValue();
+ if (GlobalInlinedFnInfo.count(OffsetOfInlineFnCopy)) {
+ InlinedVars = GlobalInlinedFnInfo[OffsetOfInlineFnCopy];
+ InlinedVarsPtr = &InlinedVars;
+ } else {
+ // This means that the DW_AT_inline fn copy is out of order,
+ // so this inlined instance will be processed later.
+ InlinedFnsToBeProcessed.push_back(Die.getOffset());
+ InlinedVarsPtr = nullptr;
+ }
+ }
+ }
+ if (IsFunction || IsInlinedFunction || IsBlock) {
// Reset VarPrefix when entering a new function.
- if (Die.getTag() == dwarf::DW_TAG_subprogram ||
- Die.getTag() == dwarf::DW_TAG_inlined_subroutine)
+ if (IsFunction || IsInlinedFunction)
VarPrefix = "v";
// Ignore forward declarations.
@@ -434,9 +503,15 @@ static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix,
// Count the function.
if (!IsBlock) {
- // Skip over abstract origins.
- if (Die.find(dwarf::DW_AT_inline))
+ // Skip over abstract origins, but collect variables
+ // from it so it can be used for location statistics
+ // for inlined instancies.
+ if (Die.find(dwarf::DW_AT_inline)) {
+ uint64_t SPOffset = Die.getOffset();
+ collectInlinedFnInfo(Die, SPOffset, GlobalInlinedFnInfo);
return;
+ }
+
std::string FnID = constructDieID(Die);
// We've seen an instance of this function.
auto &FnStats = FnStatMap[FnID];
@@ -465,7 +540,7 @@ static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix,
} else {
// Not a scope, visit the Die itself. It could be a variable.
collectStatsForDie(Die, FnPrefix, VarPrefix, BytesInScope, InlineDepth,
- FnStatMap, GlobalStats, LocStats);
+ FnStatMap, GlobalStats, LocStats, InlinedVarsPtr);
}
// Set InlineDepth correctly for child recursion
@@ -486,9 +561,32 @@ static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix,
ChildVarPrefix += 'p' + toHex(FormalParameterIndex++) + '.';
collectStatsRecursive(Child, FnPrefix, ChildVarPrefix, BytesInScope,
- InlineDepth, FnStatMap, GlobalStats, LocStats);
+ InlineDepth, FnStatMap, GlobalStats, LocStats,
+ GlobalInlinedFnInfo, InlinedFnsToBeProcessed,
+ InlinedVarsPtr);
Child = Child.getSibling();
}
+
+ if (!IsInlinedFunction)
+ return;
+
+ // After we have processed all vars of the inlined function,
+ // we want to know how many variables have no location.
+ for (auto Offset : InlinedVars) {
+ LocStats.NumVarParam++;
+ LocStats.VarParamLocStats[ZeroCoverageBucket]++;
+ auto InlineDie = Die.getDwarfUnit()->getDIEForOffset(Offset);
+ if (!InlineDie)
+ continue;
+ auto Tag = InlineDie.getTag();
+ if (Tag == dwarf::DW_TAG_formal_parameter) {
+ LocStats.NumParam++;
+ LocStats.ParamLocStats[ZeroCoverageBucket]++;
+ } else if (Tag == dwarf::DW_TAG_variable) {
+ LocStats.NumVar++;
+ LocStats.LocalVarLocStats[ZeroCoverageBucket]++;
+ }
+ }
}
/// Print human-readable output.
@@ -541,6 +639,58 @@ static void printSectionSizes(json::OStream &J, const SectionSizes &Sizes) {
int64_t(DebugSec.getValue()));
}
+/// Stop tracking inlined variables with a location.
+/// This is used for out-of-order DW_AT_inline subprograms only.
+static void updateInlinedVarsCovInfo(DWARFDie InlinedFnDie,
+ InlinedVarsTy &InlinedVars) {
+ DWARFDie Child = InlinedFnDie.getFirstChild();
+ while (Child) {
+ const dwarf::Tag ChildTag = Child.getTag();
+ if ((ChildTag == dwarf::DW_TAG_formal_parameter ||
+ ChildTag == dwarf::DW_TAG_variable) &&
+ (Child.find(dwarf::DW_AT_location) ||
+ Child.find(dwarf::DW_AT_const_value))) {
+ auto OffsetVar = Child.find(dwarf::DW_AT_abstract_origin);
+ if (OffsetVar)
+ llvm::erase_value(InlinedVars, (*OffsetVar).getRawUValue());
+ } else if (ChildTag == dwarf::DW_TAG_lexical_block)
+ updateInlinedVarsCovInfo(Child, InlinedVars);
+ Child = Child.getSibling();
+ }
+}
+
+/// Collect zero location coverage for inlined variables which refer to
+/// a DW_AT_inline copy of subprogram that is out of order in the DWARF.
+static void
+collectZeroCovInlinedVars(DWARFUnit *DwUnit, GlobalStats &GlobalStats,
+ LocationStats &LocStats,
+ InlinedVarsTyMap &GlobalInlinedFnInfo,
+ InlinedFnInstacesTy &InlinedFnsToBeProcessed) {
+ for (auto FnOffset : InlinedFnsToBeProcessed) {
+ DWARFDie InlinedFnDie = DwUnit->getDIEForOffset(FnOffset);
+ auto InlinedCopy = InlinedFnDie.find(dwarf::DW_AT_abstract_origin);
+ InlinedVarsTy InlinedVars;
+ if (!InlinedCopy)
+ continue;
+
+ InlinedVars = GlobalInlinedFnInfo[(*InlinedCopy).getRawUValue()];
+ updateInlinedVarsCovInfo(InlinedFnDie, InlinedVars);
+
+ for (auto Offset : InlinedVars) {
+ LocStats.NumVarParam++;
+ LocStats.VarParamLocStats[ZeroCoverageBucket]++;
+ auto Tag = DwUnit->getDIEForOffset(Offset).getTag();
+ if (Tag == dwarf::DW_TAG_formal_parameter) {
+ LocStats.NumParam++;
+ LocStats.ParamLocStats[ZeroCoverageBucket]++;
+ } else if (Tag == dwarf::DW_TAG_variable) {
+ LocStats.NumVar++;
+ LocStats.LocalVarLocStats[ZeroCoverageBucket]++;
+ }
+ }
+ }
+}
+
/// \}
/// Collect debug info quality metrics for an entire DIContext.
@@ -557,11 +707,19 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
StringRef FormatName = Obj.getFileFormatName();
GlobalStats GlobalStats;
LocationStats LocStats;
+ InlinedVarsTyMap GlobalInlinedFnInfo;
+ InlinedFnInstacesTy InlinedFnsToBeProcessed;
StringMap<PerFunctionStats> Statistics;
- for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units())
- if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false))
+ for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units()) {
+ if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false)) {
collectStatsRecursive(CUDie, "/", "g", 0, 0, Statistics, GlobalStats,
- LocStats);
+ LocStats, GlobalInlinedFnInfo,
+ InlinedFnsToBeProcessed);
+
+ collectZeroCovInlinedVars(CUDie.getDwarfUnit(), GlobalStats, LocStats,
+ GlobalInlinedFnInfo, InlinedFnsToBeProcessed);
+ }
+ }
/// Collect the sizes of debug sections.
SectionSizes Sizes;
@@ -570,7 +728,7 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
/// The version number should be increased every time the algorithm is changed
/// (including bug fixes). New metrics may be added without increasing the
/// version.
- unsigned Version = 6;
+ unsigned Version = 7;
unsigned VarParamTotal = 0;
unsigned VarParamUnique = 0;
unsigned VarParamWithLoc = 0;
More information about the llvm-commits
mailing list