From 10a11b75613b5fc2d7fb49cadea8825ab283d745 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 25 Nov 1999 02:36:40 +0000 Subject: [PATCH] dwarf2out.c (free_AT, free_die): New fns. * dwarf2out.c (free_AT, free_die): New fns. (remove_children): Call them. (output_line_info): Disable removal of duplicate notes. Generate minimal debug info for types with TYPE_DECL_SUPPRESS_INFO set. * dwarf2out.c (gen_struct_or_union_type_die): TYPE_DECL_SUPPRESS_INFO means pretend the type isn't defined. Don't defer emitting types. (gen_type_die_for_member): New fn. (gen_decl_die): Call it. (splice_child_die): New fn. (gen_member_die): Call it rather than generate duplicate dies. Defer emitting information for the abstract instance of an inline until we either inline it or emit an out-of-line copy. * dwarf2out.c (decl_ultimate_origin): Ignore DECL_ABSTRACT_ORIGIN from output_inline_function if DECL_ABSTRACT is also set. (block_ultimate_origin): Likewise. (gen_abstract_function): New fn. (gen_decl_die, gen_inlined_subroutine_die): Call it. (gen_subprogram_die): An abstract instance is not a declaration just because it doesn't match current_function_decl. Don't abort because DECL_DEFER_OUTPUT isn't set. Do abort if a declaration has an abstract origin. * toplev.c (rest_of_compilation): Don't emit dwarf2 info for the abstract instance here. From-SVN: r30659 --- gcc/ChangeLog | 29 +++++++ gcc/dwarf2out.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++---------- gcc/toplev.c | 11 --- 3 files changed, 224 insertions(+), 50 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 93f50bd..c560118d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,32 @@ +1999-11-24 Jason Merrill + + * dwarf2out.c (free_AT, free_die): New fns. + (remove_children): Call them. + (output_line_info): Disable removal of duplicate notes. + + Generate minimal debug info for types with TYPE_DECL_SUPPRESS_INFO set. + * dwarf2out.c (gen_struct_or_union_type_die): TYPE_DECL_SUPPRESS_INFO + means pretend the type isn't defined. + Don't defer emitting types. + (gen_type_die_for_member): New fn. + (gen_decl_die): Call it. + (splice_child_die): New fn. + (gen_member_die): Call it rather than generate duplicate dies. + + Defer emitting information for the abstract instance of an inline + until we either inline it or emit an out-of-line copy. + * dwarf2out.c (decl_ultimate_origin): Ignore DECL_ABSTRACT_ORIGIN + from output_inline_function if DECL_ABSTRACT is also set. + (block_ultimate_origin): Likewise. + (gen_abstract_function): New fn. + (gen_decl_die, gen_inlined_subroutine_die): Call it. + (gen_subprogram_die): An abstract instance is not a declaration + just because it doesn't match current_function_decl. Don't abort + because DECL_DEFER_OUTPUT isn't set. Do abort if a declaration + has an abstract origin. + * toplev.c (rest_of_compilation): Don't emit dwarf2 info for the + abstract instance here. + Wed Nov 24 18:39:18 1999 Andrew Haley * config/sh/sh.h (SECONDARY_OUTPUT_RELOAD_CLASS): Add the case diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index c2926c3..6657fd5 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -2543,6 +2543,8 @@ static void gen_decl_die PROTO((tree, dw_die_ref)); static unsigned lookup_filename PROTO((const char *)); static void add_incomplete_type PROTO((tree)); static void retry_incomplete_types PROTO((void)); +static void gen_type_die_for_member PROTO((tree, tree, dw_die_ref)); +static void gen_abstract_function PROTO((tree)); /* Section names used to hold DWARF debugging information. */ #ifndef DEBUG_INFO_SECTION @@ -3542,6 +3544,12 @@ static tree decl_ultimate_origin (decl) register tree decl; { + /* output_inline_function sets DECL_ABSTRACT_ORIGIN for all the + nodes in the function to point to themselves; ignore that if + we're trying to output the abstract instance of this function. */ + if (DECL_ABSTRACT (decl) && DECL_ABSTRACT_ORIGIN (decl) == decl) + return NULL_TREE; + #ifdef ENABLE_CHECKING if (DECL_FROM_INLINE (DECL_ORIGIN (decl))) /* Since the DECL_ABSTRACT_ORIGIN for a DECL is supposed to be the @@ -3564,6 +3572,12 @@ block_ultimate_origin (block) { register tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block); + /* output_inline_function sets BLOCK_ABSTRACT_ORIGIN for all the + nodes in the function to point to themselves; ignore that if + we're trying to output the abstract instance of this function. */ + if (BLOCK_ABSTRACT (block) && immediate_origin == block) + return NULL_TREE; + if (immediate_origin == NULL_TREE) return NULL_TREE; else @@ -4035,9 +4049,31 @@ is_fortran () return (lang == DW_LANG_Fortran77 || lang == DW_LANG_Fortran90); } -/* Remove the specified attribute if present. */ +/* Free up the memory used by A. */ static inline void +free_AT (a) + dw_attr_ref a; +{ + switch (AT_class (a)) + { + case dw_val_class_addr: + case dw_val_class_str: + case dw_val_class_lbl_id: + case dw_val_class_lbl_offset: + free (a->dw_attr_val.v.val_str); + break; + + default: + break; + } + + free (a); +} + +/* Remove the specified attribute if present. */ + +static void remove_AT (die, attr_kind) register dw_die_ref die; register enum dwarf_attribute attr_kind; @@ -4056,28 +4092,23 @@ remove_AT (die, attr_kind) } if (removed != 0) - { - switch (AT_class (removed)) - { - case dw_val_class_addr: - case dw_val_class_str: - case dw_val_class_lbl_id: - case dw_val_class_lbl_offset: - free (removed->dw_attr_val.v.val_str); - break; + free_AT (removed); + } +} - default: - break; - } +/* Free up the memory used by DIE. */ - free (removed); - } - } +static inline void +free_die (die) + dw_die_ref die; +{ + remove_children (die); + free (die); } /* Discard the children of this DIE. */ -static inline void +static void remove_children (die) register dw_die_ref die; { @@ -4097,10 +4128,10 @@ remove_children (die) register dw_attr_ref tmp_a = a; a = a->dw_attr_next; - free (tmp_a); + free_AT (tmp_a); } - free (tmp_die); + free_die (tmp_die); } } @@ -4122,6 +4153,34 @@ add_child_die (die, child_die) } } +/* Move CHILD, which must be a child of PARENT, to the front of + PARENT's list of children. */ + +static void +splice_child_die (parent, child) + dw_die_ref parent, child; +{ + dw_die_ref *p; + + /* We want the declaration DIE from inside the class, not the + specification DIE at toplevel. */ + if (child->die_parent != parent) + child = get_AT_ref (child, DW_AT_specification); + + if (parent == NULL || child == NULL || child->die_parent != parent) + abort (); + + for (p = &(parent->die_child); *p; p = &((*p)->die_sib)) + if (*p == child) + { + *p = child->die_sib; + break; + } + + child->die_sib = parent->die_child; + parent->die_child = child; +} + /* Return a pointer to a newly created DIE node. */ static inline dw_die_ref @@ -4165,7 +4224,7 @@ lookup_type_die (type) /* Equate a DIE to a given type specifier. */ -static void +static inline void equate_type_number_to_die (type, type_die) register tree type; register dw_die_ref type_die; @@ -5666,12 +5725,18 @@ output_line_info () { register dw_line_info_ref line_info = &line_info_table[lt_index]; +#if 0 + /* Disable this optimization for now; GDB wants to see two line notes + at the beginning of a function so it can find the end of the + prologue. */ + /* Don't emit anything for redundant notes. Just updating the address doesn't accomplish anything, because we already assume that anything after the last address is this line. */ if (line_info->dw_line_num == current_line && line_info->dw_file_num == current_file) continue; +#endif /* Emit debug info for the address of the current line, choosing the encoding that uses the least amount of space. */ @@ -5824,11 +5889,13 @@ output_line_info () register dw_separate_line_info_ref line_info = &separate_line_info_table[lt_index]; +#if 0 /* Don't emit anything for redundant notes. */ if (line_info->dw_line_num == current_line && line_info->dw_file_num == current_file && line_info->function == function) goto cont; +#endif /* Emit debug info for the address of the current line. If this is a new function, or the first line of a function, then we need @@ -5944,7 +6011,9 @@ output_line_info () fputc ('\n', asm_out_file); } +#if 0 cont: +#endif ++lt_index; /* If we're done with a function, end its sequence. */ @@ -8192,6 +8261,55 @@ gen_formal_types_die (function_or_method_type, context_die) } } +/* We want to generate the DIE for TYPE so that we can generate the + die for MEMBER, which has been defined; we will need to refer back + to the member declaration nested within TYPE. If we're trying to + generate minimal debug info for TYPE, processing TYPE won't do the + trick; we need to attach the member declaration by hand. */ + +static void +gen_type_die_for_member (type, member, context_die) + tree type, member; + dw_die_ref context_die; +{ + gen_type_die (type, context_die); + + /* If we're trying to avoid duplicate debug info, we may not have + emitted the member decl for this function. Emit it now. */ + if (TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type)) + && ! lookup_decl_die (member)) + { + if (decl_ultimate_origin (member)) + abort (); + + push_decl_scope (type); + if (TREE_CODE (member) == FUNCTION_DECL) + gen_subprogram_die (member, lookup_type_die (type)); + else + gen_variable_die (member, lookup_type_die (type)); + pop_decl_scope (); + } +} + +/* Generate the DWARF2 info for the "abstract" instance + of a function which we may later generate inlined and/or + out-of-line instances of. */ + +static void +gen_abstract_function (decl) + tree decl; +{ + register dw_die_ref old_die = lookup_decl_die (decl); + + if (old_die && get_AT_unsigned (old_die, DW_AT_inline)) + /* We've already generated the abstract instance. */ + return; + + set_decl_abstract_flags (decl, 1); + dwarf2out_decl (decl); + set_decl_abstract_flags (decl, 0); +} + /* Generate a DIE to represent a declared function (either file-scope or block-local). */ @@ -8208,13 +8326,23 @@ gen_subprogram_die (decl, context_die) register tree outer_scope; register dw_die_ref old_die = lookup_decl_die (decl); register int declaration - = (current_function_decl != decl + = ((current_function_decl != decl && ! DECL_ABSTRACT (decl)) || (context_die && (context_die->die_tag == DW_TAG_structure_type || context_die->die_tag == DW_TAG_union_type))); + /* Note that it is possible to have both DECL_ABSTRACT and `declaration' + be true, if we started to generate the abstract instance of an inline, + decided to output its containing class, and proceeded to emit the + declaration of the inline from the member list for the class. In that + case, `declaration' takes priority; we'll get back to the abstract + instance when we're done with the class. */ + if (origin != NULL) { + if (declaration) + abort (); + subr_die = new_die (DW_TAG_subprogram, context_die); add_abstract_origin_attribute (subr_die, origin); } @@ -8324,22 +8452,20 @@ gen_subprogram_die (decl, context_die) } else if (DECL_ABSTRACT (decl)) { - /* ??? Checking DECL_DEFER_OUTPUT is correct for static inline functions, - but not for extern inline functions. We can't get this completely - correct because information about whether the function was declared - inline is not saved anywhere. */ - if (DECL_DEFER_OUTPUT (decl)) + if (DECL_INLINE (decl) && !flag_no_inline) { - if (DECL_INLINE (decl) && !flag_no_inline) + /* ??? Checking DECL_DEFER_OUTPUT is correct for static + inline functions, but not for extern inline functions. + We can't get this completely correct because information + about whether the function was declared inline is not + saved anywhere. */ + if (DECL_DEFER_OUTPUT (decl)) add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined); else - add_AT_unsigned (subr_die, DW_AT_inline, - DW_INL_declared_not_inlined); + add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined); } - else if (DECL_INLINE (decl) && !flag_no_inline) - add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined); else - abort (); + add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_not_inlined); equate_decl_number_to_die (decl, subr_die); } @@ -8637,6 +8763,9 @@ gen_inlined_subroutine_die (stmt, context_die, depth) register tree decl = block_ultimate_origin (stmt); char label[MAX_ARTIFICIAL_LABEL_BYTES]; + /* Emit info for the abstract instance first, if we haven't yet. */ + gen_abstract_function (decl); + add_abstract_origin_attribute (subr_die, decl); ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL, next_block_number); @@ -8833,6 +8962,7 @@ gen_member_die (type, context_die) register dw_die_ref context_die; { register tree member; + dw_die_ref child; /* If this is not an incomplete type, output descriptions of each of its members. Note that as we output the DIEs necessary to represent the @@ -8860,14 +8990,33 @@ gen_member_die (type, context_die) /* Now output info about the data members and type members. */ for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member)) - gen_decl_die (member, context_die); + { + /* If we thought we were generating minimal debug info for TYPE + and then changed our minds, some of the member declarations + may have already been defined. Don't define them again, but + do put them in the right order. */ + + child = lookup_decl_die (member); + if (child) + splice_child_die (context_die, child); + else + gen_decl_die (member, context_die); + } /* Now output info about the function members (if any). */ for (member = TYPE_METHODS (type); member; member = TREE_CHAIN (member)) - gen_decl_die (member, context_die); + { + child = lookup_decl_die (member); + if (child) + splice_child_die (context_die, child); + else + gen_decl_die (member, context_die); + } } -/* Generate a DIE for a structure or union type. */ +/* Generate a DIE for a structure or union type. If TYPE_DECL_SUPPRESS_DEBUG + is set, we pretend that the type was never defined, so we only get the + member DIEs needed by later specification DIEs. */ static void gen_struct_or_union_type_die (type, context_die) @@ -8877,8 +9026,10 @@ gen_struct_or_union_type_die (type, context_die) register dw_die_ref type_die = lookup_type_die (type); register dw_die_ref scope_die = 0; register int nested = 0; + int complete = (TYPE_SIZE (type) + && ! TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))); - if (type_die && ! TYPE_SIZE (type)) + if (type_die && ! complete) return; if (TYPE_CONTEXT (type) != NULL_TREE @@ -8912,7 +9063,7 @@ gen_struct_or_union_type_die (type, context_die) } /* If this type has been completed, then give it a byte_size attribute and then give a list of members. */ - else if (TYPE_SIZE (type)) + else if (complete) { /* Prevent infinite recursion in cases where the type of some member of this type is expressed in terms of this type itself. */ @@ -9386,6 +9537,11 @@ gen_decl_die (decl, context_die) && (current_function_decl == NULL_TREE || ! DECL_ARTIFICIAL (decl))) break; + /* Emit info for the abstract instance first, if we haven't yet. */ + origin = decl_ultimate_origin (decl); + if (origin) + gen_abstract_function (origin); + if (debug_info_level > DINFO_LEVEL_TERSE) { /* Before we describe the FUNCTION_DECL itself, make sure that we @@ -9395,7 +9551,7 @@ gen_decl_die (decl, context_die) /* And its containing type. */ origin = decl_class_context (decl); if (origin != NULL_TREE) - gen_type_die (origin, context_die); + gen_type_die_for_member (origin, decl, context_die); /* And its virtual context. */ if (DECL_VINDEX (decl) != NULL_TREE) @@ -9450,7 +9606,7 @@ gen_decl_die (decl, context_die) /* And its containing type. */ origin = decl_class_context (decl); if (origin != NULL_TREE) - gen_type_die (origin, context_die); + gen_type_die_for_member (origin, decl, context_die); /* Now output the DIE to represent the data object itself. This gets complicated because of the possibility that the VAR_DECL really diff --git a/gcc/toplev.c b/gcc/toplev.c index 53a8a79..dbe5dce 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -3690,17 +3690,6 @@ rest_of_compilation (decl) set_decl_abstract_flags (decl, 0); } #endif -#ifdef DWARF2_DEBUGGING_INFO - /* Generate the DWARF2 info for the "abstract" instance - of a function which we may later generate inlined and/or - out-of-line instances of. */ - if (write_symbols == DWARF2_DEBUG) - { - set_decl_abstract_flags (decl, 1); - TIMEVAR (symout_time, dwarf2out_decl (decl)); - set_decl_abstract_flags (decl, 0); - } -#endif TIMEVAR (integration_time, save_for_inline_nocopy (decl)); DECL_SAVED_INSNS (decl)->inlinable = inlinable; goto exit_rest_of_compilation; -- 2.7.4