[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