Hi,

I noticed that when you generate dwarf for an inlined function it often
comes with duplicate range lists for both the DW_TAG_inlined_subroutine
and the child DW_TAG_lexical_block DIE. For example:

static int k;

static int foo (int i)
{
  int j = i + 42;
  return k + (j > 14 ? j : i);
}

int main (int argc, char **argv)
{
  int c = argc;
  k = 2 * c;
  c = foo (c);
  return c;
}

Generates with -O2 -gdwarf-4:

DWARF section [27] '.debug_info' at offset 0x895:
 [Offset]
 Compilation unit at offset 0:
 Version: 4, Abbreviation section offset: 0, Address size: 8, Offset size: 4
[...]
 [    a8]      inlined_subroutine
               abstract_origin      (ref4) [    31]
               entry_pc             (addr) 0x0000000000400360 <main>
               ranges               (data4) range list [     0]
               call_file            (data1) 1
               call_line            (data1) 13
 [    bb]        formal_parameter
                 abstract_origin      (ref4) [    42]
                 location             (block1) 
                  [   0] reg5
 [    c2]        lexical_block
                 ranges               (data4) range list [    40]
 [    c7]          variable
                   abstract_origin      (ref4) [    4b]
                   location             (data4) location list [    23]
[...]
DWARF section [32] '.debug_ranges' at offset 0xb4e:
 [     0]  0x0000000000400360 <main>..0x0000000000400363 <main+0x3>
           0x0000000000400366 <main+0x6>..0x0000000000400369 <main+0x9>
           0x000000000040036f <main+0xf>..0x0000000000400374 <main+0x14>
 [    40]  0x0000000000400360 <main>..0x0000000000400363 <main+0x3>
           0x0000000000400366 <main+0x6>..0x0000000000400369 <main+0x9>
           0x000000000040036f <main+0xf>..0x0000000000400374 <main+0x14>
 [    80]  0x0000000000400360 <main>..0x0000000000400375

So range list 0 for the inlined_subroutine DIE a8 is the same as range
list 40 for the lexical_block DIE c2.

I had hoped I could detect and then reduce the duplication of the range
lists in this case with the attached patch where I just check that the
basic block numbers for the ranges are the same as the ranges of its
context DIE. But that doesn't actually work since by looking at the
generated assembly the basic block asm labels are in the same place,
the block numbers are actually different (and so there are actually
two differently named/numbered labels generated at the same place). e.g:

.LVL0:
.LBB4:
.LBB5:
        .loc 1 5 0
        leal    42(%rdi), %eax
.LBE5:
.LBE4:
        .loc 1 12 0
        leal    (%rdi,%rdi), %edx
.LBB8:
.LBB6:
        .loc 1 6 0
        cmpl    $14, %eax
.LBE6:
.LBE8:
        .loc 1 12 0
        movl    %edx, k(%rip)
.LVL1:
.LBB9:
.LBB7:
        .loc 1 6 0
        cmovle  %edi, %eax
.LVL2:
        addl    %edx, %eax
.LBE7:
.LBE9:
        .loc 1 15 0
        ret
        .cfi_endproc
[...]
        .section        .debug_ranges,"",@progbits
.Ldebug_ranges0:
        .quad   .LBB4
        .quad   .LBE4
        .quad   .LBB8
        .quad   .LBE8
        .quad   .LBB9
        .quad   .LBE9
        .quad   0
        .quad   0
        .quad   .LBB5
        .quad   .LBE5
        .quad   .LBB6
        .quad   .LBE6
        .quad   .LBB7
        .quad   .LBE7
        .quad   0
        .quad   0
        .quad   .LFB1
        .quad   .LFE1
        .quad   0
        .quad   0

Is there a way to detect that basic blocks have the same range even
though they have different block numbers? Or am I not looking/thinking
about this issue correctly?

Thanks,

Mark
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index f9f4295..53776f7 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -3291,6 +3291,7 @@ static int same_dw_val_p (const dw_val_node *, const 
dw_val_node *, int *);
 static int same_attr_p (dw_attr_ref, dw_attr_ref, int *);
 static int same_die_p (dw_die_ref, dw_die_ref, int *);
 static int same_die_p_wrap (dw_die_ref, dw_die_ref);
+static int same_range_p (tree, dw_die_ref, unsigned int *);
 static void compute_section_prefix (dw_die_ref);
 static int is_type_die (dw_die_ref);
 static int is_comdat_die (dw_die_ref);
@@ -6586,6 +6587,47 @@ same_die_p_wrap (dw_die_ref die1, dw_die_ref die2)
   return ret;
 }
 
+/* Is the range of the tree the same as that of the (context) die?  */
+
+static int
+same_range_p (tree stmt, dw_die_ref die, unsigned int *off)
+{
+  dw_attr_ref attr;
+  unsigned i;
+  int num;
+  tree chain;
+
+  attr = get_AT (die, DW_AT_ranges);
+  if (! attr)
+    return 0;
+
+  *off = attr->dw_attr_val.v.val_offset;
+ 
+  i = ((*off) / 2) / DWARF2_ADDR_SIZE;
+  num = ranges_table[i].num;
+
+  if (num != BLOCK_NUMBER (stmt))
+    return 0;
+
+  chain = BLOCK_FRAGMENT_CHAIN (stmt);
+  do
+    {
+      i++;
+      num = ranges_table[i].num;
+      if (num != BLOCK_NUMBER (chain))
+       return 0;
+      chain = BLOCK_FRAGMENT_CHAIN (chain);
+    }
+  while (chain);
+
+  i++;
+  num = ranges_table[i].num;
+  if (num != 0)
+    return 0;
+
+  return 1;
+}
+
 /* The prefix to attach to symbols on DIEs in the current comdat debug
    info section.  */
 static char *comdat_symbol_id;
@@ -18062,10 +18104,12 @@ add_call_src_coords_attributes (tree stmt, dw_die_ref 
die)
 
 
 /* A helper function for gen_lexical_block_die and gen_inlined_subroutine_die.
-   Add low_pc and high_pc attributes to the DIE for a block STMT.  */
+   Add low_pc and high_pc attributes to the DIE for a block STMT.
+   If a range is added then the context DIE is checked to see if it has
+   the same range already.  */
 
 static inline void
-add_high_low_attributes (tree stmt, dw_die_ref die)
+add_high_low_attributes (tree stmt, dw_die_ref die, dw_die_ref context_die)
 {
   char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
@@ -18073,6 +18117,7 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
       && (dwarf_version >= 3 || !dwarf_strict))
     {
       tree chain;
+      unsigned int range_off;
 
       if (inlined_function_outer_scope_p (stmt))
        {
@@ -18081,16 +18126,23 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
          add_AT_lbl_id (die, DW_AT_entry_pc, label);
        }
 
-      add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
-
-      chain = BLOCK_FRAGMENT_CHAIN (stmt);
-      do
+      if (same_range_p (stmt, context_die, &range_off))
        {
-         add_ranges (chain);
-         chain = BLOCK_FRAGMENT_CHAIN (chain);
+         add_AT_range_list (die, DW_AT_ranges, range_off);
+       }
+      else
+       {
+         add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
+
+         chain = BLOCK_FRAGMENT_CHAIN (stmt);
+         do
+           {
+             add_ranges (chain);
+             chain = BLOCK_FRAGMENT_CHAIN (chain);
+           }
+         while (chain);
+         add_ranges (NULL);
        }
-      while (chain);
-      add_ranges (NULL);
     }
   else
     {
@@ -18119,7 +18171,7 @@ gen_lexical_block_die (tree stmt, dw_die_ref 
context_die, int depth)
     }
 
   if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
-    add_high_low_attributes (stmt, stmt_die);
+    add_high_low_attributes (stmt, stmt_die, context_die);
 
   decls_for_scope (stmt, stmt_die, depth);
 }
@@ -18157,7 +18209,7 @@ gen_inlined_subroutine_die (tree stmt, dw_die_ref 
context_die, int depth)
        }
       add_abstract_origin_attribute (subr_die, decl);
       if (TREE_ASM_WRITTEN (stmt))
-        add_high_low_attributes (stmt, subr_die);
+        add_high_low_attributes (stmt, subr_die, context_die);
       add_call_src_coords_attributes (stmt, subr_die);
 
       decls_for_scope (stmt, subr_die, depth);

Reply via email to