Commit 05688bf7 by Jason Merrill Committed by Jason Merrill

dwarf2out.c (struct external_ref, [...]): New.

	* dwarf2out.c (struct external_ref, build_local_stub): New.
	(hash_external_ref, external_ref_eq, lookup_external_ref): New.
	(optimize_external_refs, optimize_external_refs_1): New.
	(change_AT_die_ref): New.
	(clone_as_declaration): Add DW_AT_signature when cloning a declaration.
	(build_abbrev_table): Take the external refs hashtable.
	(output_comp_unit): Get it from optimize_external_refs and pass it in.

From-SVN: r187116
parent f95f017c
2012-05-02 Jason Merrill <jason@redhat.com>
* dwarf2out.c (struct external_ref, build_local_stub): New.
(hash_external_ref, external_ref_eq, lookup_external_ref): New.
(optimize_external_refs, optimize_external_refs_1): New.
(change_AT_die_ref): New.
(clone_as_declaration): Add DW_AT_signature when cloning a declaration.
(build_abbrev_table): Take the external refs hashtable.
(output_comp_unit): Get it from optimize_external_refs and pass it in.
2012-05-03 Jan Hubicka <jh@suse.cz> 2012-05-03 Jan Hubicka <jh@suse.cz>
PR middle-end/53093 PR middle-end/53093
......
...@@ -2986,7 +2986,7 @@ static void htab_cu_del (void *); ...@@ -2986,7 +2986,7 @@ static void htab_cu_del (void *);
static int check_duplicate_cu (dw_die_ref, htab_t, unsigned *); static int check_duplicate_cu (dw_die_ref, htab_t, unsigned *);
static void record_comdat_symbol_number (dw_die_ref, htab_t, unsigned); static void record_comdat_symbol_number (dw_die_ref, htab_t, unsigned);
static void add_sibling_attributes (dw_die_ref); static void add_sibling_attributes (dw_die_ref);
static void build_abbrev_table (dw_die_ref); static void build_abbrev_table (dw_die_ref, htab_t);
static void output_location_lists (dw_die_ref); static void output_location_lists (dw_die_ref);
static int constant_size (unsigned HOST_WIDE_INT); static int constant_size (unsigned HOST_WIDE_INT);
static unsigned long size_of_die (dw_die_ref); static unsigned long size_of_die (dw_die_ref);
...@@ -3718,6 +3718,16 @@ add_AT_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind, dw_die_ref targ_ ...@@ -3718,6 +3718,16 @@ add_AT_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind, dw_die_ref targ_
add_dwarf_attr (die, &attr); add_dwarf_attr (die, &attr);
} }
/* Change DIE reference REF to point to NEW_DIE instead. */
static inline void
change_AT_die_ref (dw_attr_ref ref, dw_die_ref new_die)
{
gcc_assert (ref->dw_attr_val.val_class == dw_val_class_die_ref);
ref->dw_attr_val.v.val_die_ref.die = new_die;
ref->dw_attr_val.v.val_die_ref.external = 0;
}
/* Add an AT_specification attribute to a DIE, and also make the back /* Add an AT_specification attribute to a DIE, and also make the back
pointer from the specification to the definition. */ pointer from the specification to the definition. */
...@@ -6277,7 +6287,12 @@ clone_as_declaration (dw_die_ref die) ...@@ -6277,7 +6287,12 @@ clone_as_declaration (dw_die_ref die)
/* If the DIE is a specification, just clone its declaration DIE. */ /* If the DIE is a specification, just clone its declaration DIE. */
decl = get_AT_ref (die, DW_AT_specification); decl = get_AT_ref (die, DW_AT_specification);
if (decl != NULL) if (decl != NULL)
return clone_die (decl); {
clone = clone_die (decl);
if (die->comdat_type_p)
add_AT_die_ref (clone, DW_AT_signature, die);
return clone;
}
clone = ggc_alloc_cleared_die_node (); clone = ggc_alloc_cleared_die_node ();
clone->die_tag = die->die_tag; clone->die_tag = die->die_tag;
...@@ -6816,13 +6831,159 @@ output_location_lists (dw_die_ref die) ...@@ -6816,13 +6831,159 @@ output_location_lists (dw_die_ref die)
FOR_EACH_CHILD (die, c, output_location_lists (c)); FOR_EACH_CHILD (die, c, output_location_lists (c));
} }
/* We want to limit the number of external references, because they are
larger than local references: a relocation takes multiple words, and
even a sig8 reference is always eight bytes, whereas a local reference
can be as small as one byte (though DW_FORM_ref is usually 4 in GCC).
So if we encounter multiple external references to the same type DIE, we
make a local typedef stub for it and redirect all references there.
This is the element of the hash table for keeping track of these
references. */
struct external_ref
{
dw_die_ref type;
dw_die_ref stub;
unsigned n_refs;
};
/* Hash an external_ref. */
static hashval_t
hash_external_ref (const void *p)
{
const struct external_ref *r = (const struct external_ref *)p;
return htab_hash_pointer (r->type);
}
/* Compare external_refs. */
static int
external_ref_eq (const void *p1, const void *p2)
{
const struct external_ref *r1 = (const struct external_ref *)p1;
const struct external_ref *r2 = (const struct external_ref *)p2;
return r1->type == r2->type;
}
/* Return a pointer to the external_ref for references to DIE. */
static struct external_ref *
lookup_external_ref (htab_t map, dw_die_ref die)
{
struct external_ref ref, *ref_p;
void ** slot;
ref.type = die;
slot = htab_find_slot (map, &ref, INSERT);
if (*slot != HTAB_EMPTY_ENTRY)
return (struct external_ref *) *slot;
ref_p = XCNEW (struct external_ref);
ref_p->type = die;
*slot = ref_p;
return ref_p;
}
/* Subroutine of optimize_external_refs, below.
If we see a type skeleton, record it as our stub. If we see external
references, remember how many we've seen. */
static void
optimize_external_refs_1 (dw_die_ref die, htab_t map)
{
dw_die_ref c;
dw_attr_ref a;
unsigned ix;
struct external_ref *ref_p;
if (is_type_die (die)
&& (c = get_AT_ref (die, DW_AT_signature)))
{
/* This is a local skeleton; use it for local references. */
ref_p = lookup_external_ref (map, c);
ref_p->stub = die;
}
/* Scan the DIE references, and remember any that refer to DIEs from
other CUs (i.e. those which are not marked). */
FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
if (AT_class (a) == dw_val_class_die_ref
&& (c = AT_ref (a))->die_mark == 0
&& is_type_die (c))
{
ref_p = lookup_external_ref (map, c);
ref_p->n_refs++;
}
FOR_EACH_CHILD (die, c, optimize_external_refs_1 (c, map));
}
/* htab_traverse callback function for optimize_external_refs, below. SLOT
points to an external_ref, DATA is the CU we're processing. If we don't
already have a local stub, and we have multiple refs, build a stub. */
static int
build_local_stub (void **slot, void *data)
{
struct external_ref *ref_p = (struct external_ref *)*slot;
dw_die_ref cu = (dw_die_ref) data;
dw_die_ref type = ref_p->type;
dw_die_ref stub = NULL;
if (ref_p->stub == NULL && ref_p->n_refs > 1)
{
if (!dwarf_strict)
{
/* If we aren't being strict, use a typedef with no name
to just forward to the real type. In strict DWARF, a
typedef must have a name. */
stub = new_die (DW_TAG_typedef, cu, NULL_TREE);
add_AT_die_ref (stub, DW_AT_type, type);
}
else if (type->comdat_type_p)
{
/* If we refer to this type via sig8, we can use a simple
declaration; this is larger than the typedef, but strictly
correct. */
stub = new_die (type->die_tag, cu, NULL_TREE);
add_AT_string (stub, DW_AT_name, get_AT_string (type, DW_AT_name));
add_AT_flag (stub, DW_AT_declaration, 1);
add_AT_die_ref (stub, DW_AT_signature, type);
}
if (stub)
{
stub->die_mark++;
ref_p->stub = stub;
}
}
return 1;
}
/* DIE is a unit; look through all the DIE references to see if there are
any external references to types, and if so, create local stubs for
them which will be applied in build_abbrev_table. This is useful because
references to local DIEs are smaller. */
static htab_t
optimize_external_refs (dw_die_ref die)
{
htab_t map = htab_create (10, hash_external_ref, external_ref_eq, free);
optimize_external_refs_1 (die, map);
htab_traverse (map, build_local_stub, die);
return map;
}
/* The format of each DIE (and its attribute value pairs) is encoded in an /* The format of each DIE (and its attribute value pairs) is encoded in an
abbreviation table. This routine builds the abbreviation table and assigns abbreviation table. This routine builds the abbreviation table and assigns
a unique abbreviation id for each abbreviation entry. The children of each a unique abbreviation id for each abbreviation entry. The children of each
die are visited recursively. */ die are visited recursively. */
static void static void
build_abbrev_table (dw_die_ref die) build_abbrev_table (dw_die_ref die, htab_t extern_map)
{ {
unsigned long abbrev_id; unsigned long abbrev_id;
unsigned int n_alloc; unsigned int n_alloc;
...@@ -6830,14 +6991,22 @@ build_abbrev_table (dw_die_ref die) ...@@ -6830,14 +6991,22 @@ build_abbrev_table (dw_die_ref die)
dw_attr_ref a; dw_attr_ref a;
unsigned ix; unsigned ix;
/* Scan the DIE references, and mark as external any that refer to /* Scan the DIE references, and replace any that refer to
DIEs from other CUs (i.e. those which are not marked). */ DIEs from other CUs (i.e. those which are not marked) with
the local stubs we built in optimize_external_refs. */
FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a) FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
if (AT_class (a) == dw_val_class_die_ref if (AT_class (a) == dw_val_class_die_ref
&& AT_ref (a)->die_mark == 0) && (c = AT_ref (a))->die_mark == 0)
{ {
struct external_ref *ref_p;
gcc_assert (AT_ref (a)->comdat_type_p || AT_ref (a)->die_id.die_symbol); gcc_assert (AT_ref (a)->comdat_type_p || AT_ref (a)->die_id.die_symbol);
set_AT_ref_external (a, 1);
ref_p = lookup_external_ref (extern_map, c);
if (ref_p->stub && ref_p->stub != die)
change_AT_die_ref (a, ref_p->stub);
else
/* We aren't changing this reference, so mark it external. */
set_AT_ref_external (a, 1);
} }
for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id) for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
...@@ -6888,7 +7057,7 @@ build_abbrev_table (dw_die_ref die) ...@@ -6888,7 +7057,7 @@ build_abbrev_table (dw_die_ref die)
} }
die->die_abbrev = abbrev_id; die->die_abbrev = abbrev_id;
FOR_EACH_CHILD (die, c, build_abbrev_table (c)); FOR_EACH_CHILD (die, c, build_abbrev_table (c, extern_map));
} }
/* Return the power-of-two number of bytes necessary to represent VALUE. */ /* Return the power-of-two number of bytes necessary to represent VALUE. */
...@@ -7811,6 +7980,7 @@ output_comp_unit (dw_die_ref die, int output_if_empty) ...@@ -7811,6 +7980,7 @@ output_comp_unit (dw_die_ref die, int output_if_empty)
{ {
const char *secname, *oldsym; const char *secname, *oldsym;
char *tmp; char *tmp;
htab_t extern_map;
/* Unless we are outputting main CU, we may throw away empty ones. */ /* Unless we are outputting main CU, we may throw away empty ones. */
if (!output_if_empty && die->die_child == NULL) if (!output_if_empty && die->die_child == NULL)
...@@ -7823,7 +7993,11 @@ output_comp_unit (dw_die_ref die, int output_if_empty) ...@@ -7823,7 +7993,11 @@ output_comp_unit (dw_die_ref die, int output_if_empty)
this CU so we know which get local refs. */ this CU so we know which get local refs. */
mark_dies (die); mark_dies (die);
build_abbrev_table (die); extern_map = optimize_external_refs (die);
build_abbrev_table (die, extern_map);
htab_delete (extern_map);
/* Initialize the beginning DIE offset - and calculate sizes/offsets. */ /* Initialize the beginning DIE offset - and calculate sizes/offsets. */
next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE; next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
...@@ -7870,11 +8044,16 @@ output_comdat_type_unit (comdat_type_node *node) ...@@ -7870,11 +8044,16 @@ output_comdat_type_unit (comdat_type_node *node)
#if defined (OBJECT_FORMAT_ELF) #if defined (OBJECT_FORMAT_ELF)
tree comdat_key; tree comdat_key;
#endif #endif
htab_t extern_map;
/* First mark all the DIEs in this CU so we know which get local refs. */ /* First mark all the DIEs in this CU so we know which get local refs. */
mark_dies (node->root_die); mark_dies (node->root_die);
build_abbrev_table (node->root_die); extern_map = optimize_external_refs (node->root_die);
build_abbrev_table (node->root_die, extern_map);
htab_delete (extern_map);
/* Initialize the beginning DIE offset - and calculate sizes/offsets. */ /* Initialize the beginning DIE offset - and calculate sizes/offsets. */
next_die_offset = DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE; next_die_offset = DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE;
......
2012-05-03 Jason Merrill <jason@redhat.com> 2012-05-03 Jason Merrill <jason@redhat.com>
* g++.dg/debug/dwarf2/nested-3.C: Adjust pattern.
* gcc.dg/debug/dwarf2/dups-types.c: New. * gcc.dg/debug/dwarf2/dups-types.c: New.
* gcc.dg/debug/dwarf2/dups-types.h: New. * gcc.dg/debug/dwarf2/dups-types.h: New.
......
...@@ -37,6 +37,14 @@ main () ...@@ -37,6 +37,14 @@ main ()
// .uleb128 0x9 # (DIE (0x34) DW_TAG_class_type) // .uleb128 0x9 # (DIE (0x34) DW_TAG_class_type)
// .long .LASF0 # DW_AT_name: "Executor" // .long .LASF0 # DW_AT_name: "Executor"
// # DW_AT_declaration // # DW_AT_declaration
// .byte 0xa0 # DW_AT_signature
// .byte 0xfe
// .byte 0xe6
// .byte 0x7b
// .byte 0x66
// .byte 0xe9
// .byte 0x38
// .byte 0xf0
// .uleb128 0x5 # (DIE (0x39) DW_TAG_subprogram) // .uleb128 0x5 # (DIE (0x39) DW_TAG_subprogram)
// # DW_AT_external // # DW_AT_external
// .long .LASF1 # DW_AT_name: "CurrentExecutor" // .long .LASF1 # DW_AT_name: "CurrentExecutor"
...@@ -51,4 +59,4 @@ main () ...@@ -51,4 +59,4 @@ main ()
// //
// Hence the scary regexp: // Hence the scary regexp:
// //
// { dg-final { scan-assembler "\[^\n\r\]*\\(DIE \\(0x(\[0-9a-f\]+)\\) DW_TAG_namespace\\)\[\n\r\]+\[^\n\r\]*\"thread\[\^\n\r]+\[\n\r\]+(\[^\n\r\]*\[\n\r\]+)+\[^\n\r\]*\\(DIE \\(0x(\[0-9a-f\]+)\\) DW_TAG_class_type\\)(\[\n\r\]+\[^\n\r\]*)+\"Executor\[^\n\r\]+\[\n\r\]+\[^\n\r\]*DW_AT_declaration\[\n\r\]+\[^\n\r\]*\\(DIE\[^\n\r\]*DW_TAG_subprogram\\)\[\n\r\]+(\[^\n\r\]*\[\n\r\]+)+\[^\n\r\]*\"CurrentExecutor\[^\n\r\]+\[\n\r\]+(\[^\n\r\]*\[\n\r\]+)+(\[^\n\r\]*\[\n\r\]+)+\[^\n\r\]*end of children of DIE 0x\\3\[\n\r]+\[^\n\r\]*end of children of DIE 0x\\1\[\n\r]+" } } // { dg-final { scan-assembler "\[^\n\r\]*\\(DIE \\(0x(\[0-9a-f\]+)\\) DW_TAG_namespace\\)\[\n\r\]+\[^\n\r\]*\"thread\[\^\n\r]+\[\n\r\]+(\[^\n\r\]*\[\n\r\]+)+\[^\n\r\]*\\(DIE \\(0x(\[0-9a-f\]+)\\) DW_TAG_class_type\\)(\[\n\r\]+\[^\n\r\]*)+\"Executor\[^\n\r\]+\[\n\r\]+\[^\n\r\]*DW_AT_declaration\[\n\r\]+\[^\n\r\]*DW_AT_signature\[^#\]*# \\(DIE\[^\n\r\]*DW_TAG_subprogram\\)\[\n\r\]+(\[^\n\r\]*\[\n\r\]+)+\[^\n\r\]*\"CurrentExecutor\[^\n\r\]+\[\n\r\]+(\[^\n\r\]*\[\n\r\]+)+(\[^\n\r\]*\[\n\r\]+)+\[^\n\r\]*end of children of DIE 0x\\3\[\n\r]+\[^\n\r\]*end of children of DIE 0x\\1\[\n\r]+" } }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment