From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18409 invoked by alias); 28 May 2015 21:10:26 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 18350 invoked by uid 89); 28 May 2015 21:10:20 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.4 required=5.0 tests=AWL,BAYES_50,KAM_LAZY_DOMAIN_SECURITY,KAM_STOCKGEN,SPF_HELO_PASS,T_RP_MATCHES_RCVD autolearn=no version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Thu, 28 May 2015 21:10:13 +0000 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (Postfix) with ESMTPS id CEE9E2C76E2; Thu, 28 May 2015 21:10:11 +0000 (UTC) Received: from reynosa.quesejoda.com (vpn-53-17.rdu2.redhat.com [10.10.53.17]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t4SLA9VJ027057; Thu, 28 May 2015 17:10:10 -0400 Message-ID: <55678431.3030806@redhat.com> Date: Thu, 28 May 2015 21:31:00 -0000 From: Aldy Hernandez User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.6.0 MIME-Version: 1.0 To: Jason Merrill , Richard Biener , Jan Hubicka CC: gcc-patches Subject: Re: [patch 10/10] debug-early merge: compiler proper References: <554C060F.6000609@redhat.com> <555CAD35.5040304@redhat.com> <5565BB13.6040205@redhat.com> In-Reply-To: <5565BB13.6040205@redhat.com> Content-Type: multipart/mixed; boundary="------------010604050907030004000500" X-SW-Source: 2015-05/txt/msg02701.txt.bz2 This is a multi-part message in MIME format. --------------010604050907030004000500 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Content-length: 8503 On 05/27/2015 08:39 AM, Jason Merrill wrote: > On 05/20/2015 11:50 AM, Aldy Hernandez wrote: >> + determine anscestry later. */ > > ancestry Fixed. > >> +static bool early_dwarf_dumping; > > Sorry for the late bikeshedding, but "dumping" suddently strikes me as > odd, since there is no output as with other dumping in the compiler. Can > we change that to "generation" or "building"? Fixed. > >> + /* Reuse DIE even with a differing context. >> + >> + This happens when called through >> + dwarf2out_abstract_function for formal parameter >> + packs. */ >> + gcc_assert (parm_die->die_parent->die_tag >> + == DW_TAG_GNU_formal_parameter_pack); > > Does this mean we're generating a new DW_TAG_GNU_formal_parameter_pack > in late debug even though we already generated one in early debug? If > so, why? I will be addressing this separately, as we're likely to iterate many times on this :). > >> - /* It is possible to have both DECL_ABSTRACT_P 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. If so, DECLARATION takes >> priority; >> - we'll get back to the abstract instance when done with the >> class. */ >> - >> - /* The class-scope declaration DIE must be the primary DIE. */ >> - if (origin && declaration && class_or_namespace_scope_p (context_die)) >> - { >> - origin = NULL; >> - gcc_assert (!old_die); >> - } > > Can't this happen anymore? As discussed on IRC, this is dead code in the presence of debug-early, and no longer applicable with the upcoming DECL_ABSTRACT* redesign. > >> + if ((is_cu_die (old_die->die_parent) >> + /* FIXME: Jason doesn't like this condition, but it fixes >> + the inconsistency/ICE with the following Fortran test: >> + >> + module some_m >> + contains >> + logical function funky (FLAG) >> + funky = .true. >> + end function >> + end module >> + >> + Another alternative is !is_cu_die (context_die). >> + */ >> + || old_die->die_parent->die_tag == DW_TAG_module > > I like it now. :) > You can leave the rest of the comment. Updated comment. > >> + /* For non DECL_EXTERNALs, if range information is available, fill >> + the DIE with it. */ >> else if (!DECL_EXTERNAL (decl)) >> { >> HOST_WIDE_INT cfa_fb_offset; >> + >> struct function *fun = DECL_STRUCT_FUNCTION (decl); >> >> - if (!old_die || !get_AT (old_die, DW_AT_inline)) >> - equate_decl_number_to_die (decl, subr_die); >> + /* If we have no fun->fde, we have no range information. >> + Skip over and fill in range information in the second >> + dwarf pass. */ >> + if (!fun->fde) >> + goto no_fde_continue; > > How about controlling this block with !early_dwarf so you don't need to > deal with missing FDE? Fixed. > >> if (generic_decl_parm >> && lang_hooks.function_parameter_pack_p (generic_decl_parm)) >> - gen_formal_parameter_pack_die (generic_decl_parm, >> - parm, subr_die, >> - &parm); >> + { >> + if (early_dwarf_dumping) >> + gen_formal_parameter_pack_die (generic_decl_parm, >> + parm, subr_die, >> + &parm); >> + else if (parm) >> + parm = DECL_CHAIN (parm); >> + } > > Let's try only setting generic_decl when early_dwarf. Fixed. > >> + /* Unless we have an existing non-declaration DIE, equate the new >> + DIE. */ >> + if (!old_die || is_declaration_die (old_die)) >> + equate_decl_number_to_die (decl, subr_die); > ... >> + if (decl && (DECL_ABSTRACT_P (decl) || declaration || old_die == NULL >> + /* If we make it to a specialization, we have already >> + handled the declaration by virtue of early dwarf. >> + If so, make a new assocation if available, so late >> + dwarf can find it. */ >> + || (specialization_p && early_dwarf_dumping))) >> equate_decl_number_to_die (decl, var_die); > > Why are the conditions so different? Can we use the function condition > for variables, too? Hmmm...because they were already that way when I arrived? :). How about what I do in the attached patch, which also seems to do the trick?: if (decl && (DECL_ABSTRACT_P (decl) || !old_die || is_declaration_die (old_die))) >> + /* Do nothing. This must have been early dumped and it >> + won't even need location information since it's a >> + DW_AT_inline function. */ >> + for (dw_die_ref c = context_die; c; c = c->die_parent) >> + if (c->die_tag == DW_TAG_inlined_subroutine >> + || c->die_tag == DW_TAG_subprogram) >> + { >> + gcc_assert (get_AT (c, DW_AT_inline)); >> + break; >> + } > > Maybe wrap this in #ifdef ENABLE_CHECKING. Done. > >> + /* Do the new DIE dance. */ >> + stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt); >> + BLOCK_DIE (stmt) = stmt_die; >> + } >> + } >> + else if (BLOCK_ABSTRACT_ORIGIN (stmt)) >> + { >> + /* If this is an inlined instance, create a new lexical die for >> + anything below to attach DW_AT_abstract_origin to. */ >> + stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt); >> + } >> + else >> + { >> + if (!stmt_die) >> + { >> + /* This is the first time we are creating something for this >> + block. */ >> + stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt); >> + BLOCK_DIE (stmt) = stmt_die; >> + } > > Surely we don't need to repeat the new_die call three times; the first > and last are both controlled by !stmt_die. And don't we want to set > BLOCK_DIE for the inlined case as well, so that we can find the DIE > again in late debug? Done. > >> + /* Fill in the size of variable-length fields in late dwarf. */ >> + if (TREE_ASM_WRITTEN (type) >> + && !early_dwarf_dumping) >> + { >> + tree member; >> + for (member = TYPE_FIELDS (type); member; member = DECL_CHAIN >> (member)) >> + fill_variable_array_bounds (TREE_TYPE (member)); >> + return; >> + } > > Why is this happening in late dwarf? I'm concerned that front-end > information that is necessary to do this might be lost by that point. > >> + /* Variable-length types may be incomplete even if >> + TREE_ASM_WRITTEN. For such types, fall through to >> + gen_array_type_die() and possibly fill in >> + DW_AT_{upper,lower}_bound attributes. */ >> + if ((TREE_CODE (type) != ARRAY_TYPE >> + && TREE_CODE (type) != RECORD_TYPE >> + && TREE_CODE (type) != UNION_TYPE >> + && TREE_CODE (type) != QUAL_UNION_TYPE) >> + || (TYPE_SIZE (type) >> + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)) > > Similarly, why check for INTEGER_CST here? Will work on this now. >> + bool t = early_dwarf_dumping; >> + early_dwarf_dumping = true; >> + dwarf2out_decl (decl); >> + early_dwarf_dumping = t; > > Let's use a RAII (resource acquisition is initialization) pattern for > this and dwarf2out_imported_module_or_decl and dwarf2out_early_global_decl: > > struct set_early_dwarf { > bool saved; > set_early_dwarf(): saved(early_dwarf) { early_dwarf = true; } > ~set_early_dwarf() { early_dwarf = saved; } > }; Done. >> + /* When generating LTO bytecode we can not generate new assembler >> + names at this point and all important decls got theirs via >> + free-lang-data. */ >> + if (((!flag_generate_lto && !flag_generate_offload) >> + || DECL_ASSEMBLER_NAME_SET_P (decl)) >> + && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl) > > Doesn't early_finish happen before free_lang_data, so we should be fine? Done. Could you please verify that all the changes so far are what you had in mind, before I move onto the variable-length arrays and the DECL_ABSTRACT rework? I am only including the diff for dwarf2out, which is what are reviewing. I can include the rest in subsequent iterations if you prefer. The attached patch has been retested for --enable-languages=all,go,ada, and with the GDB testsuite. Please let me know. Thanks. Aldy --------------010604050907030004000500 Content-Type: text/x-patch; name="dearly-dwarf2out.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="dearly-dwarf2out.patch" Content-length: 63866 diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 15c545e..2c120a3 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -1268,16 +1268,6 @@ struct GTY((for_user)) dwarf_file_data { int emitted_number; }; -typedef struct GTY(()) deferred_locations_struct -{ - tree variable; - dw_die_ref die; -} deferred_locations; - - -static GTY(()) vec *deferred_locations_list; - - /* Describe an entry into the .debug_addr section. */ enum ate_kind { @@ -2448,6 +2438,7 @@ build_cfa_aligned_loc (dw_cfa_location *cfa, static void dwarf2out_init (const char *); static void dwarf2out_finish (const char *); +static void dwarf2out_early_finish (void); static void dwarf2out_assembly_start (void); static void dwarf2out_define (unsigned int, const char *); static void dwarf2out_undef (unsigned int, const char *); @@ -2457,7 +2448,8 @@ static void dwarf2out_function_decl (tree); static void dwarf2out_begin_block (unsigned, unsigned); static void dwarf2out_end_block (unsigned, unsigned); static bool dwarf2out_ignore_block (const_tree); -static void dwarf2out_global_decl (tree); +static void dwarf2out_early_global_decl (tree); +static void dwarf2out_late_global_decl (tree); static void dwarf2out_type_decl (tree, int); static void dwarf2out_imported_module_or_decl (tree, tree, tree, bool); static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree, @@ -2474,6 +2466,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = { dwarf2out_init, dwarf2out_finish, + dwarf2out_early_finish, dwarf2out_assembly_start, dwarf2out_define, dwarf2out_undef, @@ -2495,7 +2488,8 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = dwarf2out_begin_function, dwarf2out_end_function, /* end_function */ dwarf2out_function_decl, /* function_decl */ - dwarf2out_global_decl, + dwarf2out_early_global_decl, + dwarf2out_late_global_decl, dwarf2out_type_decl, /* type_decl */ dwarf2out_imported_module_or_decl, debug_nothing_tree, /* deferred_inline_function */ @@ -2636,10 +2630,20 @@ typedef struct GTY((chain_circular ("%h.die_sib"), for_user)) die_struct { /* Die is used and must not be pruned as unused. */ BOOL_BITFIELD die_perennial_p : 1; BOOL_BITFIELD comdat_type_p : 1; /* DIE has a type signature */ + /* Die was generated early via dwarf2out_early_global_decl. */ + BOOL_BITFIELD dumped_early : 1; /* Lots of spare bits. */ } die_node; +/* Set to TRUE while dwarf2out_early_global_decl is running. */ +static bool early_dwarf; +struct set_early_dwarf { + bool saved; + set_early_dwarf () : saved(early_dwarf) { early_dwarf = true; } + ~set_early_dwarf () { early_dwarf = saved; } +}; + /* Evaluate 'expr' while 'c' is set to each child of DIE in order. */ #define FOR_EACH_CHILD(die, c, expr) do { \ c = die->die_child; \ @@ -2690,9 +2694,13 @@ typedef struct GTY(()) comdat_type_struct } comdat_type_node; -/* The limbo die list structure. */ +/* A list of DIEs for which we can't determine ancestry (parent_die + field) just yet. Later in dwarf2out_finish we will fill in the + missing bits. */ typedef struct GTY(()) limbo_die_struct { dw_die_ref die; + /* The tree for which this DIE was created for. We use this to + determine ancestry later. */ tree created_for; struct limbo_die_struct *next; } @@ -2939,7 +2947,7 @@ static GTY((length ("abbrev_die_table_allocated"))) /* Number of elements currently allocated for abbrev_die_table. */ static GTY(()) unsigned abbrev_die_table_allocated; -/* Number of elements in type_die_table currently in use. */ +/* Number of elements in abbrev_die_table currently in use. */ static GTY(()) unsigned abbrev_die_table_in_use; /* Size (in elements) of increments by which we may expand the @@ -3021,9 +3029,6 @@ static GTY(()) struct dwarf_file_data * last_emitted_file; /* Number of internal labels generated by gen_internal_sym(). */ static GTY(()) int label_num; -/* Cached result of previous call to lookup_filename. */ -static GTY(()) struct dwarf_file_data * file_table_last_lookup; - static GTY(()) vec *tmpl_value_parm_die_table; /* Instances of generic types for which we need to generate debug @@ -3108,7 +3113,7 @@ static inline dw_die_ref get_AT_ref (dw_die_ref, enum dwarf_attribute); static bool is_cxx (void); static bool is_fortran (void); static bool is_ada (void); -static void remove_AT (dw_die_ref, enum dwarf_attribute); +static bool remove_AT (dw_die_ref, enum dwarf_attribute); static void remove_child_TAG (dw_die_ref, enum dwarf_tag); static void add_child_die (dw_die_ref, dw_die_ref); static dw_die_ref new_die (enum dwarf_tag, dw_die_ref, tree); @@ -4748,16 +4753,17 @@ is_ada (void) return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83; } -/* Remove the specified attribute if present. */ +/* Remove the specified attribute if present. Return TRUE if removal + was successful. */ -static void +static bool remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind) { dw_attr_ref a; unsigned ix; if (! die) - return; + return false; FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a) if (a->dw_attr == attr_kind) @@ -4769,8 +4775,9 @@ remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind) /* vec::ordered_remove should help reduce the number of abbrevs that are needed. */ die->die_attr->ordered_remove (ix); - return; + return true; } + return false; } /* Remove CHILD from its parent. PREV must have the property that @@ -4844,6 +4851,7 @@ remove_child_TAG (dw_die_ref die, enum dwarf_tag tag) while (c->die_tag == tag) { remove_child_with_prev (c, prev); + c->die_parent = NULL; /* Might have removed every child. */ if (c == c->die_sib) return; @@ -4873,6 +4881,21 @@ add_child_die (dw_die_ref die, dw_die_ref child_die) die->die_child = child_die; } +/* Unassociate CHILD from its parent, and make its parent be + NEW_PARENT. */ + +static void +reparent_child (dw_die_ref child, dw_die_ref new_parent) +{ + for (dw_die_ref p = child->die_parent->die_child; ; p = p->die_sib) + if (p->die_sib == child) + { + remove_child_with_prev (child, p); + break; + } + add_child_die (new_parent, child); +} + /* Move CHILD, which must be a child of PARENT or the DIE for which PARENT is the specification, to the end of PARENT's list of children. This is done by removing and re-adding it. */ @@ -4880,8 +4903,6 @@ add_child_die (dw_die_ref die, dw_die_ref child_die) static void splice_child_die (dw_die_ref parent, dw_die_ref 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) @@ -4896,17 +4917,13 @@ splice_child_die (dw_die_ref parent, dw_die_ref child) || (child->die_parent == get_AT_ref (parent, DW_AT_specification))); - for (p = child->die_parent->die_child; ; p = p->die_sib) - if (p->die_sib == child) - { - remove_child_with_prev (child, p); - break; - } - - add_child_die (parent, child); + reparent_child (child, parent); } -/* Return a pointer to a newly created DIE node. */ +/* Create and return a new die with a parent of PARENT_DIE. If + PARENT_DIE is NULL, the new DIE is placed in limbo and an + associated tree T must be supplied to determine parenthood + later. */ static inline dw_die_ref new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t) @@ -4915,12 +4932,44 @@ new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t) die->die_tag = tag_value; + if (early_dwarf) + die->dumped_early = true; + if (parent_die != NULL) add_child_die (parent_die, die); else { limbo_die_node *limbo_node; + /* No DIEs created after early dwarf should end up in limbo, + because the limbo list should not persist past LTO + streaming. */ + if (tag_value != DW_TAG_compile_unit + /* These are allowed because they're generated while + breaking out COMDAT units late. */ + && tag_value != DW_TAG_type_unit + && !early_dwarf + /* Allow nested functions to live in limbo because they will + only temporarily live there, as decls_for_scope will fix + them up. */ + && (TREE_CODE (t) != FUNCTION_DECL + || !decl_function_context (t)) + /* Same as nested functions above but for types. Types that + are local to a function will be fixed in + decls_for_scope. */ + && (!RECORD_OR_UNION_TYPE_P (t) + || !TYPE_CONTEXT (t) + || TREE_CODE (TYPE_CONTEXT (t)) != FUNCTION_DECL) + /* FIXME debug-early: Allow late limbo DIE creation for LTO, + especially in the ltrans stage, but once we implement LTO + dwarf streaming, we should remove this exception. */ + && !in_lto_p) + { + fprintf (stderr, "symbol ended up in limbo too late:"); + debug_generic_stmt (t); + gcc_unreachable (); + } + limbo_node = ggc_cleared_alloc (); limbo_node->die = die; limbo_node->created_for = t; @@ -5576,9 +5625,18 @@ print_die (dw_die_ref die, FILE *outfile) unsigned ix; print_spaces (outfile); - fprintf (outfile, "DIE %4ld: %s (%p)\n", + fprintf (outfile, "DIE %4ld: %s (%p)", die->die_offset, dwarf_tag_name (die->die_tag), (void*) die); + if (die->dumped_early) + { + fprintf (outfile, " (DUMPED EARLY"); + const char *name = get_AT_string (die, DW_AT_name); + if (name) + fprintf (outfile, ": %s", name); + fputc (')', outfile); + } + fputc ('\n', outfile); print_spaces (outfile); fprintf (outfile, " abbrev id: %lu", die->die_abbrev); fprintf (outfile, " offset: %ld", die->die_offset); @@ -5652,6 +5710,34 @@ debug_dwarf (void) print_indent = 0; print_die (comp_unit_die (), stderr); } + +/* Sanity checks on DIEs. */ + +static void +check_die (dw_die_ref die) +{ + /* A debugging information entry that is a member of an abstract + instance tree [that has DW_AT_inline] should not contain any + attributes which describe aspects of the subroutine which vary + between distinct inlined expansions or distinct out-of-line + expansions. */ + unsigned ix; + dw_attr_ref a; + bool inline_found = false; + FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a) + if (a->dw_attr == DW_AT_inline && a->dw_attr_val.v.val_unsigned) + inline_found = true; + if (inline_found) + { + /* Catch the most common mistakes. */ + FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a) + gcc_assert (a->dw_attr != DW_AT_low_pc + && a->dw_attr != DW_AT_high_pc + && a->dw_attr != DW_AT_location + && a->dw_attr != DW_AT_frame_base + && a->dw_attr != DW_AT_GNU_all_call_sites); + } +} /* Start a new compilation unit DIE for an include file. OLD_UNIT is the CU for the enclosing include file, if any. BINCL_DIE is the DW_TAG_GNU_BINCL @@ -8799,9 +8885,10 @@ output_die (dw_die_ref die) if (! die->comdat_type_p && die->die_id.die_symbol) output_die_symbol (die); - dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)", + dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)%s", (unsigned long)die->die_offset, - dwarf_tag_name (die->die_tag)); + dwarf_tag_name (die->die_tag), + die->dumped_early ? " (early)" : ""); FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a) { @@ -16106,17 +16193,6 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, bool cache_p, return tree_add_const_value_attribute_for_decl (die, decl); } -/* Add VARIABLE and DIE into deferred locations list. */ - -static void -defer_location (tree variable, dw_die_ref die) -{ - deferred_locations entry; - entry.variable = variable; - entry.die = die; - vec_safe_push (deferred_locations_list, entry); -} - /* Helper function for tree_add_const_value_attribute. Natively encode initializer INIT into an array. Return true if successful. */ @@ -16798,14 +16874,17 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, /* Add subscript info to TYPE_DIE, describing an array TYPE, collapsing possibly nested array subscripts in a flat sequence if COLLAPSE_P is true. Note that the block of subscript information for an array type also - includes information about the element type of the given array type. */ + includes information about the element type of the given array type. + + This function reuses previously set type and bound information if + available. */ static void add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p) { unsigned dimension_number; tree lower, upper; - dw_die_ref subrange_die; + dw_die_ref child = type_die->die_child; for (dimension_number = 0; TREE_CODE (type) == ARRAY_TYPE && (dimension_number == 0 || collapse_p); @@ -16819,7 +16898,37 @@ add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p) /* Arrays come in three flavors: Unspecified bounds, fixed bounds, and (in GNU C only) variable bounds. Handle all three forms here. */ - subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL); + + /* Find and reuse a previously generated DW_TAG_subrange_type if + available. + + For multi-dimensional arrays, as we iterate through the + various dimensions in the enclosing for loop above, we also + iterate through the DIE children and pick at each + DW_TAG_subrange_type previously generated (if available). + Each child DW_TAG_subrange_type DIE describes the range of + the current dimension. At this point we should have as many + DW_TAG_subrange_type's as we have dimensions in the + array. */ + dw_die_ref subrange_die = NULL; + if (child) + while (1) + { + child = child->die_sib; + if (child->die_tag == DW_TAG_subrange_type) + subrange_die = child; + if (child == type_die->die_child) + { + /* If we wrapped around, stop looking next time. */ + child = NULL; + break; + } + if (child->die_tag == DW_TAG_subrange_type) + break; + } + if (!subrange_die) + subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL); + if (domain) { /* We have an array type with specified bounds. */ @@ -16827,7 +16936,8 @@ add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p) upper = TYPE_MAX_VALUE (domain); /* Define the index type. */ - if (TREE_TYPE (domain)) + if (TREE_TYPE (domain) + && !get_AT (subrange_die, DW_AT_type)) { /* ??? This is probably an Ada unnamed subrange type. Ignore the TREE_TYPE field. We can't emit debug info for this @@ -16849,8 +16959,9 @@ add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p) to produce useful results, go ahead and output the lower bound solo, and hope the debugger can cope. */ - add_bound_info (subrange_die, DW_AT_lower_bound, lower, NULL); - if (upper) + if (!get_AT (subrange_die, DW_AT_lower_bound)) + add_bound_info (subrange_die, DW_AT_lower_bound, lower, NULL); + if (upper && !get_AT (subrange_die, DW_AT_upper_bound)) add_bound_info (subrange_die, DW_AT_upper_bound, upper, NULL); } @@ -17477,6 +17588,26 @@ decl_start_label (tree decl) } #endif +/* For variable-length arrays that have been previously generated, but + may be incomplete due to missing subscript info, fill the subscript + info. Return TRUE if this is one of those cases. */ +static bool +fill_variable_array_bounds (tree type) +{ + if (TREE_ASM_WRITTEN (type) + && TREE_CODE (type) == ARRAY_TYPE + && TYPE_SIZE (type) + && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + { + dw_die_ref array_die = lookup_type_die (type); + if (!array_die) + return false; + add_subscript_info (array_die, type, !is_ada ()); + return true; + } + return false; +} + /* These routines generate the internal representation of the DIE's for the compilation unit. Debugging information is collected by walking the declaration trees passed in from dwarf2out_decl(). */ @@ -17484,7 +17615,6 @@ decl_start_label (tree decl) static void gen_array_type_die (tree type, dw_die_ref context_die) { - dw_die_ref scope_die = scope_die_for (type, context_die); dw_die_ref array_die; /* GNU compilers represent multidimensional array types as sequences of one @@ -17498,6 +17628,11 @@ gen_array_type_die (tree type, dw_die_ref context_die) flexibilty wrt arrays of variable size. */ bool collapse_nested_arrays = !is_ada (); + + if (fill_variable_array_bounds (type)) + return; + + dw_die_ref scope_die = scope_die_for (type, context_die); tree element_type; /* Emit DW_TAG_string_type for Fortran character types (with kind 1 only, as @@ -17853,8 +17988,64 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p, { tree node_or_origin = node ? node : origin; tree ultimate_origin; - dw_die_ref parm_die - = new_die (DW_TAG_formal_parameter, context_die, node); + dw_die_ref parm_die = NULL; + + if (TREE_CODE_CLASS (TREE_CODE (node_or_origin)) == tcc_declaration) + { + parm_die = lookup_decl_die (node); + + /* If the contexts differ, we may not be talking about the same + thing. */ + if (parm_die && parm_die->die_parent != context_die) + { + if (!DECL_ABSTRACT_P (node)) + { + /* This can happen when creating an inlined instance, in + which case we need to create a new DIE that will get + annotated with DW_AT_abstract_origin. */ + parm_die = NULL; + } + else + { + /* Reuse DIE even with a differing context. + + This happens when called through + dwarf2out_abstract_function for formal parameter + packs. */ + gcc_assert (parm_die->die_parent->die_tag + == DW_TAG_GNU_formal_parameter_pack); + } + } + + if (parm_die && parm_die->die_parent == NULL) + { + /* Check that parm_die already has the right attributes that + we would have added below. If any attributes are + missing, fall through to add them. */ + if (! DECL_ABSTRACT_P (node_or_origin) + && !get_AT (parm_die, DW_AT_location) + && !get_AT (parm_die, DW_AT_const_value)) + /* We are missing location info, and are about to add it. */ + ; + else + { + add_child_die (context_die, parm_die); + return parm_die; + } + } + } + + /* If we have a previously generated DIE, use it, unless this is an + concrete instance (origin != NULL), in which case we need a new + DIE with a corresponding DW_AT_abstract_origin. */ + bool reusing_die; + if (parm_die && origin == NULL) + reusing_die = true; + else + { + parm_die = new_die (DW_TAG_formal_parameter, context_die, node); + reusing_die = false; + } switch (TREE_CODE_CLASS (TREE_CODE (node_or_origin))) { @@ -17862,6 +18053,10 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p, ultimate_origin = decl_ultimate_origin (node_or_origin); if (node || ultimate_origin) origin = ultimate_origin; + + if (reusing_die) + goto add_location; + if (origin != NULL) add_abstract_origin_attribute (parm_die, origin); else if (emit_name_p) @@ -17881,6 +18076,7 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p, decl_quals (node_or_origin), context_die); } + add_location: if (origin == NULL && DECL_ARTIFICIAL (node)) add_AT_flag (parm_die, DW_AT_artificial, 1); @@ -18394,26 +18590,94 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) { tree origin = decl_ultimate_origin (decl); dw_die_ref subr_die; - tree outer_scope; dw_die_ref old_die = lookup_decl_die (decl); + + /* This function gets called multiple times for different stages of + the debug process. For example, for func() in this code: + + namespace S + { + void func() { ... } + } + + ...we get called 4 times. Twice in early debug and twice in + late debug: + + Early debug + ----------- + + 1. Once while generating func() within the namespace. This is + the declaration. The declaration bit below is set, as the + context is the namespace. + + A new DIE will be generated with DW_AT_declaration set. + + 2. Once for func() itself. This is the specification. The + declaration bit below is clear as the context is the CU. + + We will use the cached DIE from (1) to create a new DIE with + DW_AT_specification pointing to the declaration in (1). + + Late debug via rest_of_handle_final() + ------------------------------------- + + 3. Once generating func() within the namespace. This is also the + declaration, as in (1), but this time we will early exit below + as we have a cached DIE and a declaration needs no additional + annotations (no locations), as the source declaration line + info is enough. + + 4. Once for func() itself. As in (2), this is the specification, + but this time we will re-use the cached DIE, and just annotate + it with the location information that should now be available. + + For something without namespaces, but with abstract instances, we + are also called a multiple times: + + class Base + { + public: + Base (); // constructor declaration (1) + }; + + Base::Base () { } // constructor specification (2) + + Early debug + ----------- + + 1. Once for the Base() constructor by virtue of it being a + member of the Base class. This is done via + rest_of_type_compilation. + + This is a declaration, so a new DIE will be created with + DW_AT_declaration. + + 2. Once for the Base() constructor definition, but this time + while generating the abstract instance of the base + constructor (__base_ctor) which is being generated via early + debug of reachable functions. + + Even though we have a cached version of the declaration (1), + we will create a DW_AT_specification of the declaration DIE + in (1). + + 3. Once for the __base_ctor itself, but this time, we generate + an DW_AT_abstract_origin version of the DW_AT_specification in + (2). + + Late debug via rest_of_handle_final + ----------------------------------- + + 4. One final time for the __base_ctor (which will have a cached + DIE with DW_AT_abstract_origin created in (3). This time, + we will just annotate the location information now + available. + */ int declaration = (current_function_decl != decl || class_or_namespace_scope_p (context_die)); premark_used_types (DECL_STRUCT_FUNCTION (decl)); - /* It is possible to have both DECL_ABSTRACT_P 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. If so, DECLARATION takes priority; - we'll get back to the abstract instance when done with the class. */ - - /* The class-scope declaration DIE must be the primary DIE. */ - if (origin && declaration && class_or_namespace_scope_p (context_die)) - { - origin = NULL; - gcc_assert (!old_die); - } - /* Now that the C++ front end lazily declares artificial member fns, we might need to retrofit the declaration into its class. */ if (!declaration && !origin && !old_die @@ -18422,6 +18686,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) && debug_info_level > DINFO_LEVEL_TERSE) old_die = force_decl_die (decl); + bool dumped_early = false; + /* An inlined instance, tag a new DIE with DW_AT_abstract_origin. */ if (origin != NULL) { gcc_assert (!declaration || local_scope_p (context_die)); @@ -18431,19 +18697,34 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) if (old_die && old_die->die_parent == NULL) add_child_die (context_die, old_die); - subr_die = new_die (DW_TAG_subprogram, context_die, decl); - add_abstract_origin_attribute (subr_die, origin); - /* This is where the actual code for a cloned function is. - Let's emit linkage name attribute for it. This helps - debuggers to e.g, set breakpoints into - constructors/destructors when the user asks "break - K::K". */ - add_linkage_name (subr_die, decl); + if (old_die && get_AT_ref (old_die, DW_AT_abstract_origin)) + { + /* If we have a DW_AT_abstract_origin we have a working + cached version. */ + subr_die = old_die; + } + else + { + subr_die = new_die (DW_TAG_subprogram, context_die, decl); + add_abstract_origin_attribute (subr_die, origin); + /* This is where the actual code for a cloned function is. + Let's emit linkage name attribute for it. This helps + debuggers to e.g, set breakpoints into + constructors/destructors when the user asks "break + K::K". */ + add_linkage_name (subr_die, decl); + } } + /* A cached copy, possibly from early dwarf generation. Reuse as + much as possible. */ else if (old_die) { - expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl)); - struct dwarf_file_data * file_index = lookup_filename (s.file); + /* A declaration that has been previously dumped needs no + additional information. */ + if (declaration) + return; + + dumped_early = old_die->dumped_early; if (!get_AT_flag (old_die, DW_AT_declaration) /* We can have a normal definition following an inline one in the @@ -18453,7 +18734,13 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) { /* Detect and ignore this case, where we are trying to output something we have already output. */ - return; + if (get_AT (old_die, DW_AT_low_pc) + || get_AT (old_die, DW_AT_ranges)) + return; + + /* If we have no location information, this must be a + partially generated DIE from early dwarf generation. + Fall through and generate it. */ } /* If the definition comes from the same place as the declaration, @@ -18463,23 +18750,43 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) instances of inlines, since the spec requires the out-of-line copy to have the same parent. For local class methods, this doesn't apply; we just use the old DIE. */ - if ((is_cu_die (old_die->die_parent) || context_die == NULL) - && (DECL_ARTIFICIAL (decl) - || (get_AT_file (old_die, DW_AT_decl_file) == file_index - && (get_AT_unsigned (old_die, DW_AT_decl_line) - == (unsigned) s.line)))) + expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl)); + struct dwarf_file_data * file_index = lookup_filename (s.file); + if ((is_cu_die (old_die->die_parent) + /* This condition fixes the inconsistency/ICE with the + following Fortran test (or some derivative thereof) while + building libgfortran: + + module some_m + contains + logical function funky (FLAG) + funky = .true. + end function + end module + */ + || old_die->die_parent->die_tag == DW_TAG_module + || context_die == NULL) + && (DECL_ARTIFICIAL (decl) + || (get_AT_file (old_die, DW_AT_decl_file) == file_index + && (get_AT_unsigned (old_die, DW_AT_decl_line) + == (unsigned) s.line)))) { subr_die = old_die; - /* Clear out the declaration attribute and the formal parameters. - Do not remove all children, because it is possible that this - declaration die was forced using force_decl_die(). In such - cases die that forced declaration die (e.g. TAG_imported_module) - is one of the children that we do not want to remove. */ - remove_AT (subr_die, DW_AT_declaration); - remove_AT (subr_die, DW_AT_object_pointer); - remove_child_TAG (subr_die, DW_TAG_formal_parameter); + /* Clear out the declaration attribute, but leave the + parameters so they can be augmented with location + information later. Unless this was a declaration, in + which case, wipe out the nameless parameters and recreate + them further down. */ + if (remove_AT (subr_die, DW_AT_declaration)) + { + + remove_AT (subr_die, DW_AT_object_pointer); + remove_child_TAG (subr_die, DW_TAG_formal_parameter); + } } + /* Make a specification pointing to the previously built + declaration. */ else { subr_die = new_die (DW_TAG_subprogram, context_die, decl); @@ -18501,6 +18808,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) } } } + /* Create a fresh DIE for anything else. */ else { subr_die = new_die (DW_TAG_subprogram, context_die, decl); @@ -18527,6 +18835,11 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) add_accessibility_attribute (subr_die, decl); } + /* Unless we have an existing non-declaration DIE, equate the new + DIE. */ + if (!old_die || is_declaration_die (old_die)) + equate_decl_number_to_die (decl, subr_die); + if (declaration) { if (!old_die || !get_AT (old_die, DW_AT_inline)) @@ -18544,17 +18857,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) if (lang_hooks.decls.function_decl_deleted_p (decl) && (! dwarf_strict)) add_AT_flag (subr_die, DW_AT_GNU_deleted, 1); - - /* The first time we see a member function, it is in the context of - the class to which it belongs. We make sure of this by emitting - the class first. The next time is the definition, which is - handled above. The two may come from the same source text. - - Note that force_decl_die() forces function declaration die. It is - later reused to represent definition. */ - equate_decl_number_to_die (decl, subr_die); } } + /* Tag abstract instances with DW_AT_inline. */ else if (DECL_ABSTRACT_P (decl)) { if (DECL_DECLARED_INLINE_P (decl)) @@ -18575,18 +18880,15 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) if (DECL_DECLARED_INLINE_P (decl) && lookup_attribute ("artificial", DECL_ATTRIBUTES (decl))) add_AT_flag (subr_die, DW_AT_artificial, 1); - - equate_decl_number_to_die (decl, subr_die); } - else if (!DECL_EXTERNAL (decl)) + /* For non DECL_EXTERNALs, if range information is available, fill + the DIE with it. */ + else if (!DECL_EXTERNAL (decl) && !early_dwarf) { HOST_WIDE_INT cfa_fb_offset; - struct function *fun = DECL_STRUCT_FUNCTION (decl); - if (!old_die || !get_AT (old_die, DW_AT_inline)) - equate_decl_number_to_die (decl, subr_die); + struct function *fun = DECL_STRUCT_FUNCTION (decl); - gcc_checking_assert (fun); if (!flag_reorder_blocks_and_partition) { dw_fde_ref fde = fun->fde; @@ -18740,12 +19042,13 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) compute_frame_pointer_to_fb_displacement (cfa_fb_offset); if (fun->static_chain_decl) - add_AT_location_description (subr_die, DW_AT_static_link, - loc_list_from_tree (fun->static_chain_decl, 2, NULL)); + add_AT_location_description + (subr_die, DW_AT_static_link, + loc_list_from_tree (fun->static_chain_decl, 2, NULL)); } /* Generate child dies for template paramaters. */ - if (debug_info_level > DINFO_LEVEL_TERSE) + if (early_dwarf && debug_info_level > DINFO_LEVEL_TERSE) gen_generic_params_dies (decl); /* Now output descriptions of the arguments for this function. This gets @@ -18764,12 +19067,17 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) if (debug_info_level <= DINFO_LEVEL_TERSE) ; else if (declaration) - gen_formal_types_die (decl, subr_die); + { + /* Only generate a prototype's parameters once. */ + if (!dumped_early) + gen_formal_types_die (decl, subr_die); + } else { /* Generate DIEs to represent all known formal parameters. */ tree parm = DECL_ARGUMENTS (decl); - tree generic_decl = lang_hooks.decls.get_generic_function_decl (decl); + tree generic_decl = early_dwarf + ? lang_hooks.decls.get_generic_function_decl (decl) : NULL; tree generic_decl_parm = generic_decl ? DECL_ARGUMENTS (generic_decl) : NULL; @@ -18834,11 +19142,14 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) gen_unspecified_parameters_die (decl, subr_die); } + if (subr_die != old_die) + /* Add the calling convention attribute if requested. */ + add_calling_convention_attribute (subr_die, decl); + /* Output Dwarf info for all of the stuff within the body of the function - (if it has one - it may be just a declaration). */ - outer_scope = DECL_INITIAL (decl); + (if it has one - it may be just a declaration). - /* OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent + OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent a function. This BLOCK actually represents the outermost binding contour for the function, i.e. the contour in which the function's formal parameters and labels get declared. Curiously, it appears that the front @@ -18852,6 +19163,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) a BLOCK node representing the function's outermost pair of curly braces, and any blocks used for the base and member initializers of a C++ constructor function. */ + tree outer_scope = DECL_INITIAL (decl); if (! declaration && outer_scope && TREE_CODE (outer_scope) != ERROR_MARK) { int call_site_note_count = 0; @@ -18861,6 +19173,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) if (DECL_NAME (DECL_RESULT (decl))) gen_decl_die (DECL_RESULT (decl), NULL, subr_die); + /* The first time through decls_for_scope we will generate the + DIEs for the locals. The second time, we fill in the + location info. */ decls_for_scope (outer_scope, subr_die); if (call_arg_locations && !dwarf_strict) @@ -19012,10 +19327,6 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) call_site_count = -1; tail_call_site_count = -1; } - - if (subr_die != old_die) - /* Add the calling convention attribute if requested. */ - add_calling_convention_attribute (subr_die, decl); } /* Returns a hash value for X (which really is a die_struct). */ @@ -19035,6 +19346,33 @@ block_die_hasher::equal (die_struct *x, die_struct *y) return x->decl_id == y->decl_id && x->die_parent == y->die_parent; } +/* Return TRUE if DECL, which may have been previously generated as + OLD_DIE, is a candidate for a DW_AT_specification. DECLARATION is + true if decl (or its origin) is either an extern declaration or a + class/namespace scoped declaration. + + The declare_in_namespace support causes us to get two DIEs for one + variable, both of which are declarations. We want to avoid + considering one to be a specification, so we must test for + DECLARATION and DW_AT_declaration. */ +static inline bool +decl_will_get_specification_p (dw_die_ref old_die, tree decl, bool declaration) +{ + return (old_die && TREE_STATIC (decl) && !declaration + && get_AT_flag (old_die, DW_AT_declaration) == 1); +} + +/* Return true if DECL is a local static. */ + +static inline bool +local_function_static (tree decl) +{ + gcc_assert (TREE_CODE (decl) == VAR_DECL); + return TREE_STATIC (decl) + && DECL_CONTEXT (decl) + && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL; +} + /* Generate a DIE to represent a declared data object. Either DECL or ORIGIN must be non-null. */ @@ -19047,7 +19385,6 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) tree ultimate_origin; dw_die_ref var_die; dw_die_ref old_die = decl ? lookup_decl_die (decl) : NULL; - dw_die_ref origin_die; bool declaration = (DECL_EXTERNAL (decl_or_origin) || class_or_namespace_scope_p (context_die)); bool specialization_p = false; @@ -19162,11 +19499,74 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) return; } + dw_die_ref origin_die = NULL; + + if (old_die && old_die->dumped_early) + { + if (decl_will_get_specification_p (old_die, decl, declaration)) + { + /* If we already have a DW_AT_specification, all we need is + location info. */ + if (get_AT (old_die, DW_AT_specification)) + { + var_die = old_die; + goto gen_variable_die_location; + } + /* Otherwise fall-thru so we can make a new variable die + along with a DW_AT_specification. */ + } + else if (declaration) + { + /* A declaration that has been previously dumped, needs no + further annotations, since it doesn't need location on + the second pass. */ + return; + } + else if (old_die->die_parent != context_die) + { + /* If the contexts differ, it means we _MAY_ not be talking + about the same thing. */ + if (origin) + { + /* If we will be creating an inlined instance, we need a + new DIE that will get annotated with + DW_AT_abstract_origin. Clear things so we can get a + new DIE. */ + gcc_assert (!DECL_ABSTRACT_P (decl)); + old_die = NULL; + } + else + { + /* In some cases we end up with different contexts because + the context_die is set to the context of the containing + function, whereas the cached die is correctly set to the + (possible) enclosing lexical scope (DW_TAG_lexical_block). + In which case, special case it (hack). + + See dwarf2out_decl and its use of + local_function_static to see how this can happened. + In java, it can happen with non local statics, hence + we do not check for TREE_STATIC here. */ + gcc_assert (!DECL_CONTEXT (decl) + || TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL); + var_die = old_die; + goto gen_variable_die_location; + } + } + else + { + /* If a DIE was dumped early, it still needs location info. + Skip to where we fill the location bits. */ + var_die = old_die; + goto gen_variable_die_location; + } + } + /* If the compiler emitted a definition for the DECL declaration - and if we already emitted a DIE for it, don't emit a second + and we already emitted a DIE for it, don't emit a second DIE for it again. Allow re-declarations of DECLs that are inside functions, though. */ - if (old_die && declaration && !local_scope_p (context_die)) + else if (old_die && !declaration && !local_scope_p (context_die)) return; /* For static data members, the declaration in the class is supposed @@ -19177,7 +19577,6 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) else var_die = new_die (DW_TAG_variable, context_die, decl); - origin_die = NULL; if (origin != NULL) origin_die = add_abstract_origin_attribute (var_die, origin); @@ -19188,14 +19587,8 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) copy decls and set the DECL_ABSTRACT_P flag on them instead of sharing them. - ??? Duplicated blocks have been rewritten to use .debug_ranges. - - ??? The declare_in_namespace support causes us to get two DIEs for one - variable, both of which are declarations. We want to avoid considering - one to be a specification, so we must test that this DIE is not a - declaration. */ - else if (old_die && TREE_STATIC (decl) && ! declaration - && get_AT_flag (old_die, DW_AT_declaration) == 1) + ??? Duplicated blocks have been rewritten to use .debug_ranges. */ + else if (decl_will_get_specification_p (old_die, decl, declaration)) { /* This is a definition of a C++ class level static. */ add_AT_specification (var_die, old_die); @@ -19249,9 +19642,11 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) if (declaration) add_AT_flag (var_die, DW_AT_declaration, 1); - if (decl && (DECL_ABSTRACT_P (decl) || declaration || old_die == NULL)) + if (decl && (DECL_ABSTRACT_P (decl) + || !old_die || is_declaration_die (old_die))) equate_decl_number_to_die (decl, var_die); + gen_variable_die_location: if (! declaration && (! DECL_ABSTRACT_P (decl_or_origin) /* Local static vars are shared between all clones/inlines, @@ -19264,13 +19659,11 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) to add it again. */ && (origin_die == NULL || get_AT (origin_die, DW_AT_location) == NULL)) { - if (TREE_CODE (decl_or_origin) == VAR_DECL && TREE_STATIC (decl_or_origin) - && !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl_or_origin))) - defer_location (decl_or_origin, var_die); + if (early_dwarf) + add_pubname (decl_or_origin, var_die); else - add_location_or_const_value_attribute (var_die, decl_or_origin, + add_location_or_const_value_attribute (var_die, decl_or_origin, decl == NULL, DW_AT_location); - add_pubname (decl_or_origin, var_die); } else tree_add_const_value_attribute_for_decl (var_die, decl_or_origin); @@ -19284,7 +19677,12 @@ gen_const_die (tree decl, dw_die_ref context_die) dw_die_ref const_die; tree type = TREE_TYPE (decl); + const_die = lookup_decl_die (decl); + if (const_die) + return; + const_die = new_die (DW_TAG_constant, context_die, decl); + equate_decl_number_to_die (decl, const_die); add_name_and_src_coords_attributes (const_die, decl); add_type_attribute (const_die, type, TYPE_QUAL_CONST, context_die); if (TREE_PUBLIC (decl)) @@ -19300,14 +19698,20 @@ static void gen_label_die (tree decl, dw_die_ref context_die) { tree origin = decl_ultimate_origin (decl); - dw_die_ref lbl_die = new_die (DW_TAG_label, context_die, decl); + dw_die_ref lbl_die = lookup_decl_die (decl); rtx insn; char label[MAX_ARTIFICIAL_LABEL_BYTES]; - if (origin != NULL) - add_abstract_origin_attribute (lbl_die, origin); - else - add_name_and_src_coords_attributes (lbl_die, decl); + if (!lbl_die) + { + lbl_die = new_die (DW_TAG_label, context_die, decl); + equate_decl_number_to_die (decl, lbl_die); + + if (origin != NULL) + add_abstract_origin_attribute (lbl_die, origin); + else + add_name_and_src_coords_attributes (lbl_die, decl); + } if (DECL_ABSTRACT_P (decl)) equate_decl_number_to_die (decl, lbl_die); @@ -19461,13 +19865,56 @@ add_high_low_attributes (tree stmt, dw_die_ref die) static void gen_lexical_block_die (tree stmt, dw_die_ref context_die) { - dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt); + dw_die_ref old_die = BLOCK_DIE (stmt); + dw_die_ref stmt_die; + if (!old_die) + { + stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt); + BLOCK_DIE (stmt) = stmt_die; + } - if (call_arg_locations) - BLOCK_DIE (stmt) = stmt_die; + if (BLOCK_ABSTRACT (stmt)) + { + if (old_die) + { +#ifdef ENABLE_CHECKING + /* This must have been generated early and it won't even + need location information since it's a DW_AT_inline + function. */ + for (dw_die_ref c = context_die; c; c = c->die_parent) + if (c->die_tag == DW_TAG_inlined_subroutine + || c->die_tag == DW_TAG_subprogram) + { + gcc_assert (get_AT (c, DW_AT_inline)); + break; + } +#endif + return; + } + } + else if (BLOCK_ABSTRACT_ORIGIN (stmt)) + { + /* If this is an inlined instance, create a new lexical die for + anything below to attach DW_AT_abstract_origin to. */ + if (old_die) + { + stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt); + BLOCK_DIE (stmt) = stmt_die; + old_die = NULL; + } + } - if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt)) - add_high_low_attributes (stmt, stmt_die); + if (old_die) + stmt_die = old_die; + + if (!early_dwarf) + { + /* A non abstract block whose blocks have already been reordered + should have the instruction range for this block. If so, set the + high/low attributes. */ + if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt)) + add_high_low_attributes (stmt, stmt_die); + } decls_for_scope (stmt, stmt_die); } @@ -19962,6 +20409,16 @@ static void gen_struct_or_union_type_die (tree type, dw_die_ref context_die, enum debug_info_usage usage) { + /* Fill in the size of variable-length fields in late dwarf. */ + if (TREE_ASM_WRITTEN (type) + && !early_dwarf) + { + tree member; + for (member = TYPE_FIELDS (type); member; member = DECL_CHAIN (member)) + fill_variable_array_bounds (TREE_TYPE (member)); + return; + } + dw_die_ref type_die = lookup_type_die (type); dw_die_ref scope_die = 0; int nested = 0; @@ -20081,7 +20538,11 @@ gen_typedef_die (tree decl, dw_die_ref context_die) tree origin; if (TREE_ASM_WRITTEN (decl)) - return; + { + if (DECL_ORIGINAL_TYPE (decl)) + fill_variable_array_bounds (DECL_ORIGINAL_TYPE (decl)); + return; + } TREE_ASM_WRITTEN (decl) = 1; type_die = new_die (DW_TAG_typedef, context_die, decl); @@ -20097,6 +20558,9 @@ gen_typedef_die (tree decl, dw_die_ref context_die) { type = DECL_ORIGINAL_TYPE (decl); + if (type == error_mark_node) + return; + gcc_assert (type != TREE_TYPE (decl)); equate_type_number_to_die (TREE_TYPE (decl), type_die); } @@ -20104,6 +20568,9 @@ gen_typedef_die (tree decl, dw_die_ref context_die) { type = TREE_TYPE (decl); + if (type == error_mark_node) + return; + if (is_naming_typedef_decl (TYPE_NAME (type))) { /* Here, we are in the case of decl being a typedef naming @@ -20164,13 +20631,15 @@ gen_tagged_type_die (tree type, || !is_tagged_type (type)) return; + if (TREE_ASM_WRITTEN (type)) + need_pop = 0; /* If this is a nested type whose containing class hasn't been written out yet, writing it out will cover this one, too. This does not apply to instantiations of member class templates; they need to be added to the containing class as they are generated. FIXME: This hurts the idea of combining type decls from multiple TUs, since we can't predict what set of template instantiations we'll get. */ - if (TYPE_CONTEXT (type) + else if (TYPE_CONTEXT (type) && AGGREGATE_TYPE_P (TYPE_CONTEXT (type)) && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type))) { @@ -20302,7 +20771,19 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die, } if (TREE_ASM_WRITTEN (type)) - return; + { + /* Variable-length types may be incomplete even if + TREE_ASM_WRITTEN. For such types, fall through to + gen_array_type_die() and possibly fill in + DW_AT_{upper,lower}_bound attributes. */ + if ((TREE_CODE (type) != ARRAY_TYPE + && TREE_CODE (type) != RECORD_TYPE + && TREE_CODE (type) != UNION_TYPE + && TREE_CODE (type) != QUAL_UNION_TYPE) + || (TYPE_SIZE (type) + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)) + return; + } switch (TREE_CODE (type)) { @@ -20354,9 +20835,6 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die, break; case ARRAY_TYPE: - gen_array_type_die (type, context_die); - break; - case VECTOR_TYPE: gen_array_type_die (type, context_die); break; @@ -20527,8 +21005,11 @@ process_scope_var (tree stmt, tree decl, tree origin, dw_die_ref context_die) if (die != NULL && die->die_parent == NULL) add_child_die (context_die, die); else if (TREE_CODE (decl_or_origin) == IMPORTED_DECL) - dwarf2out_imported_module_or_decl_1 (decl_or_origin, DECL_NAME (decl_or_origin), - stmt, context_die); + { + if (early_dwarf) + dwarf2out_imported_module_or_decl_1 (decl_or_origin, DECL_NAME (decl_or_origin), + stmt, context_die); + } else gen_decl_die (decl, origin, context_die); } @@ -20742,7 +21223,9 @@ setup_namespace_context (tree thing, dw_die_ref context_die) type) within its namespace, if appropriate. For compatibility with older debuggers, namespace DIEs only contain - declarations; all definitions are emitted at CU scope. */ + declarations; all definitions are emitted at CU scope, with + DW_AT_specification pointing to the declaration (like with class + members). */ static dw_die_ref declare_in_namespace (tree thing, dw_die_ref context_die) @@ -21059,16 +21542,65 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die) return NULL; } -/* Output debug information for global decl DECL. Called from toplev.c after - compilation proper has finished. */ +/* Output initial debug information for global DECL. Called at the + end of the parsing process. + + This is the initial debug generation process. As such, the DIEs + generated may be incomplete. A later debug generation pass + (dwarf2out_late_global_decl) will augment the information generated + in this pass (e.g., with complete location info). */ static void -dwarf2out_global_decl (tree decl) +dwarf2out_early_global_decl (tree decl) { - /* Output DWARF2 information for file-scope tentative data object - declarations, file-scope (extern) function declarations (which - had no corresponding body) and file-scope tagged type declarations - and definitions which have not yet been forced out. */ + set_early_dwarf s; + + /* gen_decl_die() will set DECL_ABSTRACT because + cgraph_function_possibly_inlined_p() returns true. This is in + turn will cause DW_AT_inline attributes to be set. + + This happens because at early dwarf generation, there is no + cgraph information, causing cgraph_function_possibly_inlined_p() + to return true. Trick cgraph_function_possibly_inlined_p() + while we generate dwarf early. */ + bool save = symtab->global_info_ready; + symtab->global_info_ready = true; + + /* We don't handle TYPE_DECLs. If required, they'll be reached via + other DECLs and they can point to template types or other things + that dwarf2out can't handle when done via dwarf2out_decl. */ + if (TREE_CODE (decl) != TYPE_DECL + && TREE_CODE (decl) != PARM_DECL) + { + tree save_fndecl = current_function_decl; + if (TREE_CODE (decl) == FUNCTION_DECL) + { + /* No cfun means the symbol has no body, so there's nothing + to emit. */ + if (!DECL_STRUCT_FUNCTION (decl)) + goto early_decl_exit; + + current_function_decl = decl; + } + dwarf2out_decl (decl); + if (TREE_CODE (decl) == FUNCTION_DECL) + current_function_decl = save_fndecl; + } + early_decl_exit: + symtab->global_info_ready = save; +} + +/* Output debug information for global decl DECL. Called from + toplev.c after compilation proper has finished. */ + +static void +dwarf2out_late_global_decl (tree decl) +{ + /* Output any global decls we missed or fill-in any location + information we were unable to determine on the first pass. + + Skip over functions because they were handled by the + debug_hooks->function_decl() call in rest_of_handle_final. */ if ((TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl)) && !POINTER_BOUNDS_P (decl)) dwarf2out_decl (decl); @@ -21080,7 +21612,10 @@ static void dwarf2out_type_decl (tree decl, int local) { if (!local) - dwarf2out_decl (decl); + { + set_early_dwarf s; + dwarf2out_decl (decl); + } } /* Output debug information for imported module or decl DECL. @@ -21188,6 +21723,8 @@ dwarf2out_imported_module_or_decl (tree decl, tree name, tree context, gcc_assert (decl); + set_early_dwarf s; + /* To emit DW_TAG_imported_module or DW_TAG_imported_decl, we need two DIEs. We need decl DIE for reference and scope die. First, get DIE for the decl itself. */ @@ -21214,7 +21751,6 @@ dwarf2out_imported_module_or_decl (tree decl, tree name, tree context, /* OK, now we have DIEs for decl as well as scope. Emit imported die. */ dwarf2out_imported_module_or_decl_1 (decl, name, context, scope_die); - } /* Output debug information for namelists. */ @@ -21254,13 +21790,22 @@ gen_namelist_decl (tree name, dw_die_ref scope_die, tree item_decls) } -/* Write the debugging output for DECL. */ +/* Write the debugging output for DECL and return the DIE. */ static void dwarf2out_decl (tree decl) { dw_die_ref context_die = comp_unit_die (); +#ifdef ENABLE_CHECKING + /* Save some info so we can later determine if we erroneously + created a DIE for something we had already created a DIE for. + We should always be reusing DIEs created early. */ + dw_die_ref early_die = NULL; + if (decl_die_table) + early_die = lookup_decl_die (decl); +#endif + switch (TREE_CODE (decl)) { case ERROR_MARK: @@ -21313,21 +21858,8 @@ dwarf2out_decl (tree decl) break; case VAR_DECL: - /* Ignore this VAR_DECL if it refers to a file-scope extern data object - declaration and if the declaration was never even referenced from - within this entire compilation unit. We suppress these DIEs in - order to save space in the .debug section (by eliminating entries - which are probably useless). Note that we must not suppress - block-local extern declarations (whether used or not) because that - would screw-up the debugger's name lookup mechanism and cause it to - miss things which really ought to be in scope at a given point. */ - if (DECL_EXTERNAL (decl) && !TREE_USED (decl)) - return; - /* For local statics lookup proper context die. */ - if (TREE_STATIC (decl) - && DECL_CONTEXT (decl) - && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL) + if (local_function_static (decl)) context_die = lookup_decl_die (DECL_CONTEXT (decl)); /* If we are in terse mode, don't generate any DIEs to represent any @@ -21382,6 +21914,19 @@ dwarf2out_decl (tree decl) } gen_decl_die (decl, NULL, context_die); + + dw_die_ref die = lookup_decl_die (decl); + if (die) + check_die (die); +#ifdef ENABLE_CHECKING + /* If we early created a DIE, make sure it didn't get re-created by + mistake. */ + if (early_die && early_die->dumped_early) + gcc_assert (early_die == die + /* We can have a differing DIE if and only if, the + new one is a specification of the old one. */ + || get_AT_ref (die, DW_AT_specification) == early_die); +#endif } /* Write the debugging output for DECL. */ @@ -21468,23 +22013,16 @@ dwarf_file_hasher::hash (dwarf_file_data *p) section) and references to those files numbers (in the .debug_srcinfo and.debug_macinfo sections). If the filename given as an argument is not found in our current list, add it to the list and assign it the next - available unique index number. In order to speed up searches, we remember - the index of the filename was looked up last. This handles the majority of - all searches. */ + available unique index number. */ static struct dwarf_file_data * lookup_filename (const char *file_name) { struct dwarf_file_data * created; - /* Check to see if the file name that was searched on the previous - call matches this file name. If so, return the index. */ - if (file_table_last_lookup - && (file_name == file_table_last_lookup->filename - || filename_cmp (file_table_last_lookup->filename, file_name) == 0)) - return file_table_last_lookup; + if (!file_name) + return NULL; - /* Didn't match the previous lookup, search the table. */ dwarf_file_data **slot = file_table->find_slot_with_hash (file_name, htab_hash_string (file_name), INSERT); @@ -24523,11 +25061,20 @@ optimize_location_lists (dw_die_ref die) static void dwarf2out_finish (const char *filename) { - limbo_die_node *node, *next_node; comdat_type_node *ctnode; - unsigned int i; dw_die_ref main_comp_unit_die; + /* If the limbo list has anything, it should be things that were + created after the compilation proper. Anything from the early + dwarf pass, should have parents and should never be in the limbo + list this late. */ + for (limbo_die_node *node = limbo_die_list; node; node = node->next) + gcc_assert (node->die->die_tag == DW_TAG_compile_unit + || !node->die->dumped_early); + + /* Flush out any latecomers to the limbo party. */ + dwarf2out_early_finish (); + /* PCH might result in DW_AT_producer string being restored from the header compilation, so always fill it with empty string initially and overwrite only here. */ @@ -24557,65 +25104,6 @@ dwarf2out_finish (const char *filename) add_comp_dir_attribute (comp_unit_die ()); } - if (deferred_locations_list) - for (i = 0; i < deferred_locations_list->length (); i++) - { - add_location_or_const_value_attribute ( - (*deferred_locations_list)[i].die, - (*deferred_locations_list)[i].variable, - false, - DW_AT_location); - } - - /* Traverse the limbo die list, and add parent/child links. The only - dies without parents that should be here are concrete instances of - inline functions, and the comp_unit_die. We can ignore the comp_unit_die. - For concrete instances, we can get the parent die from the abstract - instance. */ - for (node = limbo_die_list; node; node = next_node) - { - dw_die_ref die = node->die; - next_node = node->next; - - if (die->die_parent == NULL) - { - dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin); - - if (origin && origin->die_parent) - add_child_die (origin->die_parent, die); - else if (is_cu_die (die)) - ; - else if (seen_error ()) - /* It's OK to be confused by errors in the input. */ - add_child_die (comp_unit_die (), die); - else - { - /* In certain situations, the lexical block containing a - nested function can be optimized away, which results - in the nested function die being orphaned. Likewise - with the return type of that nested function. Force - this to be a child of the containing function. - - It may happen that even the containing function got fully - inlined and optimized out. In that case we are lost and - assign the empty child. This should not be big issue as - the function is likely unreachable too. */ - gcc_assert (node->created_for); - - if (DECL_P (node->created_for)) - origin = get_context_die (DECL_CONTEXT (node->created_for)); - else if (TYPE_P (node->created_for)) - origin = scope_die_for (node->created_for, comp_unit_die ()); - else - origin = comp_unit_die (); - - add_child_die (origin, die); - } - } - } - - limbo_die_list = NULL; - #if ENABLE_ASSERT_CHECKING { dw_die_ref die = comp_unit_die (), c; @@ -24625,23 +25113,6 @@ dwarf2out_finish (const char *filename) resolve_addr (comp_unit_die ()); move_marked_base_types (); - for (node = deferred_asm_name; node; node = node->next) - { - tree decl = node->created_for; - /* When generating LTO bytecode we can not generate new assembler - names at this point and all important decls got theirs via - free-lang-data. */ - if (((!flag_generate_lto && !flag_generate_offload) - || DECL_ASSEMBLER_NAME_SET_P (decl)) - && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)) - { - add_linkage_attr (node->die, decl); - move_linkage_attr (node->die); - } - } - - deferred_asm_name = NULL; - /* Walk through the list of incomplete types again, trying once more to emit full debugging info for them. */ retry_incomplete_types (); @@ -24680,6 +25151,7 @@ dwarf2out_finish (const char *filename) /* Traverse the DIE's and add add sibling attributes to those DIE's that have children. */ add_sibling_attributes (comp_unit_die ()); + limbo_die_node *node; for (node = limbo_die_list; node; node = node->next) add_sibling_attributes (node->die); for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next) @@ -24941,6 +25413,83 @@ dwarf2out_finish (const char *filename) output_indirect_strings (); } +/* Perform any cleanups needed after the early debug generation pass + has run. */ + +static void +dwarf2out_early_finish (void) +{ + limbo_die_node *node, *next_node; + + /* Add DW_AT_linkage_name for all deferred DIEs. */ + for (node = deferred_asm_name; node; node = node->next) + { + tree decl = node->created_for; + if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl) + /* A missing DECL_ASSEMBLER_NAME can be a constant DIE that + ended up in in deferred_asm_name before we knew it was + constant and never written to disk. */ + && DECL_ASSEMBLER_NAME (decl)) + { + add_linkage_attr (node->die, decl); + move_linkage_attr (node->die); + } + } + deferred_asm_name = NULL; + + /* Traverse the limbo die list, and add parent/child links. The only + dies without parents that should be here are concrete instances of + inline functions, and the comp_unit_die. We can ignore the comp_unit_die. + For concrete instances, we can get the parent die from the abstract + instance. + + The point here is to flush out the limbo list so that it is empty + and we don't need to stream it for LTO. */ + for (node = limbo_die_list; node; node = next_node) + { + dw_die_ref die = node->die; + next_node = node->next; + + if (die->die_parent == NULL) + { + dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin); + + if (origin && origin->die_parent) + add_child_die (origin->die_parent, die); + else if (is_cu_die (die)) + ; + else if (seen_error ()) + /* It's OK to be confused by errors in the input. */ + add_child_die (comp_unit_die (), die); + else + { + /* In certain situations, the lexical block containing a + nested function can be optimized away, which results + in the nested function die being orphaned. Likewise + with the return type of that nested function. Force + this to be a child of the containing function. + + It may happen that even the containing function got fully + inlined and optimized out. In that case we are lost and + assign the empty child. This should not be big issue as + the function is likely unreachable too. */ + gcc_assert (node->created_for); + + if (DECL_P (node->created_for)) + origin = get_context_die (DECL_CONTEXT (node->created_for)); + else if (TYPE_P (node->created_for)) + origin = scope_die_for (node->created_for, comp_unit_die ()); + else + origin = comp_unit_die (); + + add_child_die (origin, die); + } + } + } + + limbo_die_list = NULL; +} + /* Reset all state within dwarf2out.c so that we can rerun the compiler within the same process. For use by toplev::finalize. */ @@ -24979,13 +25528,10 @@ dwarf2out_c_finalize (void) cold_text_section = NULL; current_unit_personality = NULL; - deferred_locations_list = NULL; - next_die_offset = 0; single_comp_unit_die = NULL; comdat_type_list = NULL; limbo_die_list = NULL; - deferred_asm_name = NULL; file_table = NULL; decl_die_table = NULL; common_block_die_table = NULL; @@ -25018,7 +25564,6 @@ dwarf2out_c_finalize (void) poc_label_num = 0; last_emitted_file = NULL; label_num = 0; - file_table_last_lookup = NULL; tmpl_value_parm_die_table = NULL; generic_type_instances = NULL; frame_pointer_fb_offset = 0; --------------010604050907030004000500--