From patchwork Wed Jan 28 18:29:20 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aldy Hernandez X-Patchwork-Id: 433909 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 8E4741401F0 for ; Thu, 29 Jan 2015 05:32:41 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; q=dns; s=default; b=SjY+RPwYWxzIB+Bg+ 8x49DNrcDZ87gTXCsW0eN7GZsuq8Qi0a/PbToK6ar3HvmMrAArsu70Hw6M5xKhYv W5SroVGPuTMTRpA+3jA0Lt+ZNS4Xd3aScAOB6oCZF05XAyo0OjI9P7LgaUi+skBO EC4cjvO84MMpOjM7mD6l546jMo= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; s=default; bh=XFniyiWOjr8RJ9ir2jyS/m7 oO8o=; b=vrxDs9efUBNyf9YbyXPp9AxcndN3MTVdZcmFIQjbMgtpnH2LK//j5Qf jfc8Yt4BQlQkf194TpoQ8h1nExMRgRLJGHK8CsTIVWtyeJsRC1ZLIWMWTPUs9seR KWGGdYucOmqj1MDez5JU+bCDT1sAd4PNS60qabvMBBqDLtPAimFk= Received: (qmail 11902 invoked by alias); 28 Jan 2015 18:29:29 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 11851 invoked by uid 89); 28 Jan 2015 18:29:27 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-0.3 required=5.0 tests=AWL, BAYES_50, SPF_HELO_PASS, SPF_PASS, T_RP_MATCHES_RCVD autolearn=ham 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; Wed, 28 Jan 2015 18:29:24 +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 (8.14.4/8.14.4) with ESMTP id t0SITMP4016670 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 28 Jan 2015 13:29:22 -0500 Received: from reynosa.quesejoda.com (vpn-61-230.rdu2.redhat.com [10.10.61.230]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t0SITKJZ009070; Wed, 28 Jan 2015 13:29:20 -0500 Message-ID: <54C92A80.80306@redhat.com> Date: Wed, 28 Jan 2015 10:29:20 -0800 From: Aldy Hernandez User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.4.0 MIME-Version: 1.0 To: Jason Merrill CC: Richard Biener , gcc-patches Subject: Re: [debug-early] C++ clones and limbo DIEs References: <54B87E5B.1090502@redhat.com> <54B88149.1040906@redhat.com> <54B94F4D.4040009@redhat.com> <54B97854.7040007@redhat.com> <54C296B5.4050506@redhat.com> <54C7FA41.8010903@redhat.com> <54C92A59.4070401@redhat.com> In-Reply-To: <54C92A59.4070401@redhat.com> And now with the actual patch ;-). * c-family/cilk.c (create_cilk_wrapper_body): Emit debug information for wrappers. * cp/decl2.c (emit_debug_for_namespace): Add FIXME note for templates. * cp/optimize.c (maybe_clone_body): Emit early debug for clones. * dbxout.c (dbx_debug_hooks): Add early_finish field. * sdbout.c (sdb_debug_hooks): Same. * vmsdbgout.c (vmsdbg_debug_hooks): Same. * debug.h (gcc_debug_hooks): Same. * dwarf2out.c (dwarf2_debug_hooks): Same. (new_die): Inhibit limbo dies unless generating early dwarf. (gen_subprogram_die): Do not create a new DIE if we have an old DIE and it has DW_AT_abstract_origin set. (lookup_filename): Return NULL when no file name. (optimize_location_lists): Abstract flushing of limbo list to... (dwarf2out_early_finish): ...here. New function. (dwarf2out_abstract_function): Do not set DECL_ABSTRACT_P recursively if DECL_ABSTRACT_P of parent is set. * toplev.c (toplev::main): Add temporary debugging aid. * tree.c (free_lang_data): Call debug_hooks->early_finish. diff --git a/gcc/c-family/cilk.c b/gcc/c-family/cilk.c index 82dd2cb..c9a4a4b 100644 --- a/gcc/c-family/cilk.c +++ b/gcc/c-family/cilk.c @@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see #include "cgraph.h" #include "diagnostic.h" #include "cilk.h" +#include "debug.h" enum add_variable_type { /* Reference to previously-defined variable. */ @@ -573,6 +574,14 @@ create_cilk_wrapper_body (tree stmt, struct wrapper_data *wd) pop_cfun_to (outer); + /* It is rather unfortunate that Cilk creates trees this late + (during gimplification). However, until this gets fixed, + specially handle emitting DWARF for this new function and + immediately clean up the limbo_die_list where the new function's + DIE will inevitably end up. */ + debug_hooks->early_global_decl (fndecl); + debug_hooks->early_finish (); + /* Recognize the new function. */ call_graph_add_fn (fndecl); return fndecl; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 691688b..70abc99 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -4346,6 +4346,9 @@ emit_debug_for_namespace (tree name_space, void* data ATTRIBUTE_UNUSED) check_global_declarations (vec, len); + /* FIXME: What does this do for templates? I think we don't want to + send a template off to early_global_decl, but rather walk through + its specializations and emit them. */ for (tree t = level->names; t; t = TREE_CHAIN(t)) debug_hooks->early_global_decl (t); diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index 62e32d2..ab3e93e 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -539,6 +539,10 @@ maybe_clone_body (tree fn) /* Start processing the function. */ start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED); + /* Generate early dwarf for the clone now that we have a body + for it. */ + debug_hooks->early_global_decl (clone); + /* Tell cgraph if both ctors or both dtors are known to have the same body. */ if (can_alias diff --git a/gcc/dbxout.c b/gcc/dbxout.c index 430a2eb..202ef8a 100644 --- a/gcc/dbxout.c +++ b/gcc/dbxout.c @@ -359,6 +359,7 @@ const struct gcc_debug_hooks dbx_debug_hooks = dbxout_init, dbxout_finish, debug_nothing_void, + debug_nothing_void, debug_nothing_int_charstar, debug_nothing_int_charstar, dbxout_start_source_file, @@ -400,6 +401,7 @@ const struct gcc_debug_hooks xcoff_debug_hooks = dbxout_init, dbxout_finish, debug_nothing_void, + debug_nothing_void, debug_nothing_int_charstar, debug_nothing_int_charstar, dbxout_start_source_file, diff --git a/gcc/debug.c b/gcc/debug.c index 449d3a1..d0e00c0 100644 --- a/gcc/debug.c +++ b/gcc/debug.c @@ -27,6 +27,7 @@ const struct gcc_debug_hooks do_nothing_debug_hooks = { debug_nothing_charstar, debug_nothing_charstar, + debug_nothing_void, /* early_finish */ debug_nothing_void, debug_nothing_int_charstar, debug_nothing_int_charstar, diff --git a/gcc/debug.h b/gcc/debug.h index f9485bc..a8d3f23 100644 --- a/gcc/debug.h +++ b/gcc/debug.h @@ -30,6 +30,9 @@ struct gcc_debug_hooks /* Output debug symbols. */ void (* finish) (const char *main_filename); + /* Run cleanups necessary after early debug generation. */ + void (* early_finish) (void); + /* Called from cgraph_optimize before starting to assemble functions/variables/toplevel asms. */ void (* assembly_start) (void); diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index e3ccda2..bf9268a 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -106,6 +106,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-dfa.h" #include "gdb/gdb-index.h" #include "rtl-iter.h" +#include "print-tree.h" static void dwarf2out_source_line (unsigned int, const char *, int, bool); static rtx_insn *last_var_location_insn; @@ -2424,6 +2425,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 *); @@ -2451,6 +2453,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = { dwarf2out_init, dwarf2out_finish, + dwarf2out_early_finish, dwarf2out_assembly_start, dwarf2out_define, dwarf2out_undef, @@ -4903,6 +4906,25 @@ new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t) { 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 some corner case (Cilk), is creating definitions too late, + it should itself take care of calling + dwarf2out_early_global_decl() and flushing the limbo_die_list + afterwards via dwarf2out_early_finish(). See cilk.c for an + example of such stupidity. */ + if (tag_value != DW_TAG_compile_unit + && !early_dwarf_dumping + /* FIXME: 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_tree (t); + gcc_unreachable (); + } + limbo_node = ggc_cleared_alloc (); limbo_node->die = die; limbo_node->created_for = t; @@ -18277,9 +18299,10 @@ dwarf2out_abstract_function (tree decl) current_function_decl = decl; was_abstract = DECL_ABSTRACT_P (decl); - set_decl_abstract_flags (decl, 1); + if (!was_abstract) + set_decl_abstract_flags (decl, 1); dwarf2out_decl (decl); - if (! was_abstract) + if (!was_abstract) set_decl_abstract_flags (decl, 0); current_function_decl = save_fn; @@ -18443,14 +18466,23 @@ 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. */ @@ -21738,6 +21770,9 @@ lookup_filename (const char *file_name) { struct dwarf_file_data * created; + if (!file_name) + return NULL; + /* 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 @@ -24739,10 +24774,19 @@ optimize_location_lists (dw_die_ref die) static void dwarf2out_finish (const char *filename) { - limbo_die_node *node, *next_node; comdat_type_node *ctnode; 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->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. */ @@ -24767,55 +24811,6 @@ dwarf2out_finish (const char *filename) add_comp_dir_attribute (comp_unit_die ()); } - /* 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; @@ -24863,6 +24858,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) @@ -25124,6 +25120,66 @@ 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) +{ + /* 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. */ + limbo_die_node *node, *next_node; + 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. */ diff --git a/gcc/sdbout.c b/gcc/sdbout.c index d7b2d6b..43b8cf2 100644 --- a/gcc/sdbout.c +++ b/gcc/sdbout.c @@ -279,6 +279,7 @@ const struct gcc_debug_hooks sdb_debug_hooks = { sdbout_init, /* init */ sdbout_finish, /* finish */ + debug_nothing_void, /* early_finish */ debug_nothing_void, /* assembly_start */ debug_nothing_int_charstar, /* define */ debug_nothing_int_charstar, /* undef */ diff --git a/gcc/toplev.c b/gcc/toplev.c index 42a2cdc..6b58ed2 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -2136,6 +2136,21 @@ toplev::main (int argc, char **argv) if (version_flag) print_version (stderr, ""); + /* FIXME: Temporary debugging aid to know which LTO phase we are in + without having to pass -v to the driver and all its verbosity. */ + if (0) + { + fprintf(stderr, "MAIN: cc1*\n"); + if (flag_lto) + fprintf(stderr, "\tMAIN: flag_lto\n"); + if (in_lto_p) + fprintf(stderr, "\tMAIN: in_lto_p\n"); + if (flag_wpa) + fprintf(stderr, "\tMAIN: flag_wpa\n"); + if (flag_ltrans) + fprintf(stderr, "\tMAIN: flag_ltrans\n"); + } + if (help_flag) print_plugins_help (stderr, ""); diff --git a/gcc/tree.c b/gcc/tree.c index 8743763..80b4287 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -5730,6 +5730,10 @@ free_lang_data (void) { unsigned i; + /* Clean up anything that needs cleaning up after initial debug + generation. */ + (*debug_hooks->early_finish) (); + /* If we are the LTO frontend we have freed lang-specific data already. */ if (in_lto_p /* FIXME: Eventually we need to remove this so the function diff --git a/gcc/vmsdbgout.c b/gcc/vmsdbgout.c index 5cb66bc..6da48eb 100644 --- a/gcc/vmsdbgout.c +++ b/gcc/vmsdbgout.c @@ -179,6 +179,7 @@ static void vmsdbgout_abstract_function (tree); const struct gcc_debug_hooks vmsdbg_debug_hooks = {vmsdbgout_init, vmsdbgout_finish, + debug_nothing_void, vmsdbgout_assembly_start, vmsdbgout_define, vmsdbgout_undef,