[PATCH] Only share the same DW_TAG_common_block within the same scope (PR debug/37738)
Jakub Jelinek
jakub@redhat.com
Tue Oct 7 11:10:00 GMT 2008
Hi!
lookup_decl_die is wrong thing to use for com_decl, because VAR_DECLs
for Fortran COMMON block are global and thus have the same DECL_UID between
different routines, but we don't want to append vars from one function
to other function's DW_TAG_common_block and not emit any DW_TAG_common_block
in the current scope.
This patch introduces a separate hash table for common block DIEs which
doesn't take into account just DECL_UID, but also the context in which it
is present. Walking the whole die_child chain of context_die might be
too expensive IMHO, so I went with a hash table instead.
Additionally, the patch implements a small debug info size optimization
suggested by Jan, instead of emitting say:
.byte 0x3 # DW_OP_addr
.quad foo_
.byte 0x23 # DW_OP_plus_uconst
.uleb128 0x8
we now emit in the common case:
.byte 0x3 # DW_OP_addr
.quad foo_+8
which is 2 (or more, for larger offsets) bytes shorter.
Ok for trunk?
2008-10-07 Jakub Jelinek <jakub@redhat.com>
PR debug/37738
* dwarf2out.c (common_block_die_table): New variable.
(common_block_die_table_hash, common_block_die_table_eq): New
functions.
(gen_variable_die): Look up a DW_TAG_common_block die for a particular
COMMON block in the current scope rather than globally. Optimize
DW_OP_addr SYMBOL_REF DW_OP_plus_uconst off into
DW_OP_addr SYMBOL_REF+off.
* gfortran.dg/debug/pr37738.f: New test.
--- gcc/dwarf2out.c.jj 2008-10-01 15:33:53.000000000 +0200
+++ gcc/dwarf2out.c 2008-10-07 11:40:21.000000000 +0200
@@ -4746,6 +4746,10 @@ static GTY((param_is (struct dwarf_file_
The key is a DECL_UID() which is a unique number identifying each decl. */
static GTY ((param_is (struct die_struct))) htab_t decl_die_table;
+/* A hash table of references to DIE's that describe COMMON blocks.
+ The key is DECL_UID() ^ die_parent. */
+static GTY ((param_is (struct die_struct))) htab_t common_block_die_table;
+
/* Node of the variable location list. */
struct var_loc_node GTY ((chain_next ("%h.next")))
{
@@ -4958,6 +4962,8 @@ static void equate_type_number_to_die (t
static hashval_t decl_die_table_hash (const void *);
static int decl_die_table_eq (const void *, const void *);
static dw_die_ref lookup_decl_die (tree);
+static hashval_t common_block_die_table_hash (const void *);
+static int common_block_die_table_eq (const void *, const void *);
static hashval_t decl_loc_table_hash (const void *);
static int decl_loc_table_eq (const void *, const void *);
static var_loc_list *lookup_decl_loc (const_tree);
@@ -13810,6 +13816,26 @@ gen_subprogram_die (tree decl, dw_die_re
}
+/* Returns a hash value for X (which really is a die_struct). */
+
+static hashval_t
+common_block_die_table_hash (const void *x)
+{
+ const_dw_die_ref d = (const_dw_die_ref) x;
+ return (hashval_t) d->decl_id ^ htab_hash_pointer (d->die_parent);
+}
+
+/* Return nonzero if decl_id and die_parent of die_struct X is the same
+ as decl_id and die_parent of die_struct Y. */
+
+static int
+common_block_die_table_eq (const void *x, const void *y)
+{
+ const_dw_die_ref d = (const_dw_die_ref) x;
+ const_dw_die_ref e = (const_dw_die_ref) y;
+ return d->decl_id == e->decl_id && d->die_parent == e->die_parent;
+}
+
/* Generate a DIE to represent a declared data object. */
static void
@@ -13851,6 +13877,7 @@ gen_variable_die (tree decl, dw_die_ref
tree field;
dw_die_ref com_die;
dw_loc_descr_ref loc;
+ die_node com_die_arg;
var_die = lookup_decl_die (decl);
if (var_die)
@@ -13861,21 +13888,41 @@ gen_variable_die (tree decl, dw_die_ref
if (loc)
{
if (off)
- add_loc_descr (&loc, new_loc_descr (DW_OP_plus_uconst,
+ {
+ /* Optimize the common case. */
+ if (loc->dw_loc_opc == DW_OP_addr
+ && loc->dw_loc_next == NULL
+ && GET_CODE (loc->dw_loc_oprnd1.v.val_addr)
+ == SYMBOL_REF)
+ loc->dw_loc_oprnd1.v.val_addr
+ = plus_constant (loc->dw_loc_oprnd1.v.val_addr, off);
+ else
+ add_loc_descr (&loc,
+ new_loc_descr (DW_OP_plus_uconst,
off, 0));
+ }
add_AT_loc (var_die, DW_AT_location, loc);
remove_AT (var_die, DW_AT_declaration);
}
}
return;
}
+
+ if (common_block_die_table == NULL)
+ common_block_die_table
+ = htab_create_ggc (10, common_block_die_table_hash,
+ common_block_die_table_eq, NULL);
+
field = TREE_OPERAND (DECL_VALUE_EXPR (decl), 0);
- com_die = lookup_decl_die (com_decl);
+ com_die_arg.decl_id = DECL_UID (com_decl);
+ com_die_arg.die_parent = context_die;
+ com_die = (dw_die_ref) htab_find (common_block_die_table, &com_die_arg);
loc = loc_descriptor_from_tree (com_decl);
if (com_die == NULL)
{
const char *cnam
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (com_decl));
+ void **slot;
com_die = new_die (DW_TAG_common_block, context_die, decl);
add_name_and_src_coords_attributes (com_die, com_decl);
@@ -13889,7 +13936,9 @@ gen_variable_die (tree decl, dw_die_ref
else if (DECL_EXTERNAL (decl))
add_AT_flag (com_die, DW_AT_declaration, 1);
add_pubname_string (cnam, com_die); /* ??? needed? */
- equate_decl_number_to_die (com_decl, com_die);
+ com_die->decl_id = DECL_UID (com_decl);
+ slot = htab_find_slot (common_block_die_table, com_die, INSERT);
+ *slot = (void *) com_die;
}
else if (get_AT (com_die, DW_AT_location) == NULL && loc)
{
@@ -13905,7 +13954,17 @@ gen_variable_die (tree decl, dw_die_ref
if (loc)
{
if (off)
- add_loc_descr (&loc, new_loc_descr (DW_OP_plus_uconst, off, 0));
+ {
+ /* Optimize the common case. */
+ if (loc->dw_loc_opc == DW_OP_addr
+ && loc->dw_loc_next == NULL
+ && GET_CODE (loc->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF)
+ loc->dw_loc_oprnd1.v.val_addr
+ = plus_constant (loc->dw_loc_oprnd1.v.val_addr, off);
+ else
+ add_loc_descr (&loc, new_loc_descr (DW_OP_plus_uconst,
+ off, 0));
+ }
add_AT_loc (var_die, DW_AT_location, loc);
}
else if (DECL_EXTERNAL (decl))
--- gcc/testsuite/gfortran.dg/debug/pr37738.f.jj 2008-10-07 11:54:47.000000000 +0200
+++ gcc/testsuite/gfortran.dg/debug/pr37738.f 2008-10-07 11:56:15.000000000 +0200
@@ -0,0 +1,30 @@
+C PR debug/37738
+C { dg-do compile }
+C { dg-skip-if "DWARF-2 only" { "*-*-*" } { "*" } { "-gdwarf-2" } }
+C { dg-options "-dA" }
+
+ subroutine a
+ integer*4 a_i, c_i
+ common /block/a_i, c_i
+ a_i = 1
+ c_i = 4
+ end subroutine a
+ subroutine b
+ integer*4 b_i
+ common /block/b_i, d_i
+ b_i = 2
+ d_i = 5
+ end subroutine b
+ subroutine c
+ integer*4 a_i, c_i
+ common /block/a_i, c_i
+ if (a_i .ne. 2) call abort
+ if (c_i .ne. 5) call abort
+ end subroutine c
+ program abc
+ call a
+ call b
+ call c
+ end program abc
+
+C { dg-final { scan-assembler-times "DIE\[^\n\]*DW_TAG_common_block" 3 } }
Jakub
More information about the Gcc-patches
mailing list