diff options
author | Cary Coutant <ccoutant@google.com> | 2009-10-02 20:44:09 +0000 |
---|---|---|
committer | Cary Coutant <ccoutant@gcc.gnu.org> | 2009-10-02 13:44:09 -0700 |
commit | 15b3fbeb7e97f2ca3731881bf3a0f899ec56ebbf (patch) | |
tree | 4468285ea24669cbd92f07d38982098e08547294 /gcc | |
parent | e9cfc9b5f4d7eca860c207ee89ad7ca0b24e481e (diff) | |
download | gcc-15b3fbeb7e97f2ca3731881bf3a0f899ec56ebbf.zip gcc-15b3fbeb7e97f2ca3731881bf3a0f899ec56ebbf.tar.gz gcc-15b3fbeb7e97f2ca3731881bf3a0f899ec56ebbf.tar.bz2 |
Add support for comdat type sections for DWARF v4.
Add support for comdat type sections for DWARF v4. Merge from dwarf4
branch.
* dwarf2out.c (DWARF_TYPE_SIGNATURE_SIZE): New constant.
(dw_die_ref): Define vector type.
(enum dw_val_class): Add dw_val_class_data8.
(struct dw_val_struct): Add v.val_data8.
(comdat_type_node_ref): New type.
(struct die_struct): Move die_symbol into a union; add new field
die_type_node. Change all uses.
(comdat_type_node): New type.
(skeleton_chain_node): New type.
(DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE): New constant.
(comdat_type_list): New variable.
(dwarf_tag_name): Add DW_TAG_type_unit.
(dwarf_attr_name): Add DW_AT_signature.
(add_AT_data8): New function.
(replace_child): New function.
(move_all_children): New function.
(print_signature): New function.
(print_die): Print signature information; add dw_val_class_data8.
(attr_checksum): Support dw_val_class_data8.
(CHECKSUM_STRING): Redefine for DWARF-4 to include
trailing NULL byte.
(CHECKSUM_SLEB128, CHECKSUM_ULEB128): New macros.
(checksum_sleb128, checksum_uleb128): New functions.
(checksum_die_context): New function.
(loc_checksum_ordered): New function.
(attr_checksum_ordered): New function.
(struct checksum_attributes): New structure.
(collect_checksum_attributes): New function.
(die_checksum_ordered): New function.
(generate_type_signature): New function.
(same_dw_val_p): Add dw_val_class_data8.
(is_symbol_die): Use new is_declaration_die function.
(is_declaration_die): New function.
(should_move_die_to_comdat): New function.
(clone_die): New function.
(clone_tree): New function.
(clone_as_declaration): New function.
(copy_declaration_context): New function.
(generate_skeleton_ancestor_tree): New function.
(generate_skeleton_bottom_up): New function.
(generate_skeleton): New function.
(remove_child_or_replace_with_skeleton): New function.
(break_out_comdat_types): New function.
(struct decl_table_entry): New type.
(htab_decl_hash): New function.
(htab_decl_eq): New function.
(htab_decl_del): New function.
(copy_ancestor_tree): New function.
(copy_decls_walk): New function.
(copy_decls_for_unworthy_types): New function.
(build_abbrev_table): Don't assert on missing die_symbol when doing
comdat type sections.
(size_of_die): Use DW_FORM_sig8 for external references; Add
dw_val_class_data8.
(unmark_dies): Don't assert for unmarked dies when doing comdat
type sections.
(value_format): Support DW_FORM_sig8 and dw_val_class_data8.
(output_signature): New function.
(output_die): Likewise.
(output_compilation_unit_header): Mark output as DWARF version 3
even if generating DWARF 4.
(output_comdat_type_unit): New function.
(output_line_info): Mark output as DWARF version 3 even if generating
DWARF 4.
(dwarf2out_start_source_file): Don't do eliminate_dwarf2_dups with
DWARF-4.
(dwarf2out_end_source_file): Likewise.
(prune_unused_types_walk_attribs): Don't follow references into
comdat type sections.
(prune_unused_types_mark): When generating type units, do not mark
children of non-defining declarations of types; do mark children of
type entries.
(prune_unused_types): Process comdat type sections.
(htab_ct_hash): New function.
(htab_ct_eq): New function.
(dwarf2out_finish): Move types to comdat sections when using DWARF-4.
Add a pointer to the line table from type unit entries so
DW_AT_decl_file has meaning.
* varasm.c (default_elf_asm_named_section): Use identifier name as
comdat key instead of lang hook.
From-SVN: r152421
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 85 | ||||
-rw-r--r-- | gcc/dwarf2out.c | 1616 | ||||
-rw-r--r-- | gcc/varasm.c | 9 |
3 files changed, 1664 insertions, 46 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c13fe4f..7263e90 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,88 @@ +2009-10-02 Cary Coutant <ccoutant@google.com> + + Add support for comdat type sections for DWARF v4. Merge from dwarf4 + branch. + * dwarf2out.c (DWARF_TYPE_SIGNATURE_SIZE): New constant. + (dw_die_ref): Define vector type. + (enum dw_val_class): Add dw_val_class_data8. + (struct dw_val_struct): Add v.val_data8. + (comdat_type_node_ref): New type. + (struct die_struct): Move die_symbol into a union; add new field + die_type_node. Change all uses. + (comdat_type_node): New type. + (skeleton_chain_node): New type. + (DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE): New constant. + (comdat_type_list): New variable. + (dwarf_tag_name): Add DW_TAG_type_unit. + (dwarf_attr_name): Add DW_AT_signature. + (add_AT_data8): New function. + (replace_child): New function. + (move_all_children): New function. + (print_signature): New function. + (print_die): Print signature information; add dw_val_class_data8. + (attr_checksum): Support dw_val_class_data8. + (CHECKSUM_STRING): Redefine for DWARF-4 to include + trailing NULL byte. + (CHECKSUM_SLEB128, CHECKSUM_ULEB128): New macros. + (checksum_sleb128, checksum_uleb128): New functions. + (checksum_die_context): New function. + (loc_checksum_ordered): New function. + (attr_checksum_ordered): New function. + (struct checksum_attributes): New structure. + (collect_checksum_attributes): New function. + (die_checksum_ordered): New function. + (generate_type_signature): New function. + (same_dw_val_p): Add dw_val_class_data8. + (is_symbol_die): Use new is_declaration_die function. + (is_declaration_die): New function. + (should_move_die_to_comdat): New function. + (clone_die): New function. + (clone_tree): New function. + (clone_as_declaration): New function. + (copy_declaration_context): New function. + (generate_skeleton_ancestor_tree): New function. + (generate_skeleton_bottom_up): New function. + (generate_skeleton): New function. + (remove_child_or_replace_with_skeleton): New function. + (break_out_comdat_types): New function. + (struct decl_table_entry): New type. + (htab_decl_hash): New function. + (htab_decl_eq): New function. + (htab_decl_del): New function. + (copy_ancestor_tree): New function. + (copy_decls_walk): New function. + (copy_decls_for_unworthy_types): New function. + (build_abbrev_table): Don't assert on missing die_symbol when doing + comdat type sections. + (size_of_die): Use DW_FORM_sig8 for external references; Add + dw_val_class_data8. + (unmark_dies): Don't assert for unmarked dies when doing comdat + type sections. + (value_format): Support DW_FORM_sig8 and dw_val_class_data8. + (output_signature): New function. + (output_die): Likewise. + (output_compilation_unit_header): Mark output as DWARF version 3 + even if generating DWARF 4. + (output_comdat_type_unit): New function. + (output_line_info): Mark output as DWARF version 3 even if generating + DWARF 4. + (dwarf2out_start_source_file): Don't do eliminate_dwarf2_dups with + DWARF-4. + (dwarf2out_end_source_file): Likewise. + (prune_unused_types_walk_attribs): Don't follow references into + comdat type sections. + (prune_unused_types_mark): When generating type units, do not mark + children of non-defining declarations of types; do mark children of + type entries. + (prune_unused_types): Process comdat type sections. + (htab_ct_hash): New function. + (htab_ct_eq): New function. + (dwarf2out_finish): Move types to comdat sections when using DWARF-4. + Add a pointer to the line table from type unit entries so + DW_AT_decl_file has meaning. + * varasm.c (default_elf_asm_named_section): Use identifier name as + comdat key instead of lang hook. + 2009-10-02 Neil Vachharajani <nvachhar@google.com> * gcov-io.c (gcov_open): Open files read-only when MODE < 0 diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 2728cfd..26e8594 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -348,6 +348,12 @@ dw_fde_node; #define DWARF_OFFSET_SIZE 4 #endif +/* The size in bytes of a DWARF 4 type signature. */ + +#ifndef DWARF_TYPE_SIGNATURE_SIZE +#define DWARF_TYPE_SIGNATURE_SIZE 8 +#endif + /* According to the (draft) DWARF 3 specification, the initial length should either be 4 or 12 bytes. When it's 12 bytes, the first 4 bytes are 0xffffffff, followed by the length stored in the next 8 @@ -4155,6 +4161,9 @@ DEF_VEC_ALLOC_O(deferred_locations,gc); static GTY(()) VEC(deferred_locations, gc) *deferred_locations_list; +DEF_VEC_P(dw_die_ref); +DEF_VEC_ALLOC_P(dw_die_ref,heap); + /* Each DIE may have a series of attribute/value pairs. Values can take on several forms. The forms that are used in this implementation are listed below. */ @@ -4177,7 +4186,8 @@ enum dw_val_class dw_val_class_lineptr, dw_val_class_str, dw_val_class_macptr, - dw_val_class_file + dw_val_class_file, + dw_val_class_data8 }; /* Describe a floating point constant value, or a vector constant value. */ @@ -4214,6 +4224,7 @@ typedef struct GTY(()) dw_val_struct { char * GTY ((tag ("dw_val_class_lbl_id"))) val_lbl_id; unsigned char GTY ((tag ("dw_val_class_flag"))) val_flag; struct dwarf_file_data * GTY ((tag ("dw_val_class_file"))) val_file; + unsigned char GTY ((tag ("dw_val_class_data8"))) val_data8[8]; } GTY ((desc ("%1.val_class"))) v; } @@ -5464,6 +5475,7 @@ typedef struct dw_separate_line_info_struct *dw_separate_line_info_ref; typedef struct pubname_struct *pubname_ref; typedef struct dw_ranges_struct *dw_ranges_ref; typedef struct dw_ranges_by_label_struct *dw_ranges_by_label_ref; +typedef struct comdat_type_struct *comdat_type_node_ref; /* Each entry in the line_info_table maintains the file and line number associated with the label generated for that @@ -5504,7 +5516,12 @@ DEF_VEC_ALLOC_O(dw_attr_node,gc); typedef struct GTY((chain_circular ("%h.die_sib"))) die_struct { enum dwarf_tag die_tag; - char *die_symbol; + union die_symbol_or_type_node + { + char * GTY ((tag ("0"))) die_symbol; + comdat_type_node_ref GTY ((tag ("1"))) die_type_node; + } + GTY ((desc ("dwarf_version >= 4"))) die_id; VEC(dw_attr_node,gc) * die_attr; dw_die_ref die_parent; dw_die_ref die_child; @@ -5550,6 +5567,16 @@ struct GTY(()) dw_ranges_by_label_struct { const char *end; }; +/* The comdat type node structure. */ +typedef struct GTY(()) comdat_type_struct +{ + dw_die_ref root_die; + dw_die_ref type_die; + char signature[DWARF_TYPE_SIGNATURE_SIZE]; + struct comdat_type_struct *next; +} +comdat_type_node; + /* The limbo die list structure. */ typedef struct GTY(()) limbo_die_struct { dw_die_ref die; @@ -5558,6 +5585,14 @@ typedef struct GTY(()) limbo_die_struct { } limbo_die_node; +typedef struct GTY(()) skeleton_chain_struct +{ + dw_die_ref old_die; + dw_die_ref new_die; + struct skeleton_chain_struct *parent; +} +skeleton_chain_node; + /* How to start an assembler comment. */ #ifndef ASM_COMMENT_START #define ASM_COMMENT_START ";#" @@ -5591,6 +5626,11 @@ limbo_die_node; #define DWARF_COMPILE_UNIT_HEADER_SIZE \ (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 3) +/* Fixed size portion of the DWARF comdat type unit header. */ +#define DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE \ + (DWARF_COMPILE_UNIT_HEADER_SIZE + DWARF_TYPE_SIGNATURE_SIZE \ + + DWARF_OFFSET_SIZE) + /* Fixed size portion of public names info. */ #define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2) @@ -5641,6 +5681,9 @@ static unsigned long next_die_offset; /* Record the root of the DIE's built for the current compilation unit. */ static GTY(()) dw_die_ref comp_unit_die; +/* A list of type DIEs that have been separated into comdat sections. */ +static GTY(()) comdat_type_node *comdat_type_list; + /* A list of DIEs with a NULL parent waiting to be relocated. */ static GTY(()) limbo_die_node *limbo_die_list; @@ -5832,6 +5875,7 @@ static void add_AT_double (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT, unsigned HOST_WIDE_INT); static inline void add_AT_vec (dw_die_ref, enum dwarf_attribute, unsigned int, unsigned int, unsigned char *); +static void add_AT_data8 (dw_die_ref, enum dwarf_attribute, unsigned char *); static hashval_t debug_str_do_hash (const void *); static int debug_str_eq (const void *, const void *); static void add_AT_string (dw_die_ref, enum dwarf_attribute, const char *); @@ -5894,6 +5938,16 @@ static dw_die_ref pop_compile_unit (dw_die_ref); static void loc_checksum (dw_loc_descr_ref, struct md5_ctx *); static void attr_checksum (dw_attr_ref, struct md5_ctx *, int *); static void die_checksum (dw_die_ref, struct md5_ctx *, int *); +static void checksum_sleb128 (HOST_WIDE_INT, struct md5_ctx *); +static void checksum_uleb128 (unsigned HOST_WIDE_INT, struct md5_ctx *); +static void loc_checksum_ordered (dw_loc_descr_ref, struct md5_ctx *); +static void attr_checksum_ordered (enum dwarf_tag, dw_attr_ref, + struct md5_ctx *, int *); +struct checksum_attributes; +static void collect_checksum_attributes (struct checksum_attributes *, dw_die_ref); +static void die_checksum_ordered (dw_die_ref, struct md5_ctx *, int *); +static void checksum_die_context (dw_die_ref, struct md5_ctx *); +static void generate_type_signature (dw_die_ref, comdat_type_node *); static int same_loc_p (dw_loc_descr_ref, dw_loc_descr_ref, int *); 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 *); @@ -5905,6 +5959,22 @@ static int is_comdat_die (dw_die_ref); static int is_symbol_die (dw_die_ref); static void assign_symbol_names (dw_die_ref); static void break_out_includes (dw_die_ref); +static int is_declaration_die (dw_die_ref); +static int should_move_die_to_comdat (dw_die_ref); +static dw_die_ref clone_as_declaration (dw_die_ref); +static dw_die_ref clone_die (dw_die_ref); +static dw_die_ref clone_tree (dw_die_ref); +static void copy_declaration_context (dw_die_ref, dw_die_ref); +static void generate_skeleton_ancestor_tree (skeleton_chain_node *); +static void generate_skeleton_bottom_up (skeleton_chain_node *); +static dw_die_ref generate_skeleton (dw_die_ref); +static dw_die_ref remove_child_or_replace_with_skeleton (dw_die_ref, + dw_die_ref); +static void break_out_comdat_types (dw_die_ref); +static dw_die_ref copy_ancestor_tree (dw_die_ref, dw_die_ref, htab_t); +static void copy_decls_walk (dw_die_ref, dw_die_ref, htab_t); +static void copy_decls_for_unworthy_types (dw_die_ref); + static hashval_t htab_cu_hash (const void *); static int htab_cu_eq (const void *, const void *); static void htab_cu_del (void *); @@ -5928,6 +5998,7 @@ static void output_die_symbol (dw_die_ref); static void output_die (dw_die_ref); static void output_compilation_unit_header (void); static void output_comp_unit (dw_die_ref, int); +static void output_comdat_type_unit (comdat_type_node *); static const char *dwarf2_name (tree, int); static void add_pubname (tree, dw_die_ref); static void add_pubname_string (const char *, dw_die_ref); @@ -6352,6 +6423,8 @@ dwarf_tag_name (unsigned int tag) return "DW_TAG_condition"; case DW_TAG_shared_type: return "DW_TAG_shared_type"; + case DW_TAG_type_unit: + return "DW_TAG_type_unit"; case DW_TAG_GNU_template_parameter_pack: return "DW_TAG_GNU_template_parameter_pack"; case DW_TAG_GNU_formal_parameter_pack: @@ -6534,6 +6607,9 @@ dwarf_attr_name (unsigned int attr) case DW_AT_call_line: return "DW_AT_call_line"; + case DW_AT_signature: + return "DW_AT_signature"; + case DW_AT_MIPS_fde: return "DW_AT_MIPS_fde"; case DW_AT_MIPS_loop_begin: @@ -6794,6 +6870,20 @@ add_AT_vec (dw_die_ref die, enum dwarf_attribute attr_kind, add_dwarf_attr (die, &attr); } +/* Add an 8-byte data attribute value to a DIE. */ + +static inline void +add_AT_data8 (dw_die_ref die, enum dwarf_attribute attr_kind, + unsigned char data8[8]) +{ + dw_attr_node attr; + + attr.dw_attr = attr_kind; + attr.dw_attr_val.val_class = dw_val_class_data8; + memcpy (attr.dw_attr_val.v.val_data8, data8, 8); + add_dwarf_attr (die, &attr); +} + /* Hash and equality functions for debug_str_hash. */ static hashval_t @@ -7347,6 +7437,43 @@ remove_child_with_prev (dw_die_ref child, dw_die_ref prev) child->die_parent->die_child = prev; } +/* Replace OLD_CHILD with NEW_CHILD. PREV must have the property that + PREV->DIE_SIB == OLD_CHILD. Does not alter OLD_CHILD. */ + +static void +replace_child (dw_die_ref old_child, dw_die_ref new_child, dw_die_ref prev) +{ + dw_die_ref parent = old_child->die_parent; + + gcc_assert (parent == prev->die_parent); + gcc_assert (prev->die_sib == old_child); + + new_child->die_parent = parent; + if (prev == old_child) + { + gcc_assert (parent->die_child == old_child); + new_child->die_sib = new_child; + } + else + { + prev->die_sib = new_child; + new_child->die_sib = old_child->die_sib; + } + if (old_child->die_parent->die_child == old_child) + old_child->die_parent->die_child = new_child; +} + +/* Move all children from OLD_PARENT to NEW_PARENT. */ + +static void +move_all_children (dw_die_ref old_parent, dw_die_ref new_parent) +{ + dw_die_ref c; + new_parent->die_child = old_parent->die_child; + old_parent->die_child = NULL; + FOR_EACH_CHILD (new_parent, c, c->die_parent = new_parent); +} + /* Remove child DIE whose die_tag is TAG. Do nothing if no child matches TAG. */ @@ -7589,6 +7716,17 @@ print_spaces (FILE *outfile) fprintf (outfile, "%*s", print_indent, ""); } +/* Print a type signature in hex. */ + +static inline void +print_signature (FILE *outfile, char *sig) +{ + int i; + + for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++) + fprintf (outfile, "%02x", sig[i] & 0xff); +} + /* Print the information associated with a given DIE, and its children. This routine is a debugging aid only. */ @@ -7605,6 +7743,13 @@ print_die (dw_die_ref die, FILE *outfile) print_spaces (outfile); fprintf (outfile, " abbrev id: %lu", die->die_abbrev); fprintf (outfile, " offset: %ld\n", die->die_offset); + if (dwarf_version >= 4 && die->die_id.die_type_node) + { + print_spaces (outfile); + fprintf (outfile, " signature: "); + print_signature (outfile, die->die_id.die_type_node->signature); + fprintf (outfile, "\n"); + } for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++) { @@ -7650,8 +7795,15 @@ print_die (dw_die_ref die, FILE *outfile) case dw_val_class_die_ref: if (AT_ref (a) != NULL) { - if (AT_ref (a)->die_symbol) - fprintf (outfile, "die -> label: %s", AT_ref (a)->die_symbol); + if (dwarf_version >= 4 && AT_ref (a)->die_id.die_type_node) + { + fprintf (outfile, "die -> signature: "); + print_signature (outfile, + AT_ref (a)->die_id.die_type_node->signature); + } + else if (dwarf_version < 4 && AT_ref (a)->die_id.die_symbol) + fprintf (outfile, "die -> label: %s", + AT_ref (a)->die_id.die_symbol); else fprintf (outfile, "die -> %ld", AT_ref (a)->die_offset); } @@ -7673,6 +7825,14 @@ print_die (dw_die_ref die, FILE *outfile) fprintf (outfile, "\"%s\" (%d)", AT_file (a)->filename, AT_file (a)->emitted_number); break; + case dw_val_class_data8: + { + int i; + + for (i = 0; i < 8; i++) + fprintf (outfile, "%02x", a->dw_attr_val.v.val_data8[i]); + break; + } default: break; } @@ -7837,6 +7997,10 @@ attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark) CHECKSUM_STRING (AT_file (at)->filename); break; + case dw_val_class_data8: + CHECKSUM (at->dw_attr_val.v.val_data8); + break; + default: break; } @@ -7870,6 +8034,626 @@ die_checksum (dw_die_ref die, struct md5_ctx *ctx, int *mark) #undef CHECKSUM #undef CHECKSUM_STRING +/* For DWARF-4 types, include the trailing NULL when checksumming strings. */ +#define CHECKSUM(FOO) md5_process_bytes (&(FOO), sizeof (FOO), ctx) +#define CHECKSUM_STRING(FOO) md5_process_bytes ((FOO), strlen (FOO) + 1, ctx) +#define CHECKSUM_SLEB128(FOO) checksum_sleb128 ((FOO), ctx) +#define CHECKSUM_ULEB128(FOO) checksum_uleb128 ((FOO), ctx) +#define CHECKSUM_ATTR(FOO) \ + if (FOO) attr_checksum_ordered (die->die_tag, (FOO), ctx, mark) + +/* Calculate the checksum of a number in signed LEB128 format. */ + +static void +checksum_sleb128 (HOST_WIDE_INT value, struct md5_ctx *ctx) +{ + unsigned char byte; + bool more; + + while (1) + { + byte = (value & 0x7f); + value >>= 7; + more = !((value == 0 && (byte & 0x40) == 0) + || (value == -1 && (byte & 0x40) != 0)); + if (more) + byte |= 0x80; + CHECKSUM (byte); + if (!more) + break; + } +} + +/* Calculate the checksum of a number in unsigned LEB128 format. */ + +static void +checksum_uleb128 (unsigned HOST_WIDE_INT value, struct md5_ctx *ctx) +{ + while (1) + { + unsigned char byte = (value & 0x7f); + value >>= 7; + if (value != 0) + /* More bytes to follow. */ + byte |= 0x80; + CHECKSUM (byte); + if (value == 0) + break; + } +} + +/* Checksum the context of the DIE. This adds the names of any + surrounding namespaces or structures to the checksum. */ + +static void +checksum_die_context (dw_die_ref die, struct md5_ctx *ctx) +{ + const char *name; + dw_die_ref spec; + int tag = die->die_tag; + + if (tag != DW_TAG_namespace + && tag != DW_TAG_structure_type + && tag != DW_TAG_class_type) + return; + + name = get_AT_string (die, DW_AT_name); + + spec = get_AT_ref (die, DW_AT_specification); + if (spec != NULL) + die = spec; + + if (die->die_parent != NULL) + checksum_die_context (die->die_parent, ctx); + + CHECKSUM_ULEB128 ('C'); + CHECKSUM_ULEB128 (tag); + if (name != NULL) + CHECKSUM_STRING (name); +} + +/* Calculate the checksum of a location expression. */ + +static inline void +loc_checksum_ordered (dw_loc_descr_ref loc, struct md5_ctx *ctx) +{ + /* Special case for lone DW_OP_plus_uconst: checksum as if the location + were emitted as a DW_FORM_sdata instead of a location expression. */ + if (loc->dw_loc_opc == DW_OP_plus_uconst && loc->dw_loc_next == NULL) + { + CHECKSUM_ULEB128 (DW_FORM_sdata); + CHECKSUM_SLEB128 ((HOST_WIDE_INT) loc->dw_loc_oprnd1.v.val_unsigned); + return; + } + + /* Otherwise, just checksum the raw location expression. */ + while (loc != NULL) + { + CHECKSUM_ULEB128 (loc->dw_loc_opc); + CHECKSUM (loc->dw_loc_oprnd1); + CHECKSUM (loc->dw_loc_oprnd2); + loc = loc->dw_loc_next; + } +} + +/* Calculate the checksum of an attribute. */ + +static void +attr_checksum_ordered (enum dwarf_tag tag, dw_attr_ref at, + struct md5_ctx *ctx, int *mark) +{ + dw_loc_descr_ref loc; + rtx r; + + if (AT_class (at) == dw_val_class_die_ref) + { + dw_die_ref target_die = AT_ref (at); + + /* For pointer and reference types, we checksum only the (qualified) + name of the target type (if there is a name). For friend entries, + we checksum only the (qualified) name of the target type or function. + This allows the checksum to remain the same whether the target type + is complete or not. */ + if ((at->dw_attr == DW_AT_type + && (tag == DW_TAG_pointer_type + || tag == DW_TAG_reference_type + || tag == DW_TAG_ptr_to_member_type)) + || (at->dw_attr == DW_AT_friend + && tag == DW_TAG_friend)) + { + dw_attr_ref name_attr = get_AT (target_die, DW_AT_name); + + if (name_attr != NULL) + { + dw_die_ref decl = get_AT_ref (target_die, DW_AT_specification); + + if (decl == NULL) + decl = target_die; + CHECKSUM_ULEB128 ('N'); + CHECKSUM_ULEB128 (at->dw_attr); + if (decl->die_parent != NULL) + checksum_die_context (decl->die_parent, ctx); + CHECKSUM_ULEB128 ('E'); + CHECKSUM_STRING (AT_string (name_attr)); + return; + } + } + + /* For all other references to another DIE, we check to see if the + target DIE has already been visited. If it has, we emit a + backward reference; if not, we descend recursively. */ + if (target_die->die_mark > 0) + { + CHECKSUM_ULEB128 ('R'); + CHECKSUM_ULEB128 (at->dw_attr); + CHECKSUM_ULEB128 (target_die->die_mark); + } + else + { + dw_die_ref decl = get_AT_ref (target_die, DW_AT_specification); + + if (decl == NULL) + decl = target_die; + target_die->die_mark = ++(*mark); + CHECKSUM_ULEB128 ('T'); + CHECKSUM_ULEB128 (at->dw_attr); + if (decl->die_parent != NULL) + checksum_die_context (decl->die_parent, ctx); + die_checksum_ordered (target_die, ctx, mark); + } + return; + } + + CHECKSUM_ULEB128 ('A'); + CHECKSUM_ULEB128 (at->dw_attr); + + switch (AT_class (at)) + { + case dw_val_class_const: + CHECKSUM_ULEB128 (DW_FORM_sdata); + CHECKSUM_SLEB128 (at->dw_attr_val.v.val_int); + break; + + case dw_val_class_unsigned_const: + CHECKSUM_ULEB128 (DW_FORM_sdata); + CHECKSUM_SLEB128 ((int) at->dw_attr_val.v.val_unsigned); + break; + + case dw_val_class_const_double: + CHECKSUM_ULEB128 (DW_FORM_block); + CHECKSUM_ULEB128 (sizeof (at->dw_attr_val.v.val_double)); + CHECKSUM (at->dw_attr_val.v.val_double); + break; + + case dw_val_class_vec: + CHECKSUM_ULEB128 (DW_FORM_block); + CHECKSUM_ULEB128 (sizeof (at->dw_attr_val.v.val_vec)); + CHECKSUM (at->dw_attr_val.v.val_vec); + break; + + case dw_val_class_flag: + CHECKSUM_ULEB128 (DW_FORM_flag); + CHECKSUM_ULEB128 (at->dw_attr_val.v.val_flag ? 1 : 0); + break; + + case dw_val_class_str: + CHECKSUM_ULEB128 (DW_FORM_string); + CHECKSUM_STRING (AT_string (at)); + break; + + case dw_val_class_addr: + r = AT_addr (at); + gcc_assert (GET_CODE (r) == SYMBOL_REF); + CHECKSUM_ULEB128 (DW_FORM_string); + CHECKSUM_STRING (XSTR (r, 0)); + break; + + case dw_val_class_offset: + CHECKSUM_ULEB128 (DW_FORM_sdata); + CHECKSUM_ULEB128 (at->dw_attr_val.v.val_offset); + break; + + case dw_val_class_loc: + for (loc = AT_loc (at); loc; loc = loc->dw_loc_next) + loc_checksum_ordered (loc, ctx); + break; + + case dw_val_class_fde_ref: + case dw_val_class_lbl_id: + case dw_val_class_lineptr: + case dw_val_class_macptr: + break; + + case dw_val_class_file: + CHECKSUM_ULEB128 (DW_FORM_string); + CHECKSUM_STRING (AT_file (at)->filename); + break; + + case dw_val_class_data8: + CHECKSUM (at->dw_attr_val.v.val_data8); + break; + + default: + break; + } +} + +struct checksum_attributes +{ + dw_attr_ref at_name; + dw_attr_ref at_type; + dw_attr_ref at_friend; + dw_attr_ref at_accessibility; + dw_attr_ref at_address_class; + dw_attr_ref at_allocated; + dw_attr_ref at_artificial; + dw_attr_ref at_associated; + dw_attr_ref at_binary_scale; + dw_attr_ref at_bit_offset; + dw_attr_ref at_bit_size; + dw_attr_ref at_bit_stride; + dw_attr_ref at_byte_size; + dw_attr_ref at_byte_stride; + dw_attr_ref at_const_value; + dw_attr_ref at_containing_type; + dw_attr_ref at_count; + dw_attr_ref at_data_location; + dw_attr_ref at_data_member_location; + dw_attr_ref at_decimal_scale; + dw_attr_ref at_decimal_sign; + dw_attr_ref at_default_value; + dw_attr_ref at_digit_count; + dw_attr_ref at_discr; + dw_attr_ref at_discr_list; + dw_attr_ref at_discr_value; + dw_attr_ref at_encoding; + dw_attr_ref at_endianity; + dw_attr_ref at_explicit; + dw_attr_ref at_is_optional; + dw_attr_ref at_location; + dw_attr_ref at_lower_bound; + dw_attr_ref at_mutable; + dw_attr_ref at_ordering; + dw_attr_ref at_picture_string; + dw_attr_ref at_prototyped; + dw_attr_ref at_small; + dw_attr_ref at_segment; + dw_attr_ref at_string_length; + dw_attr_ref at_threads_scaled; + dw_attr_ref at_upper_bound; + dw_attr_ref at_use_location; + dw_attr_ref at_use_UTF8; + dw_attr_ref at_variable_parameter; + dw_attr_ref at_virtuality; + dw_attr_ref at_visibility; + dw_attr_ref at_vtable_elem_location; +}; + +/* Collect the attributes that we will want to use for the checksum. */ + +static void +collect_checksum_attributes (struct checksum_attributes *attrs, dw_die_ref die) +{ + dw_attr_ref a; + unsigned ix; + + for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++) + { + switch (a->dw_attr) + { + case DW_AT_name: + attrs->at_name = a; + break; + case DW_AT_type: + attrs->at_type = a; + break; + case DW_AT_friend: + attrs->at_friend = a; + break; + case DW_AT_accessibility: + attrs->at_accessibility = a; + break; + case DW_AT_address_class: + attrs->at_address_class = a; + break; + case DW_AT_allocated: + attrs->at_allocated = a; + break; + case DW_AT_artificial: + attrs->at_artificial = a; + break; + case DW_AT_associated: + attrs->at_associated = a; + break; + case DW_AT_binary_scale: + attrs->at_binary_scale = a; + break; + case DW_AT_bit_offset: + attrs->at_bit_offset = a; + break; + case DW_AT_bit_size: + attrs->at_bit_size = a; + break; + case DW_AT_bit_stride: + attrs->at_bit_stride = a; + break; + case DW_AT_byte_size: + attrs->at_byte_size = a; + break; + case DW_AT_byte_stride: + attrs->at_byte_stride = a; + break; + case DW_AT_const_value: + attrs->at_const_value = a; + break; + case DW_AT_containing_type: + attrs->at_containing_type = a; + break; + case DW_AT_count: + attrs->at_count = a; + break; + case DW_AT_data_location: + attrs->at_data_location = a; + break; + case DW_AT_data_member_location: + attrs->at_data_member_location = a; + break; + case DW_AT_decimal_scale: + attrs->at_decimal_scale = a; + break; + case DW_AT_decimal_sign: + attrs->at_decimal_sign = a; + break; + case DW_AT_default_value: + attrs->at_default_value = a; + break; + case DW_AT_digit_count: + attrs->at_digit_count = a; + break; + case DW_AT_discr: + attrs->at_discr = a; + break; + case DW_AT_discr_list: + attrs->at_discr_list = a; + break; + case DW_AT_discr_value: + attrs->at_discr_value = a; + break; + case DW_AT_encoding: + attrs->at_encoding = a; + break; + case DW_AT_endianity: + attrs->at_endianity = a; + break; + case DW_AT_explicit: + attrs->at_explicit = a; + break; + case DW_AT_is_optional: + attrs->at_is_optional = a; + break; + case DW_AT_location: + attrs->at_location = a; + break; + case DW_AT_lower_bound: + attrs->at_lower_bound = a; + break; + case DW_AT_mutable: + attrs->at_mutable = a; + break; + case DW_AT_ordering: + attrs->at_ordering = a; + break; + case DW_AT_picture_string: + attrs->at_picture_string = a; + break; + case DW_AT_prototyped: + attrs->at_prototyped = a; + break; + case DW_AT_small: + attrs->at_small = a; + break; + case DW_AT_segment: + attrs->at_segment = a; + break; + case DW_AT_string_length: + attrs->at_string_length = a; + break; + case DW_AT_threads_scaled: + attrs->at_threads_scaled = a; + break; + case DW_AT_upper_bound: + attrs->at_upper_bound = a; + break; + case DW_AT_use_location: + attrs->at_use_location = a; + break; + case DW_AT_use_UTF8: + attrs->at_use_UTF8 = a; + break; + case DW_AT_variable_parameter: + attrs->at_variable_parameter = a; + break; + case DW_AT_virtuality: + attrs->at_virtuality = a; + break; + case DW_AT_visibility: + attrs->at_visibility = a; + break; + case DW_AT_vtable_elem_location: + attrs->at_vtable_elem_location = a; + break; + default: + break; + } + } +} + +/* Calculate the checksum of a DIE, using an ordered subset of attributes. */ + +static void +die_checksum_ordered (dw_die_ref die, struct md5_ctx *ctx, int *mark) +{ + dw_die_ref c; + dw_die_ref decl; + struct checksum_attributes attrs; + + CHECKSUM_ULEB128 ('D'); + CHECKSUM_ULEB128 (die->die_tag); + + memset (&attrs, 0, sizeof (attrs)); + + decl = get_AT_ref (die, DW_AT_specification); + if (decl != NULL) + collect_checksum_attributes (&attrs, decl); + collect_checksum_attributes (&attrs, die); + + CHECKSUM_ATTR (attrs.at_name); + CHECKSUM_ATTR (attrs.at_accessibility); + CHECKSUM_ATTR (attrs.at_address_class); + CHECKSUM_ATTR (attrs.at_allocated); + CHECKSUM_ATTR (attrs.at_artificial); + CHECKSUM_ATTR (attrs.at_associated); + CHECKSUM_ATTR (attrs.at_binary_scale); + CHECKSUM_ATTR (attrs.at_bit_offset); + CHECKSUM_ATTR (attrs.at_bit_size); + CHECKSUM_ATTR (attrs.at_bit_stride); + CHECKSUM_ATTR (attrs.at_byte_size); + CHECKSUM_ATTR (attrs.at_byte_stride); + CHECKSUM_ATTR (attrs.at_const_value); + CHECKSUM_ATTR (attrs.at_containing_type); + CHECKSUM_ATTR (attrs.at_count); + CHECKSUM_ATTR (attrs.at_data_location); + CHECKSUM_ATTR (attrs.at_data_member_location); + CHECKSUM_ATTR (attrs.at_decimal_scale); + CHECKSUM_ATTR (attrs.at_decimal_sign); + CHECKSUM_ATTR (attrs.at_default_value); + CHECKSUM_ATTR (attrs.at_digit_count); + CHECKSUM_ATTR (attrs.at_discr); + CHECKSUM_ATTR (attrs.at_discr_list); + CHECKSUM_ATTR (attrs.at_discr_value); + CHECKSUM_ATTR (attrs.at_encoding); + CHECKSUM_ATTR (attrs.at_endianity); + CHECKSUM_ATTR (attrs.at_explicit); + CHECKSUM_ATTR (attrs.at_is_optional); + CHECKSUM_ATTR (attrs.at_location); + CHECKSUM_ATTR (attrs.at_lower_bound); + CHECKSUM_ATTR (attrs.at_mutable); + CHECKSUM_ATTR (attrs.at_ordering); + CHECKSUM_ATTR (attrs.at_picture_string); + CHECKSUM_ATTR (attrs.at_prototyped); + CHECKSUM_ATTR (attrs.at_small); + CHECKSUM_ATTR (attrs.at_segment); + CHECKSUM_ATTR (attrs.at_string_length); + CHECKSUM_ATTR (attrs.at_threads_scaled); + CHECKSUM_ATTR (attrs.at_upper_bound); + CHECKSUM_ATTR (attrs.at_use_location); + CHECKSUM_ATTR (attrs.at_use_UTF8); + CHECKSUM_ATTR (attrs.at_variable_parameter); + CHECKSUM_ATTR (attrs.at_virtuality); + CHECKSUM_ATTR (attrs.at_visibility); + CHECKSUM_ATTR (attrs.at_vtable_elem_location); + CHECKSUM_ATTR (attrs.at_type); + CHECKSUM_ATTR (attrs.at_friend); + + /* Checksum the child DIEs, except for nested types and member functions. */ + c = die->die_child; + if (c) do { + dw_attr_ref name_attr; + + c = c->die_sib; + name_attr = get_AT (c, DW_AT_name); + if ((is_type_die (c) || c->die_tag == DW_TAG_subprogram) + && name_attr != NULL) + { + CHECKSUM_ULEB128 ('S'); + CHECKSUM_ULEB128 (c->die_tag); + CHECKSUM_STRING (AT_string (name_attr)); + } + else + { + /* Mark this DIE so it gets processed when unmarking. */ + if (c->die_mark == 0) + c->die_mark = -1; + die_checksum_ordered (c, ctx, mark); + } + } while (c != die->die_child); + + CHECKSUM_ULEB128 (0); +} + +#undef CHECKSUM +#undef CHECKSUM_STRING +#undef CHECKSUM_ATTR +#undef CHECKSUM_LEB128 +#undef CHECKSUM_ULEB128 + +/* Generate the type signature for DIE. This is computed by generating an + MD5 checksum over the DIE's tag, its relevant attributes, and its + children. Attributes that are references to other DIEs are processed + by recursion, using the MARK field to prevent infinite recursion. + If the DIE is nested inside a namespace or another type, we also + need to include that context in the signature. The lower 64 bits + of the resulting MD5 checksum comprise the signature. */ + +static void +generate_type_signature (dw_die_ref die, comdat_type_node *type_node) +{ + int mark; + const char *name; + unsigned char checksum[16]; + struct md5_ctx ctx; + dw_die_ref decl; + + name = get_AT_string (die, DW_AT_name); + decl = get_AT_ref (die, DW_AT_specification); + + /* First, compute a signature for just the type name (and its surrounding + context, if any. This is stored in the type unit DIE for link-time + ODR (one-definition rule) checking. */ + + if (is_cxx() && name != NULL) + { + md5_init_ctx (&ctx); + + /* Checksum the names of surrounding namespaces and structures. */ + if (decl != NULL && decl->die_parent != NULL) + checksum_die_context (decl->die_parent, &ctx); + + md5_process_bytes (&die->die_tag, sizeof (die->die_tag), &ctx); + md5_process_bytes (name, strlen (name) + 1, &ctx); + md5_finish_ctx (&ctx, checksum); + + add_AT_data8 (type_node->root_die, DW_AT_GNU_odr_signature, &checksum[8]); + } + + /* Next, compute the complete type signature. */ + + md5_init_ctx (&ctx); + mark = 1; + die->die_mark = mark; + + /* Checksum the names of surrounding namespaces and structures. */ + if (decl != NULL && decl->die_parent != NULL) + checksum_die_context (decl->die_parent, &ctx); + + /* Checksum the DIE and its children. */ + die_checksum_ordered (die, &ctx, &mark); + unmark_all_dies (die); + md5_finish_ctx (&ctx, checksum); + + /* Store the signature in the type node and link the type DIE and the + type node together. */ + memcpy (type_node->signature, &checksum[16 - DWARF_TYPE_SIGNATURE_SIZE], + DWARF_TYPE_SIGNATURE_SIZE); + die->die_id.die_type_node = type_node; + type_node->type_die = die; + + /* If the DIE is a specification, link its declaration to the type node + as well. */ + if (decl != NULL) + decl->die_id.die_type_node = type_node; +} + /* Do the location expressions look same? */ static inline int same_loc_p (dw_loc_descr_ref loc1, dw_loc_descr_ref loc2, int *mark) @@ -7941,6 +8725,9 @@ same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark) case dw_val_class_file: return v1->v.val_file == v2->v.val_file; + case dw_val_class_data8: + return !memcmp (v1->v.val_data8, v2->v.val_data8, 8); + default: return 1; } @@ -8067,7 +8854,7 @@ compute_section_prefix (dw_die_ref unit_die) p += 2; } - comdat_symbol_id = unit_die->die_symbol = xstrdup (name); + comdat_symbol_id = unit_die->die_id.die_symbol = xstrdup (name); comdat_symbol_number = 0; } @@ -8139,8 +8926,7 @@ static int is_symbol_die (dw_die_ref c) { return (is_type_die (c) - || (get_AT (c, DW_AT_declaration) - && !get_AT (c, DW_AT_specification)) + || is_declaration_die (c) || c->die_tag == DW_TAG_namespace || c->die_tag == DW_TAG_module); } @@ -8169,10 +8955,10 @@ assign_symbol_names (dw_die_ref die) sprintf (p, "%s.%s.%x", DIE_LABEL_PREFIX, comdat_symbol_id, comdat_symbol_number++); - die->die_symbol = xstrdup (p); + die->die_id.die_symbol = xstrdup (p); } else - die->die_symbol = gen_internal_sym ("LDIE"); + die->die_id.die_symbol = gen_internal_sym ("LDIE"); } FOR_EACH_CHILD (die, c, assign_symbol_names (c)); @@ -8192,7 +8978,7 @@ htab_cu_hash (const void *of) const struct cu_hash_table_entry *const entry = (const struct cu_hash_table_entry *) of; - return htab_hash_string (entry->cu->die_symbol); + return htab_hash_string (entry->cu->die_id.die_symbol); } static int @@ -8202,7 +8988,7 @@ htab_cu_eq (const void *of1, const void *of2) (const struct cu_hash_table_entry *) of1; const struct die_struct *const entry2 = (const struct die_struct *) of2; - return !strcmp (entry1->cu->die_symbol, entry2->die_symbol); + return !strcmp (entry1->cu->die_id.die_symbol, entry2->die_id.die_symbol); } static void @@ -8230,7 +9016,7 @@ check_duplicate_cu (dw_die_ref cu, htab_t htable, unsigned int *sym_num) dummy.max_comdat_num = 0; slot = (struct cu_hash_table_entry **) - htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_symbol), + htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_id.die_symbol), INSERT); entry = *slot; @@ -8262,7 +9048,7 @@ record_comdat_symbol_number (dw_die_ref cu, htab_t htable, unsigned int sym_num) struct cu_hash_table_entry **slot, *entry; slot = (struct cu_hash_table_entry **) - htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_symbol), + htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_id.die_symbol), NO_INSERT); entry = *slot; @@ -8335,6 +9121,545 @@ break_out_includes (dw_die_ref die) htab_delete (cu_hash_table); } +/* Return non-zero if this DIE is a declaration. */ + +static int +is_declaration_die (dw_die_ref die) +{ + dw_attr_ref a; + unsigned ix; + + for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++) + if (a->dw_attr == DW_AT_declaration) + return 1; + + return 0; +} + +/* Return non-zero if this is a type DIE that should be moved to a + COMDAT .debug_types section. */ + +static int +should_move_die_to_comdat (dw_die_ref die) +{ + switch (die->die_tag) + { + case DW_TAG_class_type: + case DW_TAG_structure_type: + case DW_TAG_enumeration_type: + case DW_TAG_union_type: + /* Don't move declarations or inlined instances. */ + if (is_declaration_die (die) || get_AT (die, DW_AT_abstract_origin)) + return 0; + return 1; + case DW_TAG_array_type: + case DW_TAG_interface_type: + case DW_TAG_pointer_type: + case DW_TAG_reference_type: + case DW_TAG_string_type: + case DW_TAG_subroutine_type: + case DW_TAG_ptr_to_member_type: + case DW_TAG_set_type: + case DW_TAG_subrange_type: + case DW_TAG_base_type: + case DW_TAG_const_type: + case DW_TAG_file_type: + case DW_TAG_packed_type: + case DW_TAG_volatile_type: + case DW_TAG_typedef: + default: + return 0; + } +} + +/* Make a clone of DIE. */ + +static dw_die_ref +clone_die (dw_die_ref die) +{ + dw_die_ref clone; + dw_attr_ref a; + unsigned ix; + + clone = GGC_CNEW (die_node); + clone->die_tag = die->die_tag; + + for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++) + add_dwarf_attr (clone, a); + + return clone; +} + +/* Make a clone of the tree rooted at DIE. */ + +static dw_die_ref +clone_tree (dw_die_ref die) +{ + dw_die_ref c; + dw_die_ref clone = clone_die (die); + + FOR_EACH_CHILD (die, c, add_child_die (clone, clone_tree(c))); + + return clone; +} + +/* Make a clone of DIE as a declaration. */ + +static dw_die_ref +clone_as_declaration (dw_die_ref die) +{ + dw_die_ref clone; + dw_die_ref decl; + dw_attr_ref a; + unsigned ix; + + /* If the DIE is already a declaration, just clone it. */ + if (is_declaration_die (die)) + return clone_die (die); + + /* If the DIE is a specification, just clone its declaration DIE. */ + decl = get_AT_ref (die, DW_AT_specification); + if (decl != NULL) + return clone_die (decl); + + clone = GGC_CNEW (die_node); + clone->die_tag = die->die_tag; + + for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++) + { + /* We don't want to copy over all attributes. + For example we don't want DW_AT_byte_size because otherwise we will no + longer have a declaration and GDB will treat it as a definition. */ + + switch (a->dw_attr) + { + case DW_AT_artificial: + case DW_AT_containing_type: + case DW_AT_external: + case DW_AT_name: + case DW_AT_type: + case DW_AT_virtuality: + case DW_AT_MIPS_linkage_name: + add_dwarf_attr (clone, a); + break; + case DW_AT_byte_size: + default: + break; + } + } + + if (die->die_id.die_type_node) + add_AT_die_ref (clone, DW_AT_signature, die); + + add_AT_flag (clone, DW_AT_declaration, 1); + return clone; +} + +/* Copy the declaration context to the new compile unit DIE. This includes + any surrounding namespace or type declarations. If the DIE has an + AT_specification attribute, it also includes attributes and children + attached to the specification. */ + +static void +copy_declaration_context (dw_die_ref unit, dw_die_ref die) +{ + dw_die_ref decl; + dw_die_ref new_decl; + + decl = get_AT_ref (die, DW_AT_specification); + if (decl == NULL) + decl = die; + else + { + unsigned ix; + dw_die_ref c; + dw_attr_ref a; + + /* Copy the type node pointer from the new DIE to the original + declaration DIE so we can forward references later. */ + decl->die_id.die_type_node = die->die_id.die_type_node; + + remove_AT (die, DW_AT_specification); + + for (ix = 0; VEC_iterate (dw_attr_node, decl->die_attr, ix, a); ix++) + { + if (a->dw_attr != DW_AT_name + && a->dw_attr != DW_AT_declaration + && a->dw_attr != DW_AT_external) + add_dwarf_attr (die, a); + } + + FOR_EACH_CHILD (decl, c, add_child_die (die, clone_tree(c))); + } + + if (decl->die_parent != NULL + && decl->die_parent->die_tag != DW_TAG_compile_unit + && decl->die_parent->die_tag != DW_TAG_type_unit) + { + new_decl = copy_ancestor_tree (unit, decl, NULL); + if (new_decl != NULL) + { + remove_AT (new_decl, DW_AT_signature); + add_AT_specification (die, new_decl); + } + } +} + +/* Generate the skeleton ancestor tree for the given NODE, then clone + the DIE and add the clone into the tree. */ + +static void +generate_skeleton_ancestor_tree (skeleton_chain_node *node) +{ + if (node->new_die != NULL) + return; + + node->new_die = clone_as_declaration (node->old_die); + + if (node->parent != NULL) + { + generate_skeleton_ancestor_tree (node->parent); + add_child_die (node->parent->new_die, node->new_die); + } +} + +/* Generate a skeleton tree of DIEs containing any declarations that are + found in the original tree. We traverse the tree looking for declaration + DIEs, and construct the skeleton from the bottom up whenever we find one. */ + +static void +generate_skeleton_bottom_up (skeleton_chain_node *parent) +{ + skeleton_chain_node node; + dw_die_ref c; + dw_die_ref first; + dw_die_ref prev = NULL; + dw_die_ref next = NULL; + + node.parent = parent; + + first = c = parent->old_die->die_child; + if (c) + next = c->die_sib; + if (c) do { + if (prev == NULL || prev->die_sib == c) + prev = c; + c = next; + next = (c == first ? NULL : c->die_sib); + node.old_die = c; + node.new_die = NULL; + if (is_declaration_die (c)) + { + /* Clone the existing DIE, move the original to the skeleton + tree (which is in the main CU), and put the clone, with + all the original's children, where the original came from. */ + dw_die_ref clone = clone_die (c); + move_all_children (c, clone); + + replace_child (c, clone, prev); + generate_skeleton_ancestor_tree (parent); + add_child_die (parent->new_die, c); + node.new_die = c; + c = clone; + } + generate_skeleton_bottom_up (&node); + } while (next != NULL); +} + +/* Wrapper function for generate_skeleton_bottom_up. */ + +static dw_die_ref +generate_skeleton (dw_die_ref die) +{ + skeleton_chain_node node; + + node.old_die = die; + node.new_die = NULL; + node.parent = NULL; + + /* If this type definition is nested inside another type, + always leave at least a declaration in its place. */ + if (die->die_parent != NULL && is_type_die (die->die_parent)) + node.new_die = clone_as_declaration (die); + + generate_skeleton_bottom_up (&node); + return node.new_die; +} + +/* Remove the DIE from its parent, possibly replacing it with a cloned + declaration. The original DIE will be moved to a new compile unit + so that existing references to it follow it to the new location. If + any of the original DIE's descendants is a declaration, we need to + replace the original DIE with a skeleton tree and move the + declarations back into the skeleton tree. */ + +static dw_die_ref +remove_child_or_replace_with_skeleton (dw_die_ref child, dw_die_ref prev) +{ + dw_die_ref skeleton; + + skeleton = generate_skeleton (child); + if (skeleton == NULL) + remove_child_with_prev (child, prev); + else + { + skeleton->die_id.die_type_node = child->die_id.die_type_node; + replace_child (child, skeleton, prev); + } + + return skeleton; +} + +/* Traverse the DIE and set up additional .debug_types sections for each + type worthy of being placed in a COMDAT section. */ + +static void +break_out_comdat_types (dw_die_ref die) +{ + dw_die_ref c; + dw_die_ref first; + dw_die_ref prev = NULL; + dw_die_ref next = NULL; + dw_die_ref unit = NULL; + + first = c = die->die_child; + if (c) + next = c->die_sib; + if (c) do { + if (prev == NULL || prev->die_sib == c) + prev = c; + c = next; + next = (c == first ? NULL : c->die_sib); + if (should_move_die_to_comdat (c)) + { + dw_die_ref replacement; + comdat_type_node_ref type_node; + + /* Create a new type unit DIE as the root for the new tree, and + add it to the list of comdat types. */ + unit = new_die (DW_TAG_type_unit, NULL, NULL); + add_AT_unsigned (unit, DW_AT_language, + get_AT_unsigned (comp_unit_die, DW_AT_language)); + type_node = GGC_CNEW (comdat_type_node); + type_node->root_die = unit; + type_node->next = comdat_type_list; + comdat_type_list = type_node; + + /* Generate the type signature. */ + generate_type_signature (c, type_node); + + /* Copy the declaration context, attributes, and children of the + declaration into the new compile unit DIE. */ + copy_declaration_context (unit, c); + + /* Remove this DIE from the main CU. */ + replacement = remove_child_or_replace_with_skeleton (c, prev); + + /* Break out nested types into their own type units. */ + break_out_comdat_types (c); + + /* Add the DIE to the new compunit. */ + add_child_die (unit, c); + + if (replacement != NULL) + c = replacement; + } + else if (c->die_tag == DW_TAG_namespace + || c->die_tag == DW_TAG_class_type + || c->die_tag == DW_TAG_structure_type + || c->die_tag == DW_TAG_union_type) + { + /* Look for nested types that can be broken out. */ + break_out_comdat_types (c); + } + } while (next != NULL); +} + +/* Structure to map a DIE in one CU to its copy in a comdat type unit. */ + +struct decl_table_entry +{ + dw_die_ref orig; + dw_die_ref copy; +}; + +/* Routines to manipulate hash table of copied declarations. */ + +static hashval_t +htab_decl_hash (const void *of) +{ + const struct decl_table_entry *const entry = + (const struct decl_table_entry *) of; + + return htab_hash_pointer (entry->orig); +} + +static int +htab_decl_eq (const void *of1, const void *of2) +{ + const struct decl_table_entry *const entry1 = + (const struct decl_table_entry *) of1; + const struct die_struct *const entry2 = (const struct die_struct *) of2; + + return entry1->orig == entry2; +} + +static void +htab_decl_del (void *what) +{ + struct decl_table_entry *entry = (struct decl_table_entry *) what; + + free (entry); +} + +/* Copy DIE and its ancestors, up to, but not including, the compile unit + or type unit entry, to a new tree. Adds the new tree to UNIT and returns + a pointer to the copy of DIE. If DECL_TABLE is provided, it is used + to check if the ancestor has already been copied into UNIT. */ + +static dw_die_ref +copy_ancestor_tree (dw_die_ref unit, dw_die_ref die, htab_t decl_table) +{ + dw_die_ref parent = die->die_parent; + dw_die_ref new_parent = unit; + dw_die_ref copy; + void **slot = NULL; + struct decl_table_entry *entry = NULL; + + if (decl_table) + { + /* Check if the entry has already been copied to UNIT. */ + slot = htab_find_slot_with_hash (decl_table, die, + htab_hash_pointer (die), INSERT); + if (*slot != HTAB_EMPTY_ENTRY) + { + entry = (struct decl_table_entry *) *slot; + return entry->copy; + } + + /* Record in DECL_TABLE that DIE has been copied to UNIT. */ + entry = XCNEW (struct decl_table_entry); + entry->orig = die; + entry->copy = NULL; + *slot = entry; + } + + if (parent != NULL) + { + dw_die_ref spec = get_AT_ref (parent, DW_AT_specification); + if (spec != NULL) + parent = spec; + if (parent->die_tag != DW_TAG_compile_unit + && parent->die_tag != DW_TAG_type_unit) + new_parent = copy_ancestor_tree (unit, parent, decl_table); + } + + copy = clone_as_declaration (die); + add_child_die (new_parent, copy); + + if (decl_table != NULL) + { + /* Make sure the copy is marked as part of the type unit. */ + copy->die_mark = 1; + /* Record the pointer to the copy. */ + entry->copy = copy; + } + + return copy; +} + +/* Walk the DIE and its children, looking for references to incomplete + or trivial types that are unmarked (i.e., that are not in the current + type_unit). */ + +static void +copy_decls_walk (dw_die_ref unit, dw_die_ref die, htab_t decl_table) +{ + dw_die_ref c; + dw_attr_ref a; + unsigned ix; + + for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++) + { + if (AT_class (a) == dw_val_class_die_ref) + { + dw_die_ref targ = AT_ref (a); + comdat_type_node_ref type_node = targ->die_id.die_type_node; + void **slot; + struct decl_table_entry *entry; + + if (targ->die_mark != 0 || type_node != NULL) + continue; + + slot = htab_find_slot_with_hash (decl_table, targ, + htab_hash_pointer (targ), INSERT); + + if (*slot != HTAB_EMPTY_ENTRY) + { + /* TARG has already been copied, so we just need to + modify the reference to point to the copy. */ + entry = (struct decl_table_entry *) *slot; + a->dw_attr_val.v.val_die_ref.die = entry->copy; + } + else + { + dw_die_ref parent = unit; + dw_die_ref copy = clone_tree (targ); + + /* Make sure the cloned tree is marked as part of the + type unit. */ + mark_dies (copy); + + /* Record in DECL_TABLE that TARG has been copied. + Need to do this now, before the recursive call, + because DECL_TABLE may be expanded and SLOT + would no longer be a valid pointer. */ + entry = XCNEW (struct decl_table_entry); + entry->orig = targ; + entry->copy = copy; + *slot = entry; + + /* If TARG has surrounding context, copy its ancestor tree + into the new type unit. */ + if (targ->die_parent != NULL + && targ->die_parent->die_tag != DW_TAG_compile_unit + && targ->die_parent->die_tag != DW_TAG_type_unit) + parent = copy_ancestor_tree (unit, targ->die_parent, + decl_table); + + add_child_die (parent, copy); + a->dw_attr_val.v.val_die_ref.die = copy; + + /* Make sure the newly-copied DIE is walked. If it was + installed in a previously-added context, it won't + get visited otherwise. */ + if (parent != unit) + copy_decls_walk (unit, parent, decl_table); + } + } + } + + FOR_EACH_CHILD (die, c, copy_decls_walk (unit, c, decl_table)); +} + +/* Copy declarations for "unworthy" types into the new comdat section. + Incomplete types, modified types, and certain other types aren't broken + out into comdat sections of their own, so they don't have a signature, + and we need to copy the declaration into the same section so that we + don't have an external reference. */ + +static void +copy_decls_for_unworthy_types (dw_die_ref unit) +{ + htab_t decl_table; + + mark_dies (unit); + decl_table = htab_create (10, htab_decl_hash, htab_decl_eq, htab_decl_del); + copy_decls_walk (unit, unit, decl_table); + htab_delete (decl_table); + unmark_dies (unit); +} + /* Traverse the DIE and add a sibling attribute if it may have the effect of speeding up access to siblings. To save some space, avoid generating sibling attributes for DIE's without children. */ @@ -8389,7 +9714,7 @@ build_abbrev_table (dw_die_ref die) if (AT_class (a) == dw_val_class_die_ref && AT_ref (a)->die_mark == 0) { - gcc_assert (AT_ref (a)->die_symbol); + gcc_assert (dwarf_version >= 4 || AT_ref (a)->die_id.die_symbol); set_AT_ref_external (a, 1); } @@ -8519,10 +9844,19 @@ size_of_die (dw_die_ref die) size += 1; break; case dw_val_class_die_ref: - /* In DWARF2, DW_FORM_ref_addr is sized by target address length, - whereas in DWARF3 it's always sized as an offset. */ - if (AT_ref_external (a) && dwarf_version == 2) - size += DWARF2_ADDR_SIZE; + if (AT_ref_external (a)) + { + /* In DWARF4, we use DW_FORM_sig8; for earlier versions + we use DW_FORM_ref_addr. In DWARF2, DW_FORM_ref_addr + is sized by target address length, whereas in DWARF3 + it's always sized as an offset. */ + if (dwarf_version >= 4) + size += DWARF_TYPE_SIGNATURE_SIZE; + else if (dwarf_version == 2) + size += DWARF2_ADDR_SIZE; + else + size += DWARF_OFFSET_SIZE; + } else size += DWARF_OFFSET_SIZE; break; @@ -8545,6 +9879,9 @@ size_of_die (dw_die_ref die) case dw_val_class_file: size += constant_size (maybe_emit_file (a->dw_attr_val.v.val_file)); break; + case dw_val_class_data8: + size += 8; + break; default: gcc_unreachable (); } @@ -8596,7 +9933,8 @@ unmark_dies (dw_die_ref die) { dw_die_ref c; - gcc_assert (die->die_mark); + if (dwarf_version < 4) + gcc_assert (die->die_mark); die->die_mark = 0; FOR_EACH_CHILD (die, c, unmark_dies (c)); @@ -8764,7 +10102,7 @@ value_format (dw_attr_ref a) return DW_FORM_flag; case dw_val_class_die_ref: if (AT_ref_external (a)) - return DW_FORM_ref_addr; + return dwarf_version >= 4 ? DW_FORM_sig8 : DW_FORM_ref_addr; else return DW_FORM_ref; case dw_val_class_fde_ref: @@ -8789,6 +10127,9 @@ value_format (dw_attr_ref a) gcc_unreachable (); } + case dw_val_class_data8: + return DW_FORM_data8; + default: gcc_unreachable (); } @@ -8848,7 +10189,7 @@ output_abbrev_section (void) static inline void output_die_symbol (dw_die_ref die) { - char *sym = die->die_symbol; + char *sym = die->die_id.die_symbol; if (sym == 0) return; @@ -8950,6 +10291,17 @@ output_loc_list (dw_loc_list_ref list_head) list_head->ll_symbol); } +/* Output a type signature. */ + +static inline void +output_signature (const char *sig, const char *name) +{ + int i; + + for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++) + dw2_asm_output_data (1, sig[i], "%s", name); +} + /* Output the DIE and its attributes. Called recursively to generate the definitions of each child DIE. */ @@ -8963,7 +10315,7 @@ output_die (dw_die_ref die) /* If someone in another CU might refer to us, set up a symbol for them to point to. */ - if (die->die_symbol) + if (dwarf_version < 4 && die->die_id.die_symbol) output_die_symbol (die); dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (0x%lx) %s)", @@ -9085,18 +10437,30 @@ output_die (dw_die_ref die) case dw_val_class_die_ref: if (AT_ref_external (a)) { - char *sym = AT_ref (a)->die_symbol; - int size; + if (dwarf_version >= 4) + { + comdat_type_node_ref type_node = + AT_ref (a)->die_id.die_type_node; - gcc_assert (sym); - - /* In DWARF2, DW_FORM_ref_addr is sized by target address - length, whereas in DWARF3 it's always sized as an offset. */ - if (dwarf_version == 2) - size = DWARF2_ADDR_SIZE; + gcc_assert (type_node); + output_signature (type_node->signature, name); + } else - size = DWARF_OFFSET_SIZE; - dw2_asm_output_offset (size, sym, debug_info_section, "%s", name); + { + char *sym = AT_ref (a)->die_id.die_symbol; + int size; + + gcc_assert (sym); + /* In DWARF2, DW_FORM_ref_addr is sized by target address + length, whereas in DWARF3 it's always sized as an + offset. */ + if (dwarf_version == 2) + size = DWARF2_ADDR_SIZE; + else + size = DWARF_OFFSET_SIZE; + dw2_asm_output_offset (size, sym, debug_info_section, "%s", + name); + } } else { @@ -9150,6 +10514,16 @@ output_die (dw_die_ref die) break; } + case dw_val_class_data8: + { + int i; + + for (i = 0; i < 8; i++) + dw2_asm_output_data (1, a->dw_attr_val.v.val_data8[i], + "%s", name); + break; + } + default: gcc_unreachable (); } @@ -9169,13 +10543,20 @@ output_die (dw_die_ref die) static void output_compilation_unit_header (void) { + int ver = dwarf_version; + + /* Don't mark the output as DWARF-4 until we make full use of the + version 4 extensions, and gdb supports them. For now, -gdwarf-4 + selects only a few extensions from the DWARF-4 spec. */ + if (ver > 3) + ver = 3; if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) dw2_asm_output_data (4, 0xffffffff, "Initial length escape value indicating 64-bit DWARF extension"); dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset - DWARF_INITIAL_LENGTH_SIZE, "Length of Compilation Unit Info"); - dw2_asm_output_data (2, dwarf_version, "DWARF version number"); + dw2_asm_output_data (2, ver, "DWARF version number"); dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label, debug_abbrev_section, "Offset Into Abbrev. Section"); @@ -9207,14 +10588,14 @@ output_comp_unit (dw_die_ref die, int output_if_empty) next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE; calc_die_sizes (die); - oldsym = die->die_symbol; + oldsym = die->die_id.die_symbol; if (oldsym) { tmp = XALLOCAVEC (char, strlen (oldsym) + 24); sprintf (tmp, ".gnu.linkonce.wi.%s", oldsym); secname = tmp; - die->die_symbol = NULL; + die->die_id.die_symbol = NULL; switch_to_section (get_section (secname, SECTION_DEBUG, NULL)); } else @@ -9229,10 +10610,60 @@ output_comp_unit (dw_die_ref die, int output_if_empty) if (oldsym) { unmark_dies (die); - die->die_symbol = oldsym; + die->die_id.die_symbol = oldsym; } } +/* Output a comdat type unit DIE and its children. */ + +static void +output_comdat_type_unit (comdat_type_node *node) +{ + const char *secname; + char *tmp; + int i; +#if defined (OBJECT_FORMAT_ELF) + tree comdat_key; +#endif + + /* First mark all the DIEs in this CU so we know which get local refs. */ + mark_dies (node->root_die); + + build_abbrev_table (node->root_die); + + /* Initialize the beginning DIE offset - and calculate sizes/offsets. */ + next_die_offset = DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE; + calc_die_sizes (node->root_die); + +#if defined (OBJECT_FORMAT_ELF) + secname = ".debug_types"; + tmp = XALLOCAVEC (char, 4 + DWARF_TYPE_SIGNATURE_SIZE * 2); + sprintf (tmp, "wt."); + for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++) + sprintf (tmp + 3 + i * 2, "%02x", node->signature[i] & 0xff); + comdat_key = get_identifier (tmp); + targetm.asm_out.named_section (secname, + SECTION_DEBUG | SECTION_LINKONCE, + comdat_key); +#else + tmp = XALLOCAVEC (char, 18 + DWARF_TYPE_SIGNATURE_SIZE * 2); + sprintf (tmp, ".gnu.linkonce.wt."); + for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++) + sprintf (tmp + 17 + i * 2, "%02x", node->signature[i] & 0xff); + secname = tmp; + switch_to_section (get_section (secname, SECTION_DEBUG, NULL)); +#endif + + /* Output debugging information. */ + output_compilation_unit_header (); + output_signature (node->signature, "Type Signature"); + dw2_asm_output_data (DWARF_OFFSET_SIZE, node->type_die->die_offset, + "Offset to Type DIE"); + output_die (node->root_die); + + unmark_dies (node->root_die); +} + /* Return the DWARF2/3 pubname associated with a decl. */ static const char * @@ -9950,6 +11381,13 @@ output_line_info (void) long line_delta; unsigned long current_file; unsigned long function; + int ver = dwarf_version; + + /* Don't mark the output as DWARF-4 until we make full use of the + version 4 extensions, and gdb supports them. For now, -gdwarf-4 + selects only a few extensions from the DWARF-4 spec. */ + if (ver > 3) + ver = 3; ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0); ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0); @@ -9963,7 +11401,7 @@ output_line_info (void) "Length of Source Line Info"); ASM_OUTPUT_LABEL (asm_out_file, l1); - dw2_asm_output_data (2, dwarf_version, "DWARF Version"); + dw2_asm_output_data (2, ver, "DWARF Version"); dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length"); ASM_OUTPUT_LABEL (asm_out_file, p1); @@ -18457,7 +19895,7 @@ dwarf2out_source_line (unsigned int line, const char *filename, static void dwarf2out_start_source_file (unsigned int lineno, const char *filename) { - if (flag_eliminate_dwarf2_dups) + if (flag_eliminate_dwarf2_dups && dwarf_version < 4) { /* Record the beginning of the file for break_out_includes. */ dw_die_ref bincl_die; @@ -18484,7 +19922,7 @@ dwarf2out_start_source_file (unsigned int lineno, const char *filename) static void dwarf2out_end_source_file (unsigned int lineno ATTRIBUTE_UNUSED) { - if (flag_eliminate_dwarf2_dups) + if (flag_eliminate_dwarf2_dups && dwarf_version < 4) /* Record the end of the file for break_out_includes. */ new_die (DW_TAG_GNU_EINCL, comp_unit_die, NULL); @@ -18708,8 +20146,12 @@ prune_unused_types_walk_attribs (dw_die_ref die) if (a->dw_attr_val.val_class == dw_val_class_die_ref) { /* A reference to another DIE. - Make sure that it will get emitted. */ - prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1); + Make sure that it will get emitted. + If it was broken out into a comdat group, don't follow it. */ + if (dwarf_version < 4 + || a->dw_attr == DW_AT_specification + || a->dw_attr_val.v.val_die_ref.die->die_id.die_type_node == NULL) + prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1); } /* Set the string's refcount to 0 so that prune_unused_types_mark accounts properly for it. */ @@ -18753,8 +20195,12 @@ prune_unused_types_mark (dw_die_ref die, int dokids) die->die_mark = 2; /* If this is an array type, we need to make sure our - kids get marked, even if they're types. */ - if (die->die_tag == DW_TAG_array_type) + kids get marked, even if they're types. If we're + breaking out types into comdat sections, do this + for all type definitions. */ + if (die->die_tag == DW_TAG_array_type + || (dwarf_version >= 4 + && is_type_die (die) && ! is_declaration_die (die))) FOR_EACH_CHILD (die, c, prune_unused_types_mark (c, 1)); else FOR_EACH_CHILD (die, c, prune_unused_types_walk (c)); @@ -18958,6 +20404,7 @@ prune_unused_types (void) { unsigned int i; limbo_die_node *node; + comdat_type_node *ctnode; pubname_ref pub; #if ENABLE_ASSERT_CHECKING @@ -18965,6 +20412,8 @@ prune_unused_types (void) verify_marks_clear (comp_unit_die); for (node = limbo_die_list; node; node = node->next) verify_marks_clear (node->die); + for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next) + verify_marks_clear (ctnode->root_die); #endif /* ENABLE_ASSERT_CHECKING */ /* Mark types that are used in global variables. */ @@ -18974,6 +20423,11 @@ prune_unused_types (void) prune_unused_types_walk (comp_unit_die); for (node = limbo_die_list; node; node = node->next) prune_unused_types_walk (node->die); + for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next) + { + prune_unused_types_walk (ctnode->root_die); + prune_unused_types_mark (ctnode->type_die, 1); + } /* Also set the mark on nodes referenced from the pubname_table or arange_table. */ @@ -18990,11 +20444,15 @@ prune_unused_types (void) prune_unused_types_prune (comp_unit_die); for (node = limbo_die_list; node; node = node->next) prune_unused_types_prune (node->die); + for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next) + prune_unused_types_prune (ctnode->root_die); /* Leave the marks clear. */ prune_unmark_dies (comp_unit_die); for (node = limbo_die_list; node; node = node->next) prune_unmark_dies (node->die); + for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next) + prune_unmark_dies (ctnode->root_die); } /* Set the parameter to true if there are any relative pathnames in @@ -19012,6 +20470,28 @@ file_table_relative_p (void ** slot, void *param) return 1; } +/* Routines to manipulate hash table of comdat type units. */ + +static hashval_t +htab_ct_hash (const void *of) +{ + hashval_t h; + const comdat_type_node *const type_node = (const comdat_type_node *) of; + + memcpy (&h, type_node->signature, sizeof (h)); + return h; +} + +static int +htab_ct_eq (const void *of1, const void *of2) +{ + const comdat_type_node *const type_node_1 = (const comdat_type_node *) of1; + const comdat_type_node *const type_node_2 = (const comdat_type_node *) of2; + + return (! memcmp (type_node_1->signature, type_node_2->signature, + DWARF_TYPE_SIGNATURE_SIZE)); +} + /* Move a DW_AT_MIPS_linkage_name attribute just added to dw_die_ref to the location it would have been added, should we know its DECL_ASSEMBLER_NAME when we added other attributes. This will @@ -19147,6 +20627,8 @@ static void dwarf2out_finish (const char *filename) { limbo_die_node *node, *next_node; + comdat_type_node *ctnode; + htab_t comdat_type_table; dw_die_ref die = 0; unsigned int i; @@ -19254,14 +20736,39 @@ dwarf2out_finish (const char *filename) /* Generate separate CUs for each of the include files we've seen. They will go into limbo_die_list. */ - if (flag_eliminate_dwarf2_dups) + if (flag_eliminate_dwarf2_dups && dwarf_version < 4) break_out_includes (comp_unit_die); + /* Generate separate COMDAT sections for type DIEs. */ + if (dwarf_version >= 4) + { + break_out_comdat_types (comp_unit_die); + + /* Each new type_unit DIE was added to the limbo die list when created. + Since these have all been added to comdat_type_list, clear the + limbo die list. */ + limbo_die_list = NULL; + + /* For each new comdat type unit, copy declarations for incomplete + types to make the new unit self-contained (i.e., no direct + references to the main compile unit). */ + for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next) + copy_decls_for_unworthy_types (ctnode->root_die); + copy_decls_for_unworthy_types (comp_unit_die); + + /* In the process of copying declarations from one unit to another, + we may have left some declarations behind that are no longer + referenced. Prune them. */ + prune_unused_types (); + } + /* Traverse the DIE's and add add sibling attributes to those DIE's that have children. */ add_sibling_attributes (comp_unit_die); for (node = limbo_die_list; node; node = node->next) add_sibling_attributes (node->die); + for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next) + add_sibling_attributes (ctnode->root_die); /* Output a terminator label for the .text section. */ switch_to_section (text_section); @@ -19344,6 +20851,27 @@ dwarf2out_finish (const char *filename) for (node = limbo_die_list; node; node = node->next) output_comp_unit (node->die, 0); + comdat_type_table = htab_create (100, htab_ct_hash, htab_ct_eq, NULL); + for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next) + { + void **slot = htab_find_slot (comdat_type_table, ctnode, INSERT); + + /* Don't output duplicate types. */ + if (*slot != HTAB_EMPTY_ENTRY) + continue; + + /* Add a pointer to the line table for the main compilation unit + so that the debugger can make sense of DW_AT_decl_file + attributes. */ + if (debug_info_level >= DINFO_LEVEL_NORMAL) + add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list, + debug_line_section_label); + + output_comdat_type_unit (ctnode); + *slot = ctnode; + } + htab_delete (comdat_type_table); + /* Output the main compilation unit if non-empty or if .debug_macinfo has been emitted. */ output_comp_unit (comp_unit_die, debug_info_level >= DINFO_LEVEL_VERBOSE); diff --git a/gcc/varasm.c b/gcc/varasm.c index 91ec68a..46ec00d 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -5997,8 +5997,13 @@ default_elf_asm_named_section (const char *name, unsigned int flags, if (flags & SECTION_ENTSIZE) fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE); if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE)) - fprintf (asm_out_file, ",%s,comdat", - IDENTIFIER_POINTER (DECL_COMDAT_GROUP (decl))); + { + if (TREE_CODE (decl) == IDENTIFIER_NODE) + fprintf (asm_out_file, ",%s,comdat", IDENTIFIER_POINTER (decl)); + else + fprintf (asm_out_file, ",%s,comdat", + IDENTIFIER_POINTER (DECL_COMDAT_GROUP (decl))); + } } putc ('\n', asm_out_file); |