[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