From patchwork Fri Nov 10 02:34:40 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Oliva X-Patchwork-Id: 836580 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-466472-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="LamK23Xt"; dkim-atps=neutral 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 3yY4090hFYz9t2R for ; Fri, 10 Nov 2017 13:35:52 +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:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=b+60W28cob+87WXjLsjdSGjPSgv/y8aEt45ySboVZokrPQTlfYKI+ tHI6FUvkU3y3HjHW2PzMCXguuaoh51ZDFbXoLlUU85ElRakbKc2VggkiZBjyBrTs ubon2adDobw23/qPNt3VQDFacxgBudxA2d5ErFDMoqH2ZpIlMuXGOs= 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:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=L7s9j3dwghqI2Fp1CGOCe2+4nP8=; b=LamK23Xt3JQUlGWhzMIU hnoQpkGVgKORuiJfD+l7CVos0PqB1hmEj+qeKDtLbB0r4PgRu6PBTE/MHgtB2eLU qmsXFxK8NG9jG8sbTitMQkJ+6JPE1Nx1vKEHOnRGzB1Gz2mQCD63bnV7gEFj2Ofu 2oI57aaI7G9UzsmoPHEYkNw= Received: (qmail 94431 invoked by alias); 10 Nov 2017 02:35:45 -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 94421 invoked by uid 89); 10 Nov 2017 02:35:44 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=barriers 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 ESMTP; Fri, 10 Nov 2017 02:35:43 +0000 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C9EC1C0587CE; Fri, 10 Nov 2017 02:35:41 +0000 (UTC) Received: from freie.home (ovpn04.gateway.prod.ext.phx2.redhat.com [10.5.9.4]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 894D261F24; Fri, 10 Nov 2017 02:35:40 +0000 (UTC) Received: from frit.home (frit.home [172.31.160.7]) by freie.home (8.15.2/8.15.2) with ESMTP id vAA2ZEB9003201; Fri, 10 Nov 2017 00:35:14 -0200 From: Alexandre Oliva To: Richard Biener , Jeff Law , Jason Merrill Cc: GCC Patches , Alexandre Oliva Subject: [SFN+LVU+IEPM v4 1/9] [SFN] adjust RTL insn-walking API Date: Fri, 10 Nov 2017 00:34:40 -0200 Message-Id: <20171110023448.28164-1-aoliva@redhat.com> In-Reply-To: References: This patch removes unused RTL functions, introduces alternate ones for use in a later SFN patch, and regroups other related functions so that they appear in a more consistent order. for gcc/ChangeLog * emit-rtl.c (next_nondebug_insn, prev_nondebug_insn): Reorder. (next_nonnote_nondebug_insn, prev_nonnote_nondebug_insn): Reorder. (next_nonnote_nondebug_insn_bb): New. (prev_nonnote_nondebug_insn_bb): New. (prev_nonnote_insn_bb, next_nonnote_insn_bb): Remove. * rtl.h (prev_nonnote_insn_bb, next_nonnote_insn_bb): Remove decls. (prev_nonnote_nondebug_insn_bb): Declare. (next_nonnote_nondebug_insn_bb): Declare. * cfgbuild.c (find_bb_boundaries): Adjust to skip debug insns. * cfgrtl.c (get_last_bb_insn): Likewise. * lra.c (push_insns): Likewise. --- gcc/cfgbuild.c | 2 +- gcc/cfgrtl.c | 4 ++-- gcc/emit-rtl.c | 69 ++++++++++++++++++++++++++++++++-------------------------- gcc/lra.c | 2 +- gcc/rtl.h | 4 ++-- 5 files changed, 44 insertions(+), 37 deletions(-) diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c index a0926752143d..77a221de2119 100644 --- a/gcc/cfgbuild.c +++ b/gcc/cfgbuild.c @@ -511,7 +511,7 @@ find_bb_boundaries (basic_block bb) the middle of a BB. We need to split it in the same manner as if the barrier were preceded by a control_flow_insn_p insn. */ if (!flow_transfer_insn) - flow_transfer_insn = prev_nonnote_insn_bb (insn); + flow_transfer_insn = prev_nonnote_nondebug_insn_bb (insn); } if (control_flow_insn_p (insn)) diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c index ae469088eecb..f788334ffb57 100644 --- a/gcc/cfgrtl.c +++ b/gcc/cfgrtl.c @@ -2281,11 +2281,11 @@ get_last_bb_insn (basic_block bb) end = table; /* Include any barriers that may follow the basic block. */ - tmp = next_nonnote_insn_bb (end); + tmp = next_nonnote_nondebug_insn_bb (end); while (tmp && BARRIER_P (tmp)) { end = tmp; - tmp = next_nonnote_insn_bb (end); + tmp = next_nonnote_nondebug_insn_bb (end); } return end; diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index a07671164361..2823b2eb5bcd 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -3370,20 +3370,17 @@ next_nonnote_insn (rtx_insn *insn) return insn; } -/* Return the next insn after INSN that is not a NOTE, but stop the - search before we enter another basic block. This routine does not - look inside SEQUENCEs. */ +/* Return the next insn after INSN that is not a DEBUG_INSN. This + routine does not look inside SEQUENCEs. */ rtx_insn * -next_nonnote_insn_bb (rtx_insn *insn) +next_nondebug_insn (rtx_insn *insn) { while (insn) { insn = NEXT_INSN (insn); - if (insn == 0 || !NOTE_P (insn)) + if (insn == 0 || !DEBUG_INSN_P (insn)) break; - if (NOTE_INSN_BASIC_BLOCK_P (insn)) - return NULL; } return insn; @@ -3405,67 +3402,70 @@ prev_nonnote_insn (rtx_insn *insn) return insn; } -/* Return the previous insn before INSN that is not a NOTE, but stop - the search before we enter another basic block. This routine does - not look inside SEQUENCEs. */ +/* Return the previous insn before INSN that is not a DEBUG_INSN. + This routine does not look inside SEQUENCEs. */ rtx_insn * -prev_nonnote_insn_bb (rtx_insn *insn) +prev_nondebug_insn (rtx_insn *insn) { - while (insn) { insn = PREV_INSN (insn); - if (insn == 0 || !NOTE_P (insn)) + if (insn == 0 || !DEBUG_INSN_P (insn)) break; - if (NOTE_INSN_BASIC_BLOCK_P (insn)) - return NULL; } return insn; } -/* Return the next insn after INSN that is not a DEBUG_INSN. This - routine does not look inside SEQUENCEs. */ +/* Return the next insn after INSN that is not a NOTE nor DEBUG_INSN. + This routine does not look inside SEQUENCEs. */ rtx_insn * -next_nondebug_insn (rtx_insn *insn) +next_nonnote_nondebug_insn (rtx_insn *insn) { while (insn) { insn = NEXT_INSN (insn); - if (insn == 0 || !DEBUG_INSN_P (insn)) + if (insn == 0 || (!NOTE_P (insn) && !DEBUG_INSN_P (insn))) break; } return insn; } -/* Return the previous insn before INSN that is not a DEBUG_INSN. - This routine does not look inside SEQUENCEs. */ +/* Return the next insn after INSN that is not a NOTE nor DEBUG_INSN, + but stop the search before we enter another basic block. This + routine does not look inside SEQUENCEs. */ rtx_insn * -prev_nondebug_insn (rtx_insn *insn) +next_nonnote_nondebug_insn_bb (rtx_insn *insn) { while (insn) { - insn = PREV_INSN (insn); - if (insn == 0 || !DEBUG_INSN_P (insn)) + insn = NEXT_INSN (insn); + if (insn == 0) + break; + if (DEBUG_INSN_P (insn)) + continue; + if (!NOTE_P (insn)) break; + if (NOTE_INSN_BASIC_BLOCK_P (insn)) + return NULL; } return insn; } -/* Return the next insn after INSN that is not a NOTE nor DEBUG_INSN. +/* Return the previous insn before INSN that is not a NOTE nor DEBUG_INSN. This routine does not look inside SEQUENCEs. */ rtx_insn * -next_nonnote_nondebug_insn (rtx_insn *insn) +prev_nonnote_nondebug_insn (rtx_insn *insn) { while (insn) { - insn = NEXT_INSN (insn); + insn = PREV_INSN (insn); if (insn == 0 || (!NOTE_P (insn) && !DEBUG_INSN_P (insn))) break; } @@ -3473,17 +3473,24 @@ next_nonnote_nondebug_insn (rtx_insn *insn) return insn; } -/* Return the previous insn before INSN that is not a NOTE nor DEBUG_INSN. - This routine does not look inside SEQUENCEs. */ +/* Return the previous insn before INSN that is not a NOTE nor + DEBUG_INSN, but stop the search before we enter another basic + block. This routine does not look inside SEQUENCEs. */ rtx_insn * -prev_nonnote_nondebug_insn (rtx_insn *insn) +prev_nonnote_nondebug_insn_bb (rtx_insn *insn) { while (insn) { insn = PREV_INSN (insn); - if (insn == 0 || (!NOTE_P (insn) && !DEBUG_INSN_P (insn))) + if (insn == 0) break; + if (DEBUG_INSN_P (insn)) + continue; + if (!NOTE_P (insn)) + break; + if (NOTE_INSN_BASIC_BLOCK_P (insn)) + return NULL; } return insn; diff --git a/gcc/lra.c b/gcc/lra.c index 66fbfd5477b3..88d75c18e86c 100644 --- a/gcc/lra.c +++ b/gcc/lra.c @@ -1805,7 +1805,7 @@ push_insns (rtx_insn *from, rtx_insn *to) static void setup_sp_offset (rtx_insn *from, rtx_insn *last) { - rtx_insn *before = next_nonnote_insn_bb (last); + rtx_insn *before = next_nonnote_nondebug_insn_bb (last); HOST_WIDE_INT offset = (before == NULL_RTX || ! INSN_P (before) ? 0 : lra_get_insn_recog_data (before)->sp_offset); diff --git a/gcc/rtl.h b/gcc/rtl.h index 8de5a1cada5a..9cc982172f53 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -3085,13 +3085,13 @@ extern rtx_call_insn *last_call_insn (void); extern rtx_insn *previous_insn (rtx_insn *); extern rtx_insn *next_insn (rtx_insn *); extern rtx_insn *prev_nonnote_insn (rtx_insn *); -extern rtx_insn *prev_nonnote_insn_bb (rtx_insn *); extern rtx_insn *next_nonnote_insn (rtx_insn *); -extern rtx_insn *next_nonnote_insn_bb (rtx_insn *); extern rtx_insn *prev_nondebug_insn (rtx_insn *); extern rtx_insn *next_nondebug_insn (rtx_insn *); extern rtx_insn *prev_nonnote_nondebug_insn (rtx_insn *); +extern rtx_insn *prev_nonnote_nondebug_insn_bb (rtx_insn *); extern rtx_insn *next_nonnote_nondebug_insn (rtx_insn *); +extern rtx_insn *next_nonnote_nondebug_insn_bb (rtx_insn *); extern rtx_insn *prev_real_insn (rtx_insn *); extern rtx_insn *next_real_insn (rtx); extern rtx_insn *prev_active_insn (rtx_insn *); From patchwork Fri Nov 10 02:34:41 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Oliva X-Patchwork-Id: 836581 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-466473-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="kvy0wbTK"; dkim-atps=neutral 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 3yY40c2ngbz9t2M for ; Fri, 10 Nov 2017 13:36:16 +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:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=n+3sSG2PX5yHwyhBVwGFK3fIUG7fV72LhEiIiRmoYIkiy3ZjHX6bY hq6qjBu5ycjTpPEwNqQPW3+gm+JzAB6bVYSEaA9dga9v6e6/IaXEWk2xY+PjWI5N b8vVib/3W/mcOUyT9u+h0Mj0qOBFOdjgPOWLhJzZXHZ/VHt3FGdP90= 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:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=zZ17Og2rqWhH8rgYA3SLBkOwXvk=; b=kvy0wbTKQHOFOl6DpE2/ eTZPoGbIVAIM+Pe0Baov6s4weMdCZ9F6cZN39Ar+Y+5m3isIw68W7MOIxiYLc3yS O68EQtlxkW96JGCrZw7bBZWCy92oNHdatded6koA2zPI9kohPstxzpvKe6iT1C8g NfP4OlHCq+8xJC6OAwrsYhs= Received: (qmail 95887 invoked by alias); 10 Nov 2017 02:36:04 -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 95870 invoked by uid 89); 10 Nov 2017 02:36:03 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=(unknown), UD:operands, expoperands, exp.operands 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 ESMTP; Fri, 10 Nov 2017 02:35:58 +0000 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 54FF7C0587CE; Fri, 10 Nov 2017 02:35:57 +0000 (UTC) Received: from freie.home (ovpn04.gateway.prod.ext.phx2.redhat.com [10.5.9.4]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 575AC17A7D; Fri, 10 Nov 2017 02:35:55 +0000 (UTC) Received: from frit.home (frit.home [172.31.160.7]) by freie.home (8.15.2/8.15.2) with ESMTP id vAA2ZEBA003201; Fri, 10 Nov 2017 00:35:18 -0200 From: Alexandre Oliva To: Richard Biener , Jeff Law , Jason Merrill Cc: GCC Patches , Alexandre Oliva Subject: [SFN+LVU+IEPM v4 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers Date: Fri, 10 Nov 2017 00:34:41 -0200 Message-Id: <20171110023448.28164-2-aoliva@redhat.com> In-Reply-To: References: This patch introduces a number of new macros and functions that will be used to distinguish between different kinds of debug stmts, insns and notes, namely, preexisting debug bind ones and to-be-introduced nonbind markers. In a seemingly mechanical way, it adjusts several uses of the macros and functions, so that they refer to narrower categories when appropriate. These changes, by themselves, should not have any visible effect in the compiler behavior, since the upcoming debug markers are never created with this patch alone. for gcc/ChangeLog * gimple.h (enum gimple_debug_subcode): Add GIMPLE_DEBUG_BEGIN_STMT. (gimple_debug_begin_stmt_p): New. (gimple_debug_nonbind_marker_p): New. * tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): New. (MAY_HAVE_DEBUG_BIND_STMTS): Renamed from.... (MAY_HAVE_DEBUG_STMTS): ... this. Check both. * insn-notes.def (BEGIN_STMT): New. * rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): New. (MAY_HAVE_DEBUG_BIND_INSNS): Renamed from.... (MAY_HAVE_DEBUG_INSNS): ... this. Check both. (NOTE_MARKER_LOCATION, NOTE_MARKER_P): New. (DEBUG_BIND_INSN_P, DEBUG_MARKER_INSN_P): New. (INSN_DEBUG_MARKER_KIND): New. (GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT): New. (INSN_VAR_LOCATION): Check for VAR_LOCATION. (INSN_VAR_LOCATION_PTR): New. * cfgexpand.c (expand_debug_locations): Handle debug bind insns only. (expand_gimple_basic_block): Likewise. Emit debug temps for TER deps only if debug bind insns are enabled. (pass_expand::execute): Avoid deep TER and expand debug locations for debug bind insns only. * cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Narrow debug stmts special handling down to debug bind stmts. * combine.c (try_combine): Narrow debug insns special handling down to debug bind insns. * cse.c (delete_trivially_dead_insns): Handle debug bindings. Narrow debug insns preexisting special handling down to debug bind insns. * dce.c (rest_of_handle_ud_dce): Narrow debug insns special handling down to debug bind insns. * function.c (instantiate_virtual_regs): Skip debug markers, adjust handling of debug binds. * gimple-ssa-backprop.c (backprop::prepare_change): Try debug temp insertion iff MAY_HAVE_DEBUG_BIND_STMTS. * haifa-sched.c (schedule_insn): Narrow special handling of debug insns to debug bind insns. * ipa-param-manipulation.c (ipa_modify_call_arguments): Narrow special handling of debug stmts to debug bind stmts. * ipa-split.c (split_function): Likewise. * ira.c (combine_and_move_insns): Adjust debug bind insns only. * loop-unroll.c (apply_opt_in_copies): Adjust tests on bind debug insns. * reg-stack.c (convert_regs_1): Use DEBUG_BIND_INSN_P. * regrename.c (build_def_use): Likewise. * regcprop.c (copyprop_hardreg_forward_1): Likewise. (pass_cprop_hardreg): Narrow special casing of debug insns to debug bind insns. * regstat.c (regstat_init_n_sets_and_refs): Likewise. * reload1.c (reload): Likewise. * sese.c (sese_insert_phis_for_liveouts): Narrow special casing of debug stmts to debug bind stmts. * shrink-wrap.c (move_insn_for_shrink_wrap): Likewise. * ssa-iterators.h (num_imm_uses): Likewise. * tree-cfg.c (gimple_merge_blocks): Narrow special casing of debug stmts to debug bind stmts. * tree-inline.c (tree_function_versioning): Narrow special casing of debug stmts to debug bind stmts. * tree-loop-distribution.c (generate_loops_for_partition): Narrow special casing of debug stmts to debug bind stmts. * tree-sra.c (analyze_access_subtree): Narrow special casing of debug stmts to debug bind stmts. * tree-ssa-dce.c (remove_dead_stmt): Narrow special casing of debug stmts to debug bind stmts. * tree-ssa-loop-ivopt.c (remove_unused_ivs): Narrow special casing of debug stmts to debug bind stmts. * tree-ssa-reassoc.c (reassoc_remove_stmt): Likewise. * tree-ssa-tail-merge.c (tail_merge_optimize): Narrow special casing of debug stmts to debug bind stmts. * tree-ssa-threadedge.c (propagate_threaded_block_debug_info): Likewise. * tree-ssa.c (flush_pending_stmts): Narrow special casing of debug stmts to debug bind stmts. (gimple_replace_ssa_lhs): Likewise. (insert_debug_temp_for_var_def): Likewise. (insert_debug_temps_for_defs): Likewise. (reset_debug_uses): Likewise. * tree-ssanames.c (release_ssa_name_fn): Likewise. * tree-vect-loop-manip.c (adjust_debug_stmts_now): Likewise. (adjust_debug_stmts): Likewise. (adjust_phi_and_debug_stmts): Likewise. (vect_do_peeling): Likewise. * tree-vect-loop.c (vect_transform_loop): Likewise. * valtrack.c (propagate_for_debug): Use BIND_DEBUG_INSN_P. * var-tracking.c (adjust_mems): Narrow special casing of debug insns to debug bind insns. (dv_onepart_p, dataflow_set_clar_at_call, use_type): Likewise. (compute_bb_dataflow, vt_find_locations): Likewise. (vt_expand_loc, emit_notes_for_changes): Likewise. (vt_init_cfa_base): Likewise. (vt_emit_notes): Likewise. (vt_initialize): Likewise. (vt_finalize): Likewise. --- gcc/cfgexpand.c | 8 +++---- gcc/cgraph.c | 2 +- gcc/combine.c | 12 +++++------ gcc/cse.c | 17 ++++++++------- gcc/dce.c | 2 +- gcc/function.c | 7 ++++--- gcc/gimple-ssa-backprop.c | 2 +- gcc/gimple.h | 31 ++++++++++++++++++++++----- gcc/haifa-sched.c | 4 ++-- gcc/insn-notes.def | 3 +++ gcc/ipa-param-manipulation.c | 2 +- gcc/ipa-split.c | 11 +++++----- gcc/ira.c | 4 ++-- gcc/loop-unroll.c | 6 ++++-- gcc/reg-stack.c | 4 ++-- gcc/regcprop.c | 4 ++-- gcc/regrename.c | 2 +- gcc/regstat.c | 2 +- gcc/reload1.c | 4 ++-- gcc/rtl.h | 47 +++++++++++++++++++++++++++++++++++++++-- gcc/sese.c | 2 +- gcc/shrink-wrap.c | 4 ++-- gcc/ssa-iterators.h | 2 +- gcc/tree-cfg.c | 2 +- gcc/tree-inline.c | 4 ++-- gcc/tree-loop-distribution.c | 2 +- gcc/tree-sra.c | 2 +- gcc/tree-ssa-dce.c | 2 +- gcc/tree-ssa-loop-ivopts.c | 2 +- gcc/tree-ssa-reassoc.c | 2 +- gcc/tree-ssa-tail-merge.c | 2 +- gcc/tree-ssa-threadedge.c | 2 +- gcc/tree-ssa.c | 10 ++++----- gcc/tree-ssanames.c | 2 +- gcc/tree-vect-loop-manip.c | 8 +++---- gcc/tree-vect-loop.c | 4 ++-- gcc/tree.h | 8 ++++++- gcc/valtrack.c | 2 +- gcc/var-tracking.c | 50 +++++++++++++++++++++----------------------- 39 files changed, 182 insertions(+), 104 deletions(-) diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index ca5d8dbdfd68..22a9eb45b45e 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -5309,7 +5309,7 @@ expand_debug_locations (void) flag_strict_aliasing = 0; for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - if (DEBUG_INSN_P (insn)) + if (DEBUG_BIND_INSN_P (insn)) { tree value = (tree)INSN_VAR_LOCATION_LOC (insn); rtx val; @@ -5562,7 +5562,7 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls) a_2 = ... #DEBUG ... => #D1 */ - if (MAY_HAVE_DEBUG_INSNS + if (MAY_HAVE_DEBUG_BIND_INSNS && SA.values && !is_gimple_debug (stmt)) { @@ -6183,7 +6183,7 @@ pass_expand::execute (function *fun) timevar_pop (TV_OUT_OF_SSA); SA.partition_to_pseudo = XCNEWVEC (rtx, SA.map->num_partitions); - if (MAY_HAVE_DEBUG_STMTS && flag_tree_ter) + if (MAY_HAVE_DEBUG_BIND_STMTS && flag_tree_ter) { gimple_stmt_iterator gsi; FOR_EACH_BB_FN (bb, cfun) @@ -6374,7 +6374,7 @@ pass_expand::execute (function *fun) next_bb) bb = expand_gimple_basic_block (bb, var_ret_seq != NULL_RTX); - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) expand_debug_locations (); if (deep_ter_debug_map) diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 7c3507c6ecee..536b80aac6d9 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -1459,7 +1459,7 @@ cgraph_edge::redirect_call_stmt_to_callee (void) stmts and associate D#X with parm in decl_debug_args_lookup vector to say for debug info that if parameter parm had been passed, it would have value parm_Y(D). */ - if (e->callee->clone.combined_args_to_skip && MAY_HAVE_DEBUG_STMTS) + if (e->callee->clone.combined_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS) { vec **debug_args = decl_debug_args_lookup (e->callee->decl); diff --git a/gcc/combine.c b/gcc/combine.c index eab10c599a61..78b949323771 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -3760,7 +3760,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, /* *SPLIT may be part of I2SRC, so make sure we have the original expression around for later debug processing. We should not need I2SRC any more in other cases. */ - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) i2src = copy_rtx (i2src); else i2src = NULL; @@ -4117,7 +4117,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, return 0; } - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) { struct undo *undo; @@ -4430,7 +4430,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, if (newi2pat) { - if (MAY_HAVE_DEBUG_INSNS && i2scratch) + if (MAY_HAVE_DEBUG_BIND_INSNS && i2scratch) propagate_for_debug (i2, last_combined_insn, i2dest, i2src, this_basic_block); INSN_CODE (i2) = i2_code_number; @@ -4438,7 +4438,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, } else { - if (MAY_HAVE_DEBUG_INSNS && i2src) + if (MAY_HAVE_DEBUG_BIND_INSNS && i2src) propagate_for_debug (i2, last_combined_insn, i2dest, i2src, this_basic_block); SET_INSN_DELETED (i2); @@ -4448,7 +4448,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, { LOG_LINKS (i1) = NULL; REG_NOTES (i1) = 0; - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) propagate_for_debug (i1, last_combined_insn, i1dest, i1src, this_basic_block); SET_INSN_DELETED (i1); @@ -4458,7 +4458,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, { LOG_LINKS (i0) = NULL; REG_NOTES (i0) = 0; - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) propagate_for_debug (i0, last_combined_insn, i0dest, i0src, this_basic_block); SET_INSN_DELETED (i0); diff --git a/gcc/cse.c b/gcc/cse.c index 65cc9ae110c1..e449223cbb25 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -7049,11 +7049,11 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg) timevar_push (TV_DELETE_TRIVIALLY_DEAD); /* First count the number of times each register is used. */ - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) { counts = XCNEWVEC (int, nreg * 3); for (insn = insns; insn; insn = NEXT_INSN (insn)) - if (DEBUG_INSN_P (insn)) + if (DEBUG_BIND_INSN_P (insn)) count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg, NULL_RTX, 1); else if (INSN_P (insn)) @@ -7111,12 +7111,15 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg) if (! live_insn && dbg_cnt (delete_trivial_dead)) { if (DEBUG_INSN_P (insn)) - count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg, - NULL_RTX, -1); + { + if (DEBUG_BIND_INSN_P (insn)) + count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg, + NULL_RTX, -1); + } else { rtx set; - if (MAY_HAVE_DEBUG_INSNS + if (MAY_HAVE_DEBUG_BIND_INSNS && (set = single_set (insn)) != NULL_RTX && is_dead_reg (SET_DEST (set), counts) /* Used at least once in some DEBUG_INSN. */ @@ -7156,10 +7159,10 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg) } } - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) { for (insn = get_last_insn (); insn; insn = PREV_INSN (insn)) - if (DEBUG_INSN_P (insn)) + if (DEBUG_BIND_INSN_P (insn)) { /* If this debug insn references a dead register that wasn't replaced with an DEBUG_EXPR, reset the DEBUG_INSN. */ diff --git a/gcc/dce.c b/gcc/dce.c index 7534d2abadf6..6fd9548015ce 100644 --- a/gcc/dce.c +++ b/gcc/dce.c @@ -777,7 +777,7 @@ rest_of_handle_ud_dce (void) } worklist.release (); - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) reset_unmarked_insns_debug_uses (); /* Before any insns are deleted, we must remove the chains since diff --git a/gcc/function.c b/gcc/function.c index fe3d9c1bbf3a..2f9f83117143 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -1951,10 +1951,11 @@ instantiate_virtual_regs (void) Fortunately, they shouldn't contain virtual registers either. */ if (GET_CODE (PATTERN (insn)) == USE || GET_CODE (PATTERN (insn)) == CLOBBER - || GET_CODE (PATTERN (insn)) == ASM_INPUT) + || GET_CODE (PATTERN (insn)) == ASM_INPUT + || DEBUG_MARKER_INSN_P (insn)) continue; - else if (DEBUG_INSN_P (insn)) - instantiate_virtual_regs_in_rtx (&INSN_VAR_LOCATION (insn)); + else if (DEBUG_BIND_INSN_P (insn)) + instantiate_virtual_regs_in_rtx (INSN_VAR_LOCATION_PTR (insn)); else instantiate_virtual_regs_in_insn (insn); diff --git a/gcc/gimple-ssa-backprop.c b/gcc/gimple-ssa-backprop.c index 1daa0ceef0ac..8068c2ab1f71 100644 --- a/gcc/gimple-ssa-backprop.c +++ b/gcc/gimple-ssa-backprop.c @@ -729,7 +729,7 @@ strip_sign_op (tree rhs) void backprop::prepare_change (tree var) { - if (MAY_HAVE_DEBUG_STMTS) + if (MAY_HAVE_DEBUG_BIND_STMTS) insert_debug_temp_for_var_def (NULL, var); reset_flow_sensitive_info (var); } diff --git a/gcc/gimple.h b/gcc/gimple.h index 334def89398e..f8b0a9dee4af 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -199,13 +199,12 @@ enum gf_mask { GF_PREDICT_TAKEN = 1 << 15 }; -/* Currently, there are only two types of gimple debug stmt. Others are - envisioned, for example, to enable the generation of is_stmt notes - in line number information, to mark sequence points, etc. This - subcode is to be used to tell them apart. */ +/* This subcode tells apart different kinds of stmts that are not used + for codegen, but rather to retain debug information. */ enum gimple_debug_subcode { GIMPLE_DEBUG_BIND = 0, - GIMPLE_DEBUG_SOURCE_BIND = 1 + GIMPLE_DEBUG_SOURCE_BIND = 1, + GIMPLE_DEBUG_BEGIN_STMT = 2 }; /* Masks for selecting a pass local flag (PLF) to work on. These @@ -4759,6 +4758,28 @@ gimple_debug_source_bind_set_value (gimple *dbg, tree value) gimple_set_op (dbg, 1, value); } +/* Return true if S is a GIMPLE_DEBUG BEGIN_STMT statement. */ + +static inline bool +gimple_debug_begin_stmt_p (const gimple *s) +{ + if (is_gimple_debug (s)) + return s->subcode == GIMPLE_DEBUG_BEGIN_STMT; + + return false; +} + +/* Return true if S is a GIMPLE_DEBUG non-binding marker statement. */ + +static inline bool +gimple_debug_nonbind_marker_p (const gimple *s) +{ + if (is_gimple_debug (s)) + return s->subcode == GIMPLE_DEBUG_BEGIN_STMT; + + return false; +} + /* Return the line number for EXPR, or return -1 if we have no line number information for it. */ static inline int diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c index f5c06a95bb67..b7c0b3a6f4ff 100644 --- a/gcc/haifa-sched.c +++ b/gcc/haifa-sched.c @@ -4010,7 +4010,7 @@ schedule_insn (rtx_insn *insn) gcc_assert (sd_lists_empty_p (insn, SD_LIST_HARD_BACK)); /* Reset debug insns invalidated by moving this insn. */ - if (MAY_HAVE_DEBUG_INSNS && !DEBUG_INSN_P (insn)) + if (MAY_HAVE_DEBUG_BIND_INSNS && !DEBUG_INSN_P (insn)) for (sd_it = sd_iterator_start (insn, SD_LIST_BACK); sd_iterator_cond (&sd_it, &dep);) { @@ -4023,7 +4023,7 @@ schedule_insn (rtx_insn *insn) continue; } - gcc_assert (DEBUG_INSN_P (dbg)); + gcc_assert (DEBUG_BIND_INSN_P (dbg)); if (sched_verbose >= 6) fprintf (sched_dump, ";;\t\tresetting: debug insn %d\n", diff --git a/gcc/insn-notes.def b/gcc/insn-notes.def index f96ce18ecb6d..960487b31db1 100644 --- a/gcc/insn-notes.def +++ b/gcc/insn-notes.def @@ -68,6 +68,9 @@ INSN_NOTE (VAR_LOCATION) /* The values passed to callee. */ INSN_NOTE (CALL_ARG_LOCATION) +/* The beginning of a statement. */ +INSN_NOTE (BEGIN_STMT) + /* Record the struct for the following basic block. Uses NOTE_BASIC_BLOCK. FIXME: Redundant with the basic block pointer now included in every insn. NOTE: If there's no CFG anymore, in other words, diff --git a/gcc/ipa-param-manipulation.c b/gcc/ipa-param-manipulation.c index bedd201f6dd1..bcc736b99c0f 100644 --- a/gcc/ipa-param-manipulation.c +++ b/gcc/ipa-param-manipulation.c @@ -402,7 +402,7 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt, } vargs.quick_push (expr); } - if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_STMTS) + if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_BIND_STMTS) { unsigned int ix; tree ddecl = NULL_TREE, origin = DECL_ORIGIN (adj->base), arg; diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c index 252ea053e2aa..ff09f237f054 100644 --- a/gcc/ipa-split.c +++ b/gcc/ipa-split.c @@ -1473,7 +1473,7 @@ split_function (basic_block return_bb, struct split_point *split_point, { vec **debug_args = NULL; unsigned i = 0, len = 0; - if (MAY_HAVE_DEBUG_STMTS) + if (MAY_HAVE_DEBUG_BIND_STMTS) { debug_args = decl_debug_args_lookup (node->decl); if (debug_args) @@ -1486,11 +1486,12 @@ split_function (basic_block return_bb, struct split_point *split_point, tree ddecl; gimple *def_temp; - /* This needs to be done even without MAY_HAVE_DEBUG_STMTS, - otherwise if it didn't exist before, we'd end up with - different SSA_NAME_VERSIONs between -g and -g0. */ + /* This needs to be done even without + MAY_HAVE_DEBUG_BIND_STMTS, otherwise if it didn't exist + before, we'd end up with different SSA_NAME_VERSIONs + between -g and -g0. */ arg = get_or_create_ssa_default_def (cfun, parm); - if (!MAY_HAVE_DEBUG_STMTS || debug_args == NULL) + if (!MAY_HAVE_DEBUG_BIND_STMTS || debug_args == NULL) continue; while (i < len && (**debug_args)[i] != DECL_ORIGIN (parm)) diff --git a/gcc/ira.c b/gcc/ira.c index 8c93d3df518e..888886ea1679 100644 --- a/gcc/ira.c +++ b/gcc/ira.c @@ -3842,9 +3842,9 @@ combine_and_move_insns (void) } /* Last pass - adjust debug insns referencing cleared regs. */ - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn)) - if (DEBUG_INSN_P (insn)) + if (DEBUG_BIND_INSN_P (insn)) { rtx old_loc = INSN_VAR_LOCATION_LOC (insn); INSN_VAR_LOCATION_LOC (insn) diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c index 91bf5dddeeda..4710f8bb192d 100644 --- a/gcc/loop-unroll.c +++ b/gcc/loop-unroll.c @@ -2012,12 +2012,14 @@ apply_opt_in_copies (struct opt_info *opt_info, FOR_BB_INSNS_SAFE (bb, insn, next) { if (!INSN_P (insn) - || (DEBUG_INSN_P (insn) + || (DEBUG_BIND_INSN_P (insn) + && INSN_VAR_LOCATION_DECL (insn) && TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL)) continue; while (!INSN_P (orig_insn) - || (DEBUG_INSN_P (orig_insn) + || (DEBUG_BIND_INSN_P (orig_insn) + && INSN_VAR_LOCATION_DECL (orig_insn) && (TREE_CODE (INSN_VAR_LOCATION_DECL (orig_insn)) == LABEL_DECL))) orig_insn = NEXT_INSN (orig_insn); diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c index 83fc47626710..e17b60296d80 100644 --- a/gcc/reg-stack.c +++ b/gcc/reg-stack.c @@ -3039,7 +3039,7 @@ convert_regs_1 (basic_block block) /* Don't bother processing unless there is a stack reg mentioned or if it's a CALL_INSN. */ - if (DEBUG_INSN_P (insn)) + if (DEBUG_BIND_INSN_P (insn)) { if (starting_stack_p) debug_insns_with_starting_stack++; @@ -3079,7 +3079,7 @@ convert_regs_1 (basic_block block) for (insn = BB_HEAD (block); debug_insns_with_starting_stack; insn = NEXT_INSN (insn)) { - if (!DEBUG_INSN_P (insn)) + if (!DEBUG_BIND_INSN_P (insn)) continue; debug_insns_with_starting_stack--; diff --git a/gcc/regcprop.c b/gcc/regcprop.c index b80019b5be0d..15d8b140ce7f 100644 --- a/gcc/regcprop.c +++ b/gcc/regcprop.c @@ -752,7 +752,7 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd) next = NEXT_INSN (insn); if (!NONDEBUG_INSN_P (insn)) { - if (DEBUG_INSN_P (insn)) + if (DEBUG_BIND_INSN_P (insn)) { rtx loc = INSN_VAR_LOCATION_LOC (insn); if (!VAR_LOC_UNKNOWN_P (loc)) @@ -1296,7 +1296,7 @@ pass_cprop_hardreg::execute (function *fun) copyprop_hardreg_forward_1 (bb, all_vd + bb->index); } - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) { FOR_EACH_BB_FN (bb, fun) if (bitmap_bit_p (visited, bb->index) diff --git a/gcc/regrename.c b/gcc/regrename.c index 7fbfa3162ca6..89380a877004 100644 --- a/gcc/regrename.c +++ b/gcc/regrename.c @@ -1876,7 +1876,7 @@ build_def_use (basic_block bb) if (REG_NOTE_KIND (note) == REG_CFA_RESTORE) scan_rtx (insn, &XEXP (note, 0), NO_REGS, mark_all_read, OP_IN); } - else if (DEBUG_INSN_P (insn) + else if (DEBUG_BIND_INSN_P (insn) && !VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (insn))) { scan_rtx (insn, &INSN_VAR_LOCATION_LOC (insn), diff --git a/gcc/regstat.c b/gcc/regstat.c index 3fd26fd2fc68..fd3d3a8d98bd 100644 --- a/gcc/regstat.c +++ b/gcc/regstat.c @@ -54,7 +54,7 @@ regstat_init_n_sets_and_refs (void) regstat_n_sets_and_refs = XNEWVEC (struct regstat_n_sets_and_refs_t, max_regno); - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) for (i = 0; i < max_regno; i++) { int use_count; diff --git a/gcc/reload1.c b/gcc/reload1.c index e15bd8a2c1a9..322696a25f3e 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -1112,7 +1112,7 @@ reload (rtx_insn *first, int global) /* We don't want complex addressing modes in debug insns if simpler ones will do, so delegitimize equivalences in debug insns. */ - if (MAY_HAVE_DEBUG_INSNS && reg_renumber[i] < 0) + if (MAY_HAVE_DEBUG_BIND_INSNS && reg_renumber[i] < 0) { rtx reg = regno_reg_rtx[i]; rtx equiv = 0; @@ -1140,7 +1140,7 @@ reload (rtx_insn *first, int global) while (next && DF_REF_INSN (next) == insn) next = DF_REF_NEXT_REG (next); - if (DEBUG_INSN_P (insn)) + if (DEBUG_BIND_INSN_P (insn)) { if (!equiv) { diff --git a/gcc/rtl.h b/gcc/rtl.h index 9cc982172f53..4de167d982cf 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -815,8 +815,13 @@ struct GTY(()) rtvec_def { /* Predicate yielding nonzero iff X is an insn that is not a debug insn. */ #define NONDEBUG_INSN_P(X) (INSN_P (X) && !DEBUG_INSN_P (X)) +/* Nonzero if DEBUG_MARKER_INSN_P may possibly hold. */ +#define MAY_HAVE_DEBUG_MARKER_INSNS 0 /* debug_nonbind_markers_p */ +/* Nonzero if DEBUG_BIND_INSN_P may possibly hold. */ +#define MAY_HAVE_DEBUG_BIND_INSNS flag_var_tracking_assignments /* Nonzero if DEBUG_INSN_P may possibly hold. */ -#define MAY_HAVE_DEBUG_INSNS (flag_var_tracking_assignments) +#define MAY_HAVE_DEBUG_INSNS \ + (MAY_HAVE_DEBUG_MARKER_INSNS || MAY_HAVE_DEBUG_BIND_INSNS) /* Predicate yielding nonzero iff X is a real insn. */ #define INSN_P(X) \ @@ -1604,6 +1609,7 @@ extern const char * const reg_note_name[]; #define NOTE_EH_HANDLER(INSN) XCINT (INSN, 3, NOTE) #define NOTE_BASIC_BLOCK(INSN) XCBBDEF (INSN, 3, NOTE) #define NOTE_VAR_LOCATION(INSN) XCEXP (INSN, 3, NOTE) +#define NOTE_MARKER_LOCATION(INSN) XCUINT (INSN, 3, NOTE) #define NOTE_CFI(INSN) XCCFI (INSN, 3, NOTE) #define NOTE_LABEL_NUMBER(INSN) XCINT (INSN, 3, NOTE) @@ -1615,6 +1621,12 @@ extern const char * const reg_note_name[]; #define NOTE_INSN_BASIC_BLOCK_P(INSN) \ (NOTE_P (INSN) && NOTE_KIND (INSN) == NOTE_INSN_BASIC_BLOCK) +/* Nonzero if INSN is a debug nonbind marker note, + for which NOTE_MARKER_LOCATION can be used. */ +#define NOTE_MARKER_P(INSN) \ + (NOTE_P (INSN) && \ + (NOTE_KIND (INSN) == NOTE_INSN_BEGIN_STMT)) + /* Variable declaration and the location of a variable. */ #define PAT_VAR_LOCATION_DECL(PAT) (XCTREE ((PAT), 0, VAR_LOCATION)) #define PAT_VAR_LOCATION_LOC(PAT) (XCEXP ((PAT), 1, VAR_LOCATION)) @@ -1634,8 +1646,39 @@ extern const char * const reg_note_name[]; #define NOTE_VAR_LOCATION_STATUS(NOTE) \ PAT_VAR_LOCATION_STATUS (NOTE_VAR_LOCATION (NOTE)) +/* Evaluate to TRUE if INSN is a debug insn that denotes a variable + location/value tracking annotation. */ +#define DEBUG_BIND_INSN_P(INSN) \ + (DEBUG_INSN_P (INSN) \ + && (GET_CODE (PATTERN (INSN)) \ + == VAR_LOCATION)) +/* Evaluate to TRUE if INSN is a debug insn that denotes a program + source location marker. */ +#define DEBUG_MARKER_INSN_P(INSN) \ + (DEBUG_INSN_P (INSN) \ + && (GET_CODE (PATTERN (INSN)) \ + != VAR_LOCATION)) +/* Evaluate to the marker kind. */ +#define INSN_DEBUG_MARKER_KIND(INSN) \ + (GET_CODE (PATTERN (INSN)) == DEBUG_MARKER \ + ? (GET_MODE (PATTERN (INSN)) == VOIDmode \ + ? NOTE_INSN_BEGIN_STMT \ + : (enum insn_note)-1) \ + : (enum insn_note)-1) +/* Create patterns for debug markers. These and the above abstract + the representation, so that it's easier to get rid of the abuse of + the mode to hold the marker kind. Other marker types are + envisioned, so a single bit flag won't do; maybe separate RTL codes + wouldn't be a problem. */ +#define GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT() \ + gen_rtx_DEBUG_MARKER (VOIDmode) + /* The VAR_LOCATION rtx in a DEBUG_INSN. */ -#define INSN_VAR_LOCATION(INSN) PATTERN (INSN) +#define INSN_VAR_LOCATION(INSN) \ + (RTL_FLAG_CHECK1 ("INSN_VAR_LOCATION", PATTERN (INSN), VAR_LOCATION)) +/* A pointer to the VAR_LOCATION rtx in a DEBUG_INSN. */ +#define INSN_VAR_LOCATION_PTR(INSN) \ + (&PATTERN (INSN)) /* Accessors for a tree-expanded var location debug insn. */ #define INSN_VAR_LOCATION_DECL(INSN) \ diff --git a/gcc/sese.c b/gcc/sese.c index 89cddf0ec974..bbc72d4d7618 100644 --- a/gcc/sese.c +++ b/gcc/sese.c @@ -205,7 +205,7 @@ void sese_insert_phis_for_liveouts (sese_info_p region, basic_block bb, edge false_e, edge true_e) { - if (MAY_HAVE_DEBUG_STMTS) + if (MAY_HAVE_DEBUG_BIND_STMTS) sese_reset_debug_liveouts (region); unsigned i; diff --git a/gcc/shrink-wrap.c b/gcc/shrink-wrap.c index 0e4ff6cd46a0..472928f05f76 100644 --- a/gcc/shrink-wrap.c +++ b/gcc/shrink-wrap.c @@ -309,10 +309,10 @@ move_insn_for_shrink_wrap (basic_block bb, rtx_insn *insn, move it as far as we can. */ do { - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) { FOR_BB_INSNS_REVERSE (bb, dinsn) - if (DEBUG_INSN_P (dinsn)) + if (DEBUG_BIND_INSN_P (dinsn)) { df_ref use; FOR_EACH_INSN_USE (use, dinsn) diff --git a/gcc/ssa-iterators.h b/gcc/ssa-iterators.h index 740cbf13cb2b..201bf190cefa 100644 --- a/gcc/ssa-iterators.h +++ b/gcc/ssa-iterators.h @@ -453,7 +453,7 @@ num_imm_uses (const_tree var) const ssa_use_operand_t *ptr; unsigned int num = 0; - if (!MAY_HAVE_DEBUG_STMTS) + if (!MAY_HAVE_DEBUG_BIND_STMTS) { for (ptr = start->next; ptr != start; ptr = ptr->next) if (USE_STMT (ptr)) diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index def3f0b8d9bc..17fe2b3002fe 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -2051,7 +2051,7 @@ gimple_merge_blocks (basic_block a, basic_block b) gsi_insert_before (&dest_gsi, stmt, GSI_NEW_STMT); } /* Other user labels keep around in a form of a debug stmt. */ - else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_STMTS) + else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_BIND_STMTS) { gimple *dbg = gimple_build_debug_bind (label, integer_zero_node, diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index fc5d2c703abc..0d2a31763f1f 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -5959,7 +5959,7 @@ tree_function_versioning (tree old_decl, tree new_decl, &vars); if (init) init_stmts.safe_push (init); - if (MAY_HAVE_DEBUG_STMTS && args_to_skip) + if (MAY_HAVE_DEBUG_BIND_STMTS && args_to_skip) { if (parm_num == -1) { @@ -6106,7 +6106,7 @@ tree_function_versioning (tree old_decl, tree new_decl, } } - if (debug_args_to_skip && MAY_HAVE_DEBUG_STMTS) + if (debug_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS) { tree parm; vec **debug_args = NULL; diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c index 52db3c94bd95..1accc9f49446 100644 --- a/gcc/tree-loop-distribution.c +++ b/gcc/tree-loop-distribution.c @@ -826,7 +826,7 @@ generate_loops_for_partition (struct loop *loop, partition *partition, /* Remove stmts not in the PARTITION bitmap. */ bbs = get_loop_body_in_dom_order (loop); - if (MAY_HAVE_DEBUG_STMTS) + if (MAY_HAVE_DEBUG_BIND_STMTS) for (i = 0; i < loop->num_nodes; i++) { basic_block bb = bbs[i]; diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index db490b20c3ed..7a1a93ab2387 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -2478,7 +2478,7 @@ analyze_access_subtree (struct access *root, struct access *parent, gcc_checking_assert (!root->grp_scalar_read && !root->grp_assignment_read); sth_created = true; - if (MAY_HAVE_DEBUG_STMTS) + if (MAY_HAVE_DEBUG_BIND_STMTS) { root->grp_to_be_debug_replaced = 1; root->replacement_decl = create_access_replacement (root); diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index a5f0edf7893b..4a5cd87e25e7 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -1081,7 +1081,7 @@ remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb) /* If this is a store into a variable that is being optimized away, add a debug bind stmt if possible. */ - if (MAY_HAVE_DEBUG_STMTS + if (MAY_HAVE_DEBUG_BIND_STMTS && gimple_assign_single_p (stmt) && is_gimple_val (gimple_assign_rhs1 (stmt))) { diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c index 65794b2b777e..350f94dfc33f 100644 --- a/gcc/tree-ssa-loop-ivopts.c +++ b/gcc/tree-ssa-loop-ivopts.c @@ -7154,7 +7154,7 @@ remove_unused_ivs (struct ivopts_data *data) tree def = info->iv->ssa_name; - if (MAY_HAVE_DEBUG_STMTS && SSA_NAME_DEF_STMT (def)) + if (MAY_HAVE_DEBUG_BIND_STMTS && SSA_NAME_DEF_STMT (def)) { imm_use_iterator imm_iter; use_operand_p use_p; diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c index 5e8cac69d5d5..45ca43ffac47 100644 --- a/gcc/tree-ssa-reassoc.c +++ b/gcc/tree-ssa-reassoc.c @@ -232,7 +232,7 @@ reassoc_remove_stmt (gimple_stmt_iterator *gsi) { gimple *stmt = gsi_stmt (*gsi); - if (!MAY_HAVE_DEBUG_STMTS || gimple_code (stmt) == GIMPLE_PHI) + if (!MAY_HAVE_DEBUG_BIND_STMTS || gimple_code (stmt) == GIMPLE_PHI) return gsi_remove (gsi, true); gimple_stmt_iterator prev = *gsi; diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c index 97e90233d580..6db33c566c86 100644 --- a/gcc/tree-ssa-tail-merge.c +++ b/gcc/tree-ssa-tail-merge.c @@ -1800,7 +1800,7 @@ tail_merge_optimize (unsigned int todo) if (nr_bbs_removed_total > 0) { - if (MAY_HAVE_DEBUG_STMTS) + if (MAY_HAVE_DEBUG_BIND_STMTS) { calculate_dominance_info (CDI_DOMINATORS); update_debug_stmts (); diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c index 536c4717b725..70675e4a3fcd 100644 --- a/gcc/tree-ssa-threadedge.c +++ b/gcc/tree-ssa-threadedge.c @@ -692,7 +692,7 @@ simplify_control_stmt_condition_1 (edge e, void propagate_threaded_block_debug_into (basic_block dest, basic_block src) { - if (!MAY_HAVE_DEBUG_STMTS) + if (!MAY_HAVE_DEBUG_BIND_STMTS) return; if (!single_pred_p (dest)) diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index 8b6da9645ce0..151f544babad 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -220,7 +220,7 @@ flush_pending_stmts (edge e) void gimple_replace_ssa_lhs (gimple *stmt, tree nlhs) { - if (MAY_HAVE_DEBUG_STMTS) + if (MAY_HAVE_DEBUG_BIND_STMTS) { tree lhs = gimple_get_lhs (stmt); @@ -242,7 +242,7 @@ gimple_replace_ssa_lhs (gimple *stmt, tree nlhs) tree target_for_debug_bind (tree var) { - if (!MAY_HAVE_DEBUG_STMTS) + if (!MAY_HAVE_DEBUG_BIND_STMTS) return NULL_TREE; if (TREE_CODE (var) == SSA_NAME) @@ -307,7 +307,7 @@ insert_debug_temp_for_var_def (gimple_stmt_iterator *gsi, tree var) int usecount = 0; tree value = NULL; - if (!MAY_HAVE_DEBUG_STMTS) + if (!MAY_HAVE_DEBUG_BIND_STMTS) return; /* If this name has already been registered for replacement, do nothing @@ -495,7 +495,7 @@ insert_debug_temps_for_defs (gimple_stmt_iterator *gsi) ssa_op_iter op_iter; def_operand_p def_p; - if (!MAY_HAVE_DEBUG_STMTS) + if (!MAY_HAVE_DEBUG_BIND_STMTS) return; stmt = gsi_stmt (*gsi); @@ -521,7 +521,7 @@ reset_debug_uses (gimple *stmt) imm_use_iterator imm_iter; gimple *use_stmt; - if (!MAY_HAVE_DEBUG_STMTS) + if (!MAY_HAVE_DEBUG_BIND_STMTS) return; FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt, op_iter, SSA_OP_DEF) diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c index 6d344ad53096..d00d64852c2e 100644 --- a/gcc/tree-ssanames.c +++ b/gcc/tree-ssanames.c @@ -562,7 +562,7 @@ release_ssa_name_fn (struct function *fn, tree var) int saved_ssa_name_version = SSA_NAME_VERSION (var); use_operand_p imm = &(SSA_NAME_IMM_USE_NODE (var)); - if (MAY_HAVE_DEBUG_STMTS) + if (MAY_HAVE_DEBUG_BIND_STMTS) insert_debug_temp_for_var_def (NULL, var); if (flag_checking) diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c index be34310fd03f..9ba4843be4a9 100644 --- a/gcc/tree-vect-loop-manip.c +++ b/gcc/tree-vect-loop-manip.c @@ -192,7 +192,7 @@ adjust_debug_stmts_now (adjust_info *ai) static void adjust_vec_debug_stmts (void) { - if (!MAY_HAVE_DEBUG_STMTS) + if (!MAY_HAVE_DEBUG_BIND_STMTS) return; gcc_assert (adjust_vec.exists ()); @@ -214,7 +214,7 @@ adjust_debug_stmts (tree from, tree to, basic_block bb) { adjust_info ai; - if (MAY_HAVE_DEBUG_STMTS + if (MAY_HAVE_DEBUG_BIND_STMTS && TREE_CODE (from) == SSA_NAME && ! SSA_NAME_IS_DEFAULT_DEF (from) && ! virtual_operand_p (from)) @@ -242,7 +242,7 @@ adjust_phi_and_debug_stmts (gimple *update_phi, edge e, tree new_def) SET_PHI_ARG_DEF (update_phi, e->dest_idx, new_def); - if (MAY_HAVE_DEBUG_STMTS) + if (MAY_HAVE_DEBUG_BIND_STMTS) adjust_debug_stmts (orig_def, PHI_RESULT (update_phi), gimple_bb (update_phi)); } @@ -1683,7 +1683,7 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters, tree nitersm1, create_lcssa_for_virtual_phi (loop); update_ssa (TODO_update_ssa_only_virtuals); - if (MAY_HAVE_DEBUG_STMTS) + if (MAY_HAVE_DEBUG_BIND_STMTS) { gcc_assert (!adjust_vec.exists ()); adjust_vec.create (32); diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index afb36eab1f7e..d66b0219d922 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -7380,7 +7380,7 @@ vect_transform_loop (loop_vec_info loop_vinfo) if (!stmt_info) continue; - if (MAY_HAVE_DEBUG_STMTS && !STMT_VINFO_LIVE_P (stmt_info)) + if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info)) vect_loop_kill_debug_uses (loop, phi); if (!STMT_VINFO_RELEVANT_P (stmt_info) @@ -7443,7 +7443,7 @@ vect_transform_loop (loop_vec_info loop_vinfo) continue; } - if (MAY_HAVE_DEBUG_STMTS && !STMT_VINFO_LIVE_P (stmt_info)) + if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info)) vect_loop_kill_debug_uses (loop, stmt); if (!STMT_VINFO_RELEVANT_P (stmt_info) diff --git a/gcc/tree.h b/gcc/tree.h index 277aa919780e..efc7947f4ab7 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1105,8 +1105,14 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, #define VL_EXP_OPERAND_LENGTH(NODE) \ ((int)TREE_INT_CST_LOW (VL_EXP_CHECK (NODE)->exp.operands[0])) +/* Nonzero if gimple_debug_nonbind_marker_p() may possibly hold. */ +#define MAY_HAVE_DEBUG_MARKER_STMTS 0 /* debug_nonbind_markers_p */ +/* Nonzero if gimple_debug_bind_p() (and thus + gimple_debug_source_bind_p()) may possibly hold. */ +#define MAY_HAVE_DEBUG_BIND_STMTS flag_var_tracking_assignments /* Nonzero if is_gimple_debug() may possibly hold. */ -#define MAY_HAVE_DEBUG_STMTS (flag_var_tracking_assignments) +#define MAY_HAVE_DEBUG_STMTS \ + (MAY_HAVE_DEBUG_MARKER_STMTS || MAY_HAVE_DEBUG_BIND_STMTS) /* In a LOOP_EXPR node. */ #define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0) diff --git a/gcc/valtrack.c b/gcc/valtrack.c index 38af3f0ce51d..8d864c93e6a3 100644 --- a/gcc/valtrack.c +++ b/gcc/valtrack.c @@ -211,7 +211,7 @@ propagate_for_debug (rtx_insn *insn, rtx_insn *last, rtx dest, rtx src, { insn = next; next = NEXT_INSN (insn); - if (DEBUG_INSN_P (insn)) + if (DEBUG_BIND_INSN_P (insn)) { loc = simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn), dest, propagate_for_debug_subst, &p); diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index 16327bd43f33..33bcca7d6f52 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -1125,7 +1125,7 @@ adjust_mems (rtx loc, const_rtx old_rtx, void *data) if (tem == NULL_RTX) tem = gen_rtx_raw_SUBREG (GET_MODE (loc), addr, SUBREG_BYTE (loc)); finish_subreg: - if (MAY_HAVE_DEBUG_INSNS + if (MAY_HAVE_DEBUG_BIND_INSNS && GET_CODE (tem) == SUBREG && (GET_CODE (SUBREG_REG (tem)) == PLUS || GET_CODE (SUBREG_REG (tem)) == MINUS @@ -1337,7 +1337,7 @@ dv_onepart_p (decl_or_value dv) { tree decl; - if (!MAY_HAVE_DEBUG_INSNS) + if (!MAY_HAVE_DEBUG_BIND_INSNS) return NOT_ONEPART; if (dv_is_value_p (dv)) @@ -4861,7 +4861,7 @@ dataflow_set_clear_at_call (dataflow_set *set, rtx_insn *call_insn) EXECUTE_IF_SET_IN_HARD_REG_SET (invalidated_regs, 0, r, hrsi) var_regno_delete (set, r); - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) { set->traversed_vars = set->vars; shared_hash_htab (set->vars) @@ -5535,7 +5535,7 @@ use_type (rtx loc, struct count_use_info *cui, machine_mode *modep) variable names such as VALUEs (never happens) or DEBUG_EXPRs (only happens in the presence of debug insns). */ - && (!MAY_HAVE_DEBUG_INSNS + && (!MAY_HAVE_DEBUG_BIND_INSNS || !rtx_debug_expr_p (XEXP (loc, 0)))) return MO_USE; else @@ -6700,7 +6700,7 @@ compute_bb_dataflow (basic_block bb) dataflow_set_copy (&old_out, out); dataflow_set_copy (out, in); - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) local_get_addr_cache = new hash_map; FOR_EACH_VEC_ELT (VTI (bb)->mos, i, mo) @@ -6982,7 +6982,7 @@ compute_bb_dataflow (basic_block bb) } } - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) { delete local_get_addr_cache; local_get_addr_cache = NULL; @@ -7069,7 +7069,7 @@ vt_find_locations (void) else oldinsz = oldoutsz = 0; - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) { dataflow_set *in = &VTI (bb)->in, *first_out = NULL; bool first = true, adjust = false; @@ -7130,7 +7130,7 @@ vt_find_locations (void) if (htabmax && htabsz > htabmax) { - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) inform (DECL_SOURCE_LOCATION (cfun->decl), "variable tracking size limit exceeded with " "-fvar-tracking-assignments, retrying without"); @@ -7190,7 +7190,7 @@ vt_find_locations (void) } } - if (success && MAY_HAVE_DEBUG_INSNS) + if (success && MAY_HAVE_DEBUG_BIND_INSNS) FOR_EACH_BB_FN (bb, cfun) gcc_assert (VTI (bb)->flooded); @@ -8579,7 +8579,7 @@ vt_expand_loc (rtx loc, variable_table_type *vars) struct expand_loc_callback_data data; rtx result; - if (!MAY_HAVE_DEBUG_INSNS) + if (!MAY_HAVE_DEBUG_BIND_INSNS) return loc; INIT_ELCD (data, vars); @@ -9014,7 +9014,7 @@ emit_notes_for_changes (rtx_insn *insn, enum emit_note_where where, if (!changed_variables->elements ()) return; - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) process_changed_values (htab); data.insn = insn; @@ -9498,10 +9498,8 @@ vt_emit_notes (void) delete_variable_part). */ emit_notes = true; - if (MAY_HAVE_DEBUG_INSNS) - { - dropped_values = new variable_table_type (cselib_get_next_uid () * 2); - } + if (MAY_HAVE_DEBUG_BIND_INSNS) + dropped_values = new variable_table_type (cselib_get_next_uid () * 2); dataflow_set_init (&cur); @@ -9511,13 +9509,13 @@ vt_emit_notes (void) subsequent basic blocks. */ emit_notes_for_differences (BB_HEAD (bb), &cur, &VTI (bb)->in); - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) local_get_addr_cache = new hash_map; /* Emit the notes for the changes in the basic block itself. */ emit_notes_in_bb (bb, &cur); - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) delete local_get_addr_cache; local_get_addr_cache = NULL; @@ -9533,7 +9531,7 @@ vt_emit_notes (void) dataflow_set_destroy (&cur); - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) delete dropped_values; dropped_values = NULL; @@ -9893,7 +9891,7 @@ vt_init_cfa_base (void) cfa_base_rtx = NULL_RTX; return; } - if (!MAY_HAVE_DEBUG_INSNS) + if (!MAY_HAVE_DEBUG_BIND_INSNS) return; /* Tell alias analysis that cfa_base_rtx should share @@ -9935,7 +9933,7 @@ vt_initialize (void) VTI (bb)->permp = NULL; } - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) { cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS); scratch_regs = BITMAP_ALLOC (NULL); @@ -9948,7 +9946,7 @@ vt_initialize (void) global_get_addr_cache = NULL; } - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) { rtx reg, expr; int ofst; @@ -10078,7 +10076,7 @@ vt_initialize (void) HOST_WIDE_INT pre, post = 0; basic_block first_bb, last_bb; - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) { cselib_record_sets_hook = add_with_sets; if (dump_file && (dump_flags & TDF_DETAILS)) @@ -10129,7 +10127,7 @@ vt_initialize (void) cselib_hook_called = false; adjust_insn (bb, insn); - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) { if (CALL_P (insn)) prepare_call_arguments (bb, insn); @@ -10164,7 +10162,7 @@ vt_initialize (void) vt_init_cfa_base (); hard_frame_pointer_adjustment = fp_cfa_offset; /* Disassociate sp from fp now. */ - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) { cselib_val *v; cselib_invalidate_rtx (stack_pointer_rtx); @@ -10184,7 +10182,7 @@ vt_initialize (void) bb = last_bb; - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) { cselib_preserve_only_values (); cselib_reset_table (cselib_get_next_uid ()); @@ -10283,7 +10281,7 @@ vt_finalize (void) location_chain_pool.release (); shared_hash_pool.release (); - if (MAY_HAVE_DEBUG_INSNS) + if (MAY_HAVE_DEBUG_BIND_INSNS) { if (global_get_addr_cache) delete global_get_addr_cache; From patchwork Fri Nov 10 02:34:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Oliva X-Patchwork-Id: 836583 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-466475-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="TznfstCs"; dkim-atps=neutral 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 3yY41R4fMSz9t2M for ; Fri, 10 Nov 2017 13:36:58 +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:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=GPz5Jd1tSHF8LreaT+bZ+pcCs1iOaMa7W0QvbaYwNQRA4dHGdPpE8 vF9NMVjcpLB9N1Zu823b9nT0QandhFwNfwdgdYkoVrXJbwvl/50/gYA1eK/Mxkk4 PhXKOoUlNduB2RkpSmzH2ecnnE1xBTaEUcxtGWtXQawoYLvOrJke5Y= 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:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=4O93LHbKd3PBErYkn7ApuHY2c3U=; b=TznfstCszABsvXOMSjhU QR1YuX1vSWsLML1dkXihB1d8Q84DX0YPnX7FdOAiBwbkFCy3R6hFlLyWQhw8sb/j jW4UDYsjIQoHzC7mgVVvkEVyJWRbf5zeiAp4vqdxoObPBKM4PZKXatQJi75t0q5w AIjhnY2XYKt+mveEjUyeQlw= Received: (qmail 97514 invoked by alias); 10 Nov 2017 02:36:26 -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 97381 invoked by uid 89); 10 Nov 2017 02:36:24 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=slim, collapse, numerous 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 ESMTP; Fri, 10 Nov 2017 02:36:16 +0000 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 36028356C4; Fri, 10 Nov 2017 02:36:15 +0000 (UTC) Received: from freie.home (ovpn04.gateway.prod.ext.phx2.redhat.com [10.5.9.4]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 178785D9C8; Fri, 10 Nov 2017 02:36:13 +0000 (UTC) Received: from frit.home (frit.home [172.31.160.7]) by freie.home (8.15.2/8.15.2) with ESMTP id vAA2ZEBB003201; Fri, 10 Nov 2017 00:35:23 -0200 From: Alexandre Oliva To: Richard Biener , Jeff Law , Jason Merrill Cc: GCC Patches , Alexandre Oliva Subject: [SFN+LVU+IEPM v4 3/9] [SFN] not-quite-boilerplate changes in preparation to introduce nonbind markers Date: Fri, 10 Nov 2017 00:34:42 -0200 Message-Id: <20171110023448.28164-3-aoliva@redhat.com> In-Reply-To: References: This patch adjusts numerous parts of the compiler that would malfunction should they find debug markers at points where they may be introduced. The changes purport to allow the compiler to pass bootstrap-debug-lean (-fcompare-debug in stage3) at various optimization levels, as well as bootstrap-debug-lib (-fcompare-debug for target libraries), even after the compiler is changed so that debug markers are introduced in code streams at spots where earlier debug stmts, insns and notes wouldn't normally appear. This patch depends on an earlier SFN boilerplate patch, and on another SFN patch that introduces new RTL insn-walking functions. for gcc/ChangeLog * cfgcleanup.c (delete_unreachable_blocks): Use alternate block removal order if MAY_HAVE_DEBUG_BIND_INSNS. * cfgexpand.c (label_rtx_for_bb): Skip debug insns. * cfgrtl.c (try_redirect_by_replacing_jump): Skip debug insns. (rtl_tidy_fallthru_edge): Likewise. (rtl_verify_fallthru): Likewise. (rtl_verify_bb_layout): Likewise. (skip_insns_after_block): Likewise. (duplicate_insn_chain): Use DEBUG_BIND_INSN_P. * dwarf2out.c: Include print-rtl.h. (dwarf2out_next_real_insn): New. (dwarf2out_var_location): Call it. Disregard begin stmt markers. Dump debug binds in asm comments. * gimple-iterator.c (gimple_find_edge_insert_loc): Skip debug stmts. * gimple-iterator.h (gsi_start_bb_nondebug): Remove; adjust callers to use gsi_start_nondebug_bb instead. (gsi_after_labels): Skip gimple debug stmts. (gsi_start_nondebug): New. * gimple-low.c (gimple_seq_may_fallthru): Take last nondebug stmt. * gimple.h (gimple_seq_last_nondebug_stmt): New. * gimplify.c (last_stmt_in_scope): Skip debug stmts. (collect_fallthrough_labels): Likewise. (should_warn_for_implicit_fallthrough): Likewise. (warn_implicit_fallthrough_r): Likewise. (expand_FALLTHROUGH_r): Likewise. * graphite-isl-ast-to-gimple.c (gsi_insert_earliest): Adjust. (graphite_copy_stmts_from_block): Skip nonbind markers. * haifa-sched.c (sched_extend_bb): Skip debug insns. * ipa-icf-gimple.c (func_checker::compare_bb): Adjust. * jump.c (clean_barriers): Skip debug insns. * omp-expand.c (expand_parallel_call): Skip debug insns. (expand_cilk_for_call): Likewise. (expand_task_call): Likewise. (remove_exit_barrier): Likewise. (expand_omp_taskreg): Likewise. (expand_omp_for_init_counts): Likewise. (expand_omp_for_generic): Likewise. (expand_omp_for_static_nochunk): Likewise. (expand_omp_for_static_chunk): Likewise. (expand_cilk_for): Likewise. (expand_omp_simd): Likewise. (expand_omp_taskloop_for_outer): Likewise. (expand_omp_taskloop_for_inner): Likewise. (expand_oacc_for): Likewise. (expand_omp_sections): Likewise. (expand_omp_single): Likewise. (expand_omp_synch): Likewise. (expand_omp_atomic_load): Likewise. (expand_omp_atomic_store): Likewise. (expand_omp_atomic_fetch_op): Likewise. (expand_omp_atomic_pipeline): Likewise. (expand_omp_atomic_mutex): Likewise. (expand_omp_target): Likewise. (grid_expand_omp_for_loop): Likewise. (grid_expand_target_grid_body): Likewise. (build_omp_regions_1): Likewise. * omp-low.c (check_combined_parallel): Skip debug stmts. * postreload.c (fixup_debug_insns): Skip nonbind debug insns. * regcprop.c (find_oldest_value_reg): Ensure REGNO is not a pseudo. * sese.c (sese_trivially_empty_bb_p): Call is_gimple_debug in test. * tree-cfg.c (make_blobs_1): Skip debug stmts. (make_edges): Likewise. (cleanup_dead_labels): Likewise. (gimple_can_merge_blocks_p): Likewise. (stmt_starts_bb_p): Likewise. (gimple_block_label): Likewise. (gimple_redirect_edge_and_branch): Likewise. * tree-cfgcleanup.c (remove_forwarder_block): Rearrange skipping of debug stmts. (execute_cleanup_cfg_post_optimizing): Dump enumerated decls with TDF_SLIM. * tree-pretty-print (print_declaration): Omit initializer in slim dumps. * tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Mark begin stmt markers. (eliminate_unnecessary_stmts): Stabilize block removal order. * tree-ssa-tail-merge.c (find_duplicate): Skip debug stmts. * var-tracking.c (get_first_insn): New. (vt_emit_notes): Call it. (vt_initialize): Walk any insns before the first BB. (delete_debug_insns): Likewise. --- gcc/cfgbuild.c | 1 + gcc/cfgcleanup.c | 12 +-- gcc/cfgexpand.c | 24 +++++- gcc/cfgrtl.c | 18 +++-- gcc/dwarf2out.c | 38 ++++++++- gcc/gimple-iterator.c | 24 +++++- gcc/gimple-iterator.h | 46 ++++++----- gcc/gimple-low.c | 2 +- gcc/gimple.h | 16 ++++ gcc/gimplify.c | 23 +++--- gcc/graphite-isl-ast-to-gimple.c | 7 +- gcc/haifa-sched.c | 2 +- gcc/ipa-icf-gimple.c | 4 +- gcc/jump.c | 2 +- gcc/omp-expand.c | 161 ++++++++++++++++++++------------------- gcc/omp-low.c | 2 + gcc/postreload.c | 2 +- gcc/regcprop.c | 2 + gcc/sese.c | 2 +- gcc/tree-cfg.c | 52 +++++++++++-- gcc/tree-cfgcleanup.c | 31 +++----- gcc/tree-pretty-print.c | 5 +- gcc/tree-ssa-dce.c | 6 +- gcc/tree-ssa-tail-merge.c | 4 +- gcc/var-tracking.c | 54 ++++++++++++- 25 files changed, 366 insertions(+), 174 deletions(-) diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c index 77a221de2119..8fa15fec45e4 100644 --- a/gcc/cfgbuild.c +++ b/gcc/cfgbuild.c @@ -475,6 +475,7 @@ find_bb_boundaries (basic_block bb) if (debug_insn && code != CODE_LABEL && code != BARRIER) prev = PREV_INSN (debug_insn); fallthru = split_block (bb, prev); + if (flow_transfer_insn) { BB_END (bb) = flow_transfer_insn; diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c index 4734d3eae17e..754e52fe799a 100644 --- a/gcc/cfgcleanup.c +++ b/gcc/cfgcleanup.c @@ -3037,13 +3037,13 @@ delete_unreachable_blocks (void) find_unreachable_blocks (); - /* When we're in GIMPLE mode and there may be debug insns, we should - delete blocks in reverse dominator order, so as to get a chance - to substitute all released DEFs into debug stmts. If we don't - have dominators information, walking blocks backward gets us a - better chance of retaining most debug information than + /* When we're in GIMPLE mode and there may be debug bind insns, we + should delete blocks in reverse dominator order, so as to get a + chance to substitute all released DEFs into debug bind stmts. If + we don't have dominators information, walking blocks backward + gets us a better chance of retaining most debug information than otherwise. */ - if (MAY_HAVE_DEBUG_INSNS && current_ir_type () == IR_GIMPLE + if (MAY_HAVE_DEBUG_BIND_INSNS && current_ir_type () == IR_GIMPLE && dom_info_available_p (CDI_DOMINATORS)) { for (b = EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb; diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 22a9eb45b45e..6f64897d0688 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -2327,6 +2327,9 @@ label_rtx_for_bb (basic_block bb ATTRIBUTE_UNUSED) { glabel *lab_stmt; + if (is_gimple_debug (gsi_stmt (gsi))) + continue; + lab_stmt = dyn_cast (gsi_stmt (gsi)); if (!lab_stmt) break; @@ -5456,7 +5459,7 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls) gimple_stmt_iterator gsi; gimple_seq stmts; gimple *stmt = NULL; - rtx_note *note; + rtx_note *note = NULL; rtx_insn *last; edge e; edge_iterator ei; @@ -5497,18 +5500,26 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls) } } - gsi = gsi_start (stmts); + gsi = gsi_start_nondebug (stmts); if (!gsi_end_p (gsi)) { stmt = gsi_stmt (gsi); if (gimple_code (stmt) != GIMPLE_LABEL) stmt = NULL; } + gsi = gsi_start (stmts); + gimple *label_stmt = stmt; rtx_code_label **elt = lab_rtx_for_bb->get (bb); - if (stmt || elt) + if (stmt) + /* We'll get to it in the loop below, and get back to + emit_label_and_note then. */ + ; + else if (stmt || elt) { + emit_label_and_note: + gcc_checking_assert (!note); last = get_last_insn (); if (stmt) @@ -5523,6 +5534,7 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls) BB_HEAD (bb) = NEXT_INSN (last); if (NOTE_P (BB_HEAD (bb))) BB_HEAD (bb) = NEXT_INSN (BB_HEAD (bb)); + gcc_assert (LABEL_P (BB_HEAD (bb))); note = emit_note_after (NOTE_INSN_BASIC_BLOCK, BB_HEAD (bb)); maybe_dump_rtl_for_gimple_stmt (stmt, last); @@ -5530,7 +5542,8 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls) else BB_HEAD (bb) = note = emit_note (NOTE_INSN_BASIC_BLOCK); - NOTE_BASIC_BLOCK (note) = bb; + if (note) + NOTE_BASIC_BLOCK (note) = bb; for (; !gsi_end_p (gsi); gsi_next (&gsi)) { @@ -5538,6 +5551,9 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls) stmt = gsi_stmt (gsi); + if (stmt == label_stmt) + goto emit_label_and_note; + /* If this statement is a non-debug one, and we generate debug insns, then this one might be the last real use of a TERed SSA_NAME, but where there are still some debug uses further diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c index f788334ffb57..0968e68ba7ec 100644 --- a/gcc/cfgrtl.c +++ b/gcc/cfgrtl.c @@ -1117,7 +1117,7 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout) if (tablejump_p (insn, &label, &table)) delete_insn_chain (label, table, false); - barrier = next_nonnote_insn (BB_END (src)); + barrier = next_nonnote_nondebug_insn (BB_END (src)); if (!barrier || !BARRIER_P (barrier)) emit_barrier_after (BB_END (src)); else @@ -1746,7 +1746,7 @@ rtl_tidy_fallthru_edge (edge e) the head of block C and assert that we really do fall through. */ for (q = NEXT_INSN (BB_END (b)); q != BB_HEAD (c); q = NEXT_INSN (q)) - if (INSN_P (q)) + if (NONDEBUG_INSN_P (q)) return; /* Remove what will soon cease being the jump insn from the source block. @@ -2901,7 +2901,7 @@ rtl_verify_fallthru (void) else for (insn = NEXT_INSN (BB_END (e->src)); insn != BB_HEAD (e->dest); insn = NEXT_INSN (insn)) - if (BARRIER_P (insn) || INSN_P (insn)) + if (BARRIER_P (insn) || NONDEBUG_INSN_P (insn)) { error ("verify_flow_info: Incorrect fallthru %i->%i", e->src->index, e->dest->index); @@ -2923,7 +2923,7 @@ rtl_verify_bb_layout (void) { basic_block bb; int err = 0; - rtx_insn *x; + rtx_insn *x, *y; int num_bb_notes; rtx_insn * const rtx_first = get_insns (); basic_block last_bb_seen = ENTRY_BLOCK_PTR_FOR_FN (cfun), curr_bb = NULL; @@ -2950,6 +2950,7 @@ rtl_verify_bb_layout (void) { case BARRIER: case NOTE: + case DEBUG_INSN: break; case CODE_LABEL: @@ -2968,7 +2969,8 @@ rtl_verify_bb_layout (void) if (JUMP_P (x) && returnjump_p (x) && ! condjump_p (x) - && ! (next_nonnote_insn (x) && BARRIER_P (next_nonnote_insn (x)))) + && ! ((y = next_nonnote_nondebug_insn (x)) + && BARRIER_P (y))) fatal_insn ("return not followed by barrier", x); if (curr_bb && x == BB_END (curr_bb)) @@ -3385,6 +3387,9 @@ skip_insns_after_block (basic_block bb) last_insn = insn; continue; + case DEBUG_INSN: + continue; + case NOTE: switch (NOTE_KIND (insn)) { @@ -4137,7 +4142,8 @@ duplicate_insn_chain (rtx_insn *from, rtx_insn *to) { case DEBUG_INSN: /* Don't duplicate label debug insns. */ - if (TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL) + if (DEBUG_BIND_INSN_P (insn) + && TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL) break; /* FALLTHRU */ case INSN: diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index b8f4e4888f1b..4f808b95519c 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -83,6 +83,7 @@ along with GCC; see the file COPYING3. If not see #include "toplev.h" #include "md5.h" #include "tree-pretty-print.h" +#include "print-rtl.h" #include "debug.h" #include "common/common-target.h" #include "langhooks.h" @@ -26189,6 +26190,22 @@ static bool maybe_at_text_label_p = true; /* One above highest N where .LVLN label might be equal to .Ltext0 label. */ static unsigned int first_loclabel_num_not_at_text_label; +/* Look ahead for a real insn, or for a begin stmt marker. */ + +static rtx_insn * +dwarf2out_next_real_insn (rtx_insn *loc_note) +{ + rtx_insn *next_real = NEXT_INSN (loc_note); + + while (next_real) + if (INSN_P (next_real)) + break; + else + next_real = NEXT_INSN (next_real); + + return next_real; +} + /* Called by the final INSN scan whenever we see a var location. We use it to drop labels in the right places, and throw the location in our lookup table. */ @@ -26237,7 +26254,7 @@ dwarf2out_var_location (rtx_insn *loc_note) loc_note = NULL; var_loc_p = false; - next_real = next_real_insn (call_insn); + next_real = dwarf2out_next_real_insn (call_insn); next_note = NULL; cached_next_real_insn = NULL; goto create_label; @@ -26267,11 +26284,12 @@ dwarf2out_var_location (rtx_insn *loc_note) || next_note->deleted () || ! NOTE_P (next_note) || (NOTE_KIND (next_note) != NOTE_INSN_VAR_LOCATION + && NOTE_KIND (next_note) != NOTE_INSN_BEGIN_STMT && NOTE_KIND (next_note) != NOTE_INSN_CALL_ARG_LOCATION)) next_note = NULL; if (! next_real) - next_real = next_real_insn (loc_note); + next_real = dwarf2out_next_real_insn (loc_note); if (next_note) { @@ -26430,6 +26448,22 @@ create_label: newloc->label = last_postcall_label; } + if (var_loc_p && flag_debug_asm) + { + const char *name = NULL, *sep = " => ", *patstr = NULL; + if (decl && DECL_NAME (decl)) + name = IDENTIFIER_POINTER (DECL_NAME (decl)); + if (NOTE_VAR_LOCATION_LOC (loc_note)) + patstr = str_pattern_slim (NOTE_VAR_LOCATION_LOC (loc_note)); + else + { + sep = " "; + patstr = "RESET"; + } + fprintf (asm_out_file, "\t%s DEBUG %s%s%s\n", ASM_COMMENT_START, + name, sep, patstr); + } + last_var_location_insn = next_real; last_in_cold_section_p = in_cold_section_p; } diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c index 3b74cc540f66..fb75f993e9a1 100644 --- a/gcc/gimple-iterator.c +++ b/gcc/gimple-iterator.c @@ -744,9 +744,13 @@ gimple_find_edge_insert_loc (edge e, gimple_stmt_iterator *gsi, if (gsi_end_p (*gsi)) return true; - /* Make sure we insert after any leading labels. */ + /* Make sure we insert after any leading labels. We have to + skip debug stmts before or among them, though. We didn't + have to skip debug stmts after the last label, but it + shouldn't hurt if we do. */ tmp = gsi_stmt (*gsi); - while (gimple_code (tmp) == GIMPLE_LABEL) + while (gimple_code (tmp) == GIMPLE_LABEL + || is_gimple_debug (tmp)) { gsi_next (gsi); if (gsi_end_p (*gsi)) @@ -776,7 +780,21 @@ gimple_find_edge_insert_loc (edge e, gimple_stmt_iterator *gsi, return true; tmp = gsi_stmt (*gsi); - if (!stmt_ends_bb_p (tmp)) + if (is_gimple_debug (tmp)) + { + gimple_stmt_iterator si = *gsi; + gsi_prev_nondebug (&si); + if (!gsi_end_p (si)) + tmp = gsi_stmt (si); + /* If we don't have a BB-ending nondebug stmt, we want to + insert after the trailing debug stmts. Otherwise, we may + insert before the BB-ending nondebug stmt, or split the + edge. */ + if (!stmt_ends_bb_p (tmp)) + return true; + *gsi = si; + } + else if (!stmt_ends_bb_p (tmp)) return true; switch (gimple_code (tmp)) diff --git a/gcc/gimple-iterator.h b/gcc/gimple-iterator.h index 70f18beceffc..167edc18db5b 100644 --- a/gcc/gimple-iterator.h +++ b/gcc/gimple-iterator.h @@ -212,29 +212,28 @@ gsi_stmt (gimple_stmt_iterator i) return i.ptr; } -/* Return a new iterator pointing to the first non-debug statement - in basic block BB. */ - -static inline gimple_stmt_iterator -gsi_start_bb_nondebug (basic_block bb) -{ - gimple_stmt_iterator gsi = gsi_start_bb (bb); - while (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi))) - gsi_next (&gsi); - - return gsi; -} - -/* Return a block statement iterator that points to the first non-label - statement in block BB. */ +/* Return a block statement iterator that points to the first + non-label statement in block BB. Skip debug stmts only if they + precede labels. */ static inline gimple_stmt_iterator gsi_after_labels (basic_block bb) { gimple_stmt_iterator gsi = gsi_start_bb (bb); - while (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL) - gsi_next (&gsi); + for (gimple_stmt_iterator gskip = gsi; + !gsi_end_p (gskip); ) + { + if (is_gimple_debug (gsi_stmt (gskip))) + gsi_next (&gskip); + else if (gimple_code (gsi_stmt (gskip)) == GIMPLE_LABEL) + { + gsi_next (&gskip); + gsi = gskip; + } + else + break; + } return gsi; } @@ -264,6 +263,19 @@ gsi_prev_nondebug (gimple_stmt_iterator *i) } /* Return a new iterator pointing to the first non-debug statement in + SEQ. */ + +static inline gimple_stmt_iterator +gsi_start_nondebug (gimple_seq seq) +{ + gimple_stmt_iterator gsi = gsi_start (seq); + if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi))) + gsi_next_nondebug (&gsi); + + return gsi; +} + +/* Return a new iterator pointing to the first non-debug statement in basic block BB. */ static inline gimple_stmt_iterator diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index 4ea6c3532f3f..22db61bbd48a 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -645,7 +645,7 @@ gimple_stmt_may_fallthru (gimple *stmt) bool gimple_seq_may_fallthru (gimple_seq seq) { - return gimple_stmt_may_fallthru (gimple_seq_last_stmt (seq)); + return gimple_stmt_may_fallthru (gimple_seq_last_nondebug_stmt (seq)); } diff --git a/gcc/gimple.h b/gcc/gimple.h index f8b0a9dee4af..103d9555e465 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -4602,6 +4602,22 @@ is_gimple_debug (const gimple *gs) return gimple_code (gs) == GIMPLE_DEBUG; } + +/* Return the last nondebug statement in GIMPLE sequence S. */ + +static inline gimple * +gimple_seq_last_nondebug_stmt (gimple_seq s) +{ + gimple_seq_node n; + for (n = gimple_seq_last (s); + n && is_gimple_debug (n); + n = n->prev) + if (n->prev == s) + return NULL; + return n; +} + + /* Return true if S is a GIMPLE_DEBUG BIND statement. */ static inline bool diff --git a/gcc/gimplify.c b/gcc/gimplify.c index e9168785fc01..d252af04bcbf 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -1857,7 +1857,7 @@ case_label_p (const vec *cases, tree label) return false; } -/* Find the last statement in a scope STMT. */ +/* Find the last nondebug statement in a scope STMT. */ static gimple * last_stmt_in_scope (gimple *stmt) @@ -1870,27 +1870,30 @@ last_stmt_in_scope (gimple *stmt) case GIMPLE_BIND: { gbind *bind = as_a (stmt); - stmt = gimple_seq_last_stmt (gimple_bind_body (bind)); + stmt = gimple_seq_last_nondebug_stmt (gimple_bind_body (bind)); return last_stmt_in_scope (stmt); } case GIMPLE_TRY: { gtry *try_stmt = as_a (stmt); - stmt = gimple_seq_last_stmt (gimple_try_eval (try_stmt)); + stmt = gimple_seq_last_nondebug_stmt (gimple_try_eval (try_stmt)); gimple *last_eval = last_stmt_in_scope (stmt); if (gimple_stmt_may_fallthru (last_eval) && (last_eval == NULL || !gimple_call_internal_p (last_eval, IFN_FALLTHROUGH)) && gimple_try_kind (try_stmt) == GIMPLE_TRY_FINALLY) { - stmt = gimple_seq_last_stmt (gimple_try_cleanup (try_stmt)); + stmt = gimple_seq_last_nondebug_stmt (gimple_try_cleanup (try_stmt)); return last_stmt_in_scope (stmt); } else return last_eval; } + case GIMPLE_DEBUG: + gcc_unreachable (); + default: return stmt; } @@ -1994,7 +1997,7 @@ collect_fallthrough_labels (gimple_stmt_iterator *gsi_p, } else if (gimple_call_internal_p (gsi_stmt (*gsi_p), IFN_ASAN_MARK)) ; - else + else if (!is_gimple_debug (gsi_stmt (*gsi_p))) prev = gsi_stmt (*gsi_p); gsi_next (gsi_p); } @@ -2031,7 +2034,7 @@ should_warn_for_implicit_fallthrough (gimple_stmt_iterator *gsi_p, tree label) && gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL && (l = gimple_label_label (as_a (gsi_stmt (gsi)))) && !case_label_p (&gimplify_ctxp->case_labels, l)) - gsi_next (&gsi); + gsi_next_nondebug (&gsi); if (gsi_end_p (gsi) || gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL) return false; } @@ -2044,7 +2047,7 @@ should_warn_for_implicit_fallthrough (gimple_stmt_iterator *gsi_p, tree label) while (!gsi_end_p (gsi) && (gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL || gimple_code (gsi_stmt (gsi)) == GIMPLE_PREDICT)) - gsi_next (&gsi); + gsi_next_nondebug (&gsi); /* { ... something; default:; } */ if (gsi_end_p (gsi) @@ -2091,7 +2094,7 @@ warn_implicit_fallthrough_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, /* Found a label. Skip all immediately following labels. */ while (!gsi_end_p (*gsi_p) && gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_LABEL) - gsi_next (gsi_p); + gsi_next_nondebug (gsi_p); /* There might be no more statements. */ if (gsi_end_p (*gsi_p)) @@ -2234,8 +2237,8 @@ expand_FALLTHROUGH_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, } else if (gimple_call_internal_p (stmt, IFN_ASAN_MARK)) ; - else - /* Something other is not expected. */ + else if (!is_gimple_debug (stmt)) + /* Anything else is not expected. */ break; gsi_next (&gsi2); } diff --git a/gcc/graphite-isl-ast-to-gimple.c b/gcc/graphite-isl-ast-to-gimple.c index 16570e168557..b0409930104b 100644 --- a/gcc/graphite-isl-ast-to-gimple.c +++ b/gcc/graphite-isl-ast-to-gimple.c @@ -1007,7 +1007,7 @@ gsi_insert_earliest (gimple_seq seq) FOR_EACH_VEC_ELT (stmts, i, use_stmt) { gcc_assert (gimple_code (use_stmt) != GIMPLE_PHI); - gimple_stmt_iterator gsi_def_stmt = gsi_start_bb_nondebug (begin_bb); + gimple_stmt_iterator gsi_def_stmt = gsi_start_nondebug_bb (begin_bb); use_operand_p use_p; ssa_op_iter op_iter; @@ -1039,7 +1039,7 @@ gsi_insert_earliest (gimple_seq seq) else if (gimple_code (gsi_stmt (gsi_def_stmt)) == GIMPLE_PHI) { gimple_stmt_iterator bsi - = gsi_start_bb_nondebug (gsi_bb (gsi_def_stmt)); + = gsi_start_nondebug_bb (gsi_bb (gsi_def_stmt)); /* Insert right after the PHI statements. */ gsi_insert_before (&bsi, use_stmt, GSI_NEW_STMT); } @@ -1146,7 +1146,8 @@ graphite_copy_stmts_from_block (basic_block bb, basic_block new_bb, { if (gimple_debug_bind_p (copy)) gimple_debug_bind_reset_value (copy); - else if (gimple_debug_source_bind_p (copy)) + else if (gimple_debug_source_bind_p (copy) + || gimple_debug_nonbind_marker_p (copy)) ; else gcc_unreachable (); diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c index b7c0b3a6f4ff..cf44422d8219 100644 --- a/gcc/haifa-sched.c +++ b/gcc/haifa-sched.c @@ -8086,7 +8086,7 @@ sched_extend_bb (void) || (!NOTE_P (insn) && !LABEL_P (insn) /* Don't emit a NOTE if it would end up before a BARRIER. */ - && !BARRIER_P (NEXT_INSN (end)))) + && !BARRIER_P (next_nondebug_insn (end)))) { rtx_note *note = emit_note_after (NOTE_INSN_DELETED, end); /* Make note appear outside BB. */ diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c index b40dd8653b4d..be8c70912698 100644 --- a/gcc/ipa-icf-gimple.c +++ b/gcc/ipa-icf-gimple.c @@ -640,8 +640,8 @@ func_checker::compare_bb (sem_bb *bb1, sem_bb *bb2) gimple_stmt_iterator gsi1, gsi2; gimple *s1, *s2; - gsi1 = gsi_start_bb_nondebug (bb1->bb); - gsi2 = gsi_start_bb_nondebug (bb2->bb); + gsi1 = gsi_start_nondebug_bb (bb1->bb); + gsi2 = gsi_start_nondebug_bb (bb2->bb); while (!gsi_end_p (gsi1)) { diff --git a/gcc/jump.c b/gcc/jump.c index fc4b4345444a..e60a6c6f8e66 100644 --- a/gcc/jump.c +++ b/gcc/jump.c @@ -123,7 +123,7 @@ cleanup_barriers (void) { if (BARRIER_P (insn)) { - rtx_insn *prev = prev_nonnote_insn (insn); + rtx_insn *prev = prev_nonnote_nondebug_insn (insn); if (!prev) continue; diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c index 07856424f65a..7d3cbbe6dc2e 100644 --- a/gcc/omp-expand.c +++ b/gcc/omp-expand.c @@ -695,7 +695,7 @@ expand_parallel_call (struct omp_region *region, basic_block bb, false, GSI_CONTINUE_LINKING); } - gsi = gsi_last_bb (bb); + gsi = gsi_last_nondebug_bb (bb); t = gimple_omp_parallel_data_arg (entry_stmt); if (t == NULL) t1 = null_pointer_node; @@ -748,7 +748,7 @@ expand_cilk_for_call (basic_block bb, gomp_parallel *entry_stmt, gcc_assert (count != NULL_TREE); count = OMP_CLAUSE_OPERAND (count, 0); - gsi = gsi_last_bb (bb); + gsi = gsi_last_nondebug_bb (bb); t = gimple_omp_parallel_data_arg (entry_stmt); if (t == NULL) t1 = null_pointer_node; @@ -874,7 +874,7 @@ expand_task_call (struct omp_region *region, basic_block bb, else priority = integer_zero_node; - gsi = gsi_last_bb (bb); + gsi = gsi_last_nondebug_bb (bb); tree t = gimple_omp_task_data_arg (entry_stmt); if (t == NULL) t2 = null_pointer_node; @@ -951,15 +951,15 @@ remove_exit_barrier (struct omp_region *region) statements that can appear in between are extremely limited -- no memory operations at all. Here, we allow nothing at all, so the only thing we allow to precede this GIMPLE_OMP_RETURN is a label. */ - gsi = gsi_last_bb (exit_bb); + gsi = gsi_last_nondebug_bb (exit_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN); - gsi_prev (&gsi); + gsi_prev_nondebug (&gsi); if (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL) return; FOR_EACH_EDGE (e, ei, exit_bb->preds) { - gsi = gsi_last_bb (e->src); + gsi = gsi_last_nondebug_bb (e->src); if (gsi_end_p (gsi)) continue; stmt = gsi_stmt (gsi); @@ -1186,7 +1186,7 @@ expand_omp_taskreg (struct omp_region *region) entry_succ_e = single_succ_edge (entry_bb); - gsi = gsi_last_bb (entry_bb); + gsi = gsi_last_nondebug_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_PARALLEL || gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_TASK); gsi_remove (&gsi, true); @@ -1299,7 +1299,7 @@ expand_omp_taskreg (struct omp_region *region) /* Split ENTRY_BB at GIMPLE_OMP_PARALLEL or GIMPLE_OMP_TASK, so that it can be moved to the child function. */ - gsi = gsi_last_bb (entry_bb); + gsi = gsi_last_nondebug_bb (entry_bb); stmt = gsi_stmt (gsi); gcc_assert (stmt && (gimple_code (stmt) == GIMPLE_OMP_PARALLEL || gimple_code (stmt) == GIMPLE_OMP_TASK)); @@ -1315,7 +1315,7 @@ expand_omp_taskreg (struct omp_region *region) gcc_assert (e2->dest == region->exit); remove_edge (BRANCH_EDGE (entry_bb)); set_immediate_dominator (CDI_DOMINATORS, e2->dest, e->src); - gsi = gsi_last_bb (region->exit); + gsi = gsi_last_nondebug_bb (region->exit); gcc_assert (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN); gsi_remove (&gsi, true); @@ -1324,7 +1324,7 @@ expand_omp_taskreg (struct omp_region *region) /* Convert GIMPLE_OMP_{RETURN,CONTINUE} into a RETURN_EXPR. */ if (exit_bb) { - gsi = gsi_last_bb (exit_bb); + gsi = gsi_last_nondebug_bb (exit_bb); gcc_assert (!gsi_end_p (gsi) && (gimple_code (gsi_stmt (gsi)) == (e2 ? GIMPLE_OMP_CONTINUE : GIMPLE_OMP_RETURN))); @@ -1787,7 +1787,7 @@ expand_omp_for_init_counts (struct omp_for_data *fd, gimple_stmt_iterator *gsi, if (l2_dom_bb == NULL) l2_dom_bb = entry_bb; entry_bb = e->dest; - *gsi = gsi_last_bb (entry_bb); + *gsi = gsi_last_nondebug_bb (entry_bb); } if (POINTER_TYPE_P (itype)) @@ -2592,7 +2592,7 @@ expand_omp_for_generic (struct omp_region *region, l3_bb = BRANCH_EDGE (entry_bb)->dest; exit_bb = region->exit; - gsi = gsi_last_bb (entry_bb); + gsi = gsi_last_nondebug_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); if (fd->ordered @@ -2622,7 +2622,7 @@ expand_omp_for_generic (struct omp_region *region, e = split_block (entry_bb, gsi_stmt (gsi)); entry_bb = e->dest; make_edge (zero_iter1_bb, entry_bb, EDGE_FALLTHRU); - gsi = gsi_last_bb (entry_bb); + gsi = gsi_last_nondebug_bb (entry_bb); set_immediate_dominator (CDI_DOMINATORS, entry_bb, get_immediate_dominator (CDI_DOMINATORS, zero_iter1_bb)); @@ -2643,7 +2643,7 @@ expand_omp_for_generic (struct omp_region *region, e = split_block (entry_bb, gsi_stmt (gsi)); entry_bb = e->dest; make_edge (zero_iter2_bb, entry_bb, EDGE_FALLTHRU); - gsi = gsi_last_bb (entry_bb); + gsi = gsi_last_nondebug_bb (entry_bb); set_immediate_dominator (CDI_DOMINATORS, entry_bb, get_immediate_dominator (CDI_DOMINATORS, zero_iter2_bb)); @@ -3061,7 +3061,7 @@ expand_omp_for_generic (struct omp_region *region, { /* Code to control the increment and predicate for the sequential loop goes in the CONT_BB. */ - gsi = gsi_last_bb (cont_bb); + gsi = gsi_last_nondebug_bb (cont_bb); gomp_continue *cont_stmt = as_a (gsi_stmt (gsi)); gcc_assert (gimple_code (cont_stmt) == GIMPLE_OMP_CONTINUE); vmain = gimple_omp_continue_control_use (cont_stmt); @@ -3127,7 +3127,7 @@ expand_omp_for_generic (struct omp_region *region, } /* Add the loop cleanup function. */ - gsi = gsi_last_bb (exit_bb); + gsi = gsi_last_nondebug_bb (exit_bb); if (gimple_omp_return_nowait_p (gsi_stmt (gsi))) t = builtin_decl_explicit (BUILT_IN_GOMP_LOOP_END_NOWAIT); else if (gimple_omp_return_lhs (gsi_stmt (gsi))) @@ -3347,7 +3347,7 @@ expand_omp_for_static_nochunk (struct omp_region *region, exit_bb = region->exit; /* Iteration space partitioning goes in ENTRY_BB. */ - gsi = gsi_last_bb (entry_bb); + gsi = gsi_last_nondebug_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); if (fd->collapse > 1) @@ -3479,7 +3479,7 @@ expand_omp_for_static_nochunk (struct omp_region *region, gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT); second_bb = split_block (entry_bb, cond_stmt)->dest; - gsi = gsi_last_bb (second_bb); + gsi = gsi_last_nondebug_bb (second_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); gsi_insert_before (&gsi, gimple_build_assign (tt, build_int_cst (itype, 0)), @@ -3489,7 +3489,7 @@ expand_omp_for_static_nochunk (struct omp_region *region, gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT); third_bb = split_block (second_bb, assign_stmt)->dest; - gsi = gsi_last_bb (third_bb); + gsi = gsi_last_nondebug_bb (third_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); t = build2 (MULT_EXPR, itype, q, threadid); @@ -3631,7 +3631,7 @@ expand_omp_for_static_nochunk (struct omp_region *region, { /* The code controlling the sequential loop replaces the GIMPLE_OMP_CONTINUE. */ - gsi = gsi_last_bb (cont_bb); + gsi = gsi_last_nondebug_bb (cont_bb); gomp_continue *cont_stmt = as_a (gsi_stmt (gsi)); gcc_assert (gimple_code (cont_stmt) == GIMPLE_OMP_CONTINUE); vmain = gimple_omp_continue_control_use (cont_stmt); @@ -3664,7 +3664,7 @@ expand_omp_for_static_nochunk (struct omp_region *region, } /* Replace the GIMPLE_OMP_RETURN with a barrier, or nothing. */ - gsi = gsi_last_bb (exit_bb); + gsi = gsi_last_nondebug_bb (exit_bb); if (!gimple_omp_return_nowait_p (gsi_stmt (gsi))) { t = gimple_omp_return_lhs (gsi_stmt (gsi)); @@ -3831,7 +3831,7 @@ expand_omp_for_static_chunk (struct omp_region *region, exit_bb = region->exit; /* Trip and adjustment setup goes in ENTRY_BB. */ - gsi = gsi_last_bb (entry_bb); + gsi = gsi_last_nondebug_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); if (fd->collapse > 1) @@ -4137,7 +4137,7 @@ expand_omp_for_static_chunk (struct omp_region *region, { /* The code controlling the sequential loop goes in CONT_BB, replacing the GIMPLE_OMP_CONTINUE. */ - gsi = gsi_last_bb (cont_bb); + gsi = gsi_last_nondebug_bb (cont_bb); gomp_continue *cont_stmt = as_a (gsi_stmt (gsi)); vmain = gimple_omp_continue_control_use (cont_stmt); vback = gimple_omp_continue_control_def (cont_stmt); @@ -4181,7 +4181,7 @@ expand_omp_for_static_chunk (struct omp_region *region, } /* Replace the GIMPLE_OMP_RETURN with a barrier, or nothing. */ - gsi = gsi_last_bb (exit_bb); + gsi = gsi_last_nondebug_bb (exit_bb); if (!gimple_omp_return_nowait_p (gsi_stmt (gsi))) { t = gimple_omp_return_lhs (gsi_stmt (gsi)); @@ -4392,7 +4392,7 @@ expand_cilk_for (struct omp_region *region, struct omp_for_data *fd) basic_block exit_bb = region->exit; basic_block l2_dom_bb = NULL; - gimple_stmt_iterator gsi = gsi_last_bb (entry_bb); + gimple_stmt_iterator gsi = gsi_last_nondebug_bb (entry_bb); /* Below statements until the "tree high_val = ..." are pseudo statements used to pass information to be used by expand_omp_taskreg. @@ -4437,7 +4437,7 @@ expand_cilk_for (struct omp_region *region, struct omp_for_data *fd) if (!broken_loop) { /* Code to control the increment goes in the CONT_BB. */ - gsi = gsi_last_bb (cont_bb); + gsi = gsi_last_nondebug_bb (cont_bb); stmt = gsi_stmt (gsi); gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE); stmt = gimple_build_assign (ind_var, PLUS_EXPR, ind_var, @@ -4467,7 +4467,7 @@ expand_cilk_for (struct omp_region *region, struct omp_for_data *fd) gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); /* Remove GIMPLE_OMP_RETURN. */ - gsi = gsi_last_bb (exit_bb); + gsi = gsi_last_nondebug_bb (exit_bb); gsi_remove (&gsi, true); /* Connect the new blocks. */ @@ -4641,7 +4641,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) exit_bb = region->exit; l2_dom_bb = NULL; - gsi = gsi_last_bb (entry_bb); + gsi = gsi_last_nondebug_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); /* Not needed in SSA form right now. */ @@ -4736,7 +4736,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) if (!broken_loop) { /* Code to control the increment goes in the CONT_BB. */ - gsi = gsi_last_bb (cont_bb); + gsi = gsi_last_nondebug_bb (cont_bb); stmt = gsi_stmt (gsi); gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE); @@ -4834,7 +4834,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) } /* Remove GIMPLE_OMP_RETURN. */ - gsi = gsi_last_bb (exit_bb); + gsi = gsi_last_nondebug_bb (exit_bb); gsi_remove (&gsi, true); /* Connect the new blocks. */ @@ -4960,7 +4960,7 @@ expand_omp_taskloop_for_outer (struct omp_region *region, gcc_assert (BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest); exit_bb = region->exit; - gsi = gsi_last_bb (entry_bb); + gsi = gsi_last_nondebug_bb (entry_bb); gimple *for_stmt = gsi_stmt (gsi); gcc_assert (gimple_code (for_stmt) == GIMPLE_OMP_FOR); if (fd->collapse > 1) @@ -5061,10 +5061,10 @@ expand_omp_taskloop_for_outer (struct omp_region *region, gsi = gsi_for_stmt (for_stmt); gsi_remove (&gsi, true); - gsi = gsi_last_bb (cont_bb); + gsi = gsi_last_nondebug_bb (cont_bb); gsi_remove (&gsi, true); - gsi = gsi_last_bb (exit_bb); + gsi = gsi_last_nondebug_bb (exit_bb); gsi_remove (&gsi, true); FALLTHRU_EDGE (entry_bb)->probability = profile_probability::always (); @@ -5138,7 +5138,7 @@ expand_omp_taskloop_for_inner (struct omp_region *region, exit_bb = region->exit; /* Iteration space partitioning goes in ENTRY_BB. */ - gsi = gsi_last_bb (entry_bb); + gsi = gsi_last_nondebug_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); if (fd->collapse > 1) @@ -5217,7 +5217,7 @@ expand_omp_taskloop_for_inner (struct omp_region *region, { /* The code controlling the sequential loop replaces the GIMPLE_OMP_CONTINUE. */ - gsi = gsi_last_bb (cont_bb); + gsi = gsi_last_nondebug_bb (cont_bb); gomp_continue *cont_stmt = as_a (gsi_stmt (gsi)); gcc_assert (gimple_code (cont_stmt) == GIMPLE_OMP_CONTINUE); vmain = gimple_omp_continue_control_use (cont_stmt); @@ -5254,7 +5254,7 @@ expand_omp_taskloop_for_inner (struct omp_region *region, gsi_remove (&gsi, true); /* Remove the GIMPLE_OMP_RETURN statement. */ - gsi = gsi_last_bb (exit_bb); + gsi = gsi_last_nondebug_bb (exit_bb); gsi_remove (&gsi, true); FALLTHRU_EDGE (entry_bb)->probability = profile_probability::always (); @@ -5437,7 +5437,7 @@ expand_oacc_for (struct omp_region *region, struct omp_for_data *fd) entry_bb = split->src; /* Chunk setup goes at end of entry_bb, replacing the omp_for. */ - gsi = gsi_last_bb (entry_bb); + gsi = gsi_last_nondebug_bb (entry_bb); gomp_for *for_stmt = as_a (gsi_stmt (gsi)); loc = gimple_location (for_stmt); @@ -5564,7 +5564,7 @@ expand_oacc_for (struct omp_region *region, struct omp_for_data *fd) if (gimple_in_ssa_p (cfun)) { - gsi = gsi_last_bb (cont_bb); + gsi = gsi_last_nondebug_bb (cont_bb); gomp_continue *cont_stmt = as_a (gsi_stmt (gsi)); offset = gimple_omp_continue_control_use (cont_stmt); @@ -5688,7 +5688,7 @@ expand_oacc_for (struct omp_region *region, struct omp_for_data *fd) occur, especially when noreturn routines are involved. */ if (cont_bb) { - gsi = gsi_last_bb (cont_bb); + gsi = gsi_last_nondebug_bb (cont_bb); gomp_continue *cont_stmt = as_a (gsi_stmt (gsi)); loc = gimple_location (cont_stmt); @@ -5777,7 +5777,7 @@ expand_oacc_for (struct omp_region *region, struct omp_for_data *fd) } } - gsi = gsi_last_bb (exit_bb); + gsi = gsi_last_nondebug_bb (exit_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN); loc = gimple_location (gsi_stmt (gsi)); @@ -6004,7 +6004,7 @@ expand_omp_sections (struct omp_region *region) len = EDGE_COUNT (l0_bb->succs); gcc_assert (len > 0); e = EDGE_SUCC (l0_bb, len - 1); - si = gsi_last_bb (e->dest); + si = gsi_last_nondebug_bb (e->dest); l2 = NULL_TREE; if (gsi_end_p (si) || gimple_code (gsi_stmt (si)) != GIMPLE_OMP_SECTION) @@ -6012,7 +6012,7 @@ expand_omp_sections (struct omp_region *region) else FOR_EACH_EDGE (e, ei, l0_bb->succs) { - si = gsi_last_bb (e->dest); + si = gsi_last_nondebug_bb (e->dest); if (gsi_end_p (si) || gimple_code (gsi_stmt (si)) != GIMPLE_OMP_SECTION) { @@ -6037,7 +6037,7 @@ expand_omp_sections (struct omp_region *region) /* The call to GOMP_sections_start goes in ENTRY_BB, replacing the GIMPLE_OMP_SECTIONS statement. */ - si = gsi_last_bb (entry_bb); + si = gsi_last_nondebug_bb (entry_bb); sections_stmt = as_a (gsi_stmt (si)); gcc_assert (gimple_code (sections_stmt) == GIMPLE_OMP_SECTIONS); vin = gimple_omp_sections_control (sections_stmt); @@ -6061,7 +6061,7 @@ expand_omp_sections (struct omp_region *region) /* The switch() statement replacing GIMPLE_OMP_SECTIONS_SWITCH goes in L0_BB. */ - switch_si = gsi_last_bb (l0_bb); + switch_si = gsi_last_nondebug_bb (l0_bb); gcc_assert (gimple_code (gsi_stmt (switch_si)) == GIMPLE_OMP_SECTIONS_SWITCH); if (exit_reachable) { @@ -6103,7 +6103,7 @@ expand_omp_sections (struct omp_region *region) u = build_case_label (u, NULL, t); label_vec.quick_push (u); - si = gsi_last_bb (s_entry_bb); + si = gsi_last_nondebug_bb (s_entry_bb); gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SECTION); gcc_assert (i < len || gimple_omp_section_last_p (gsi_stmt (si))); gsi_remove (&si, true); @@ -6112,7 +6112,7 @@ expand_omp_sections (struct omp_region *region) if (s_exit_bb == NULL) continue; - si = gsi_last_bb (s_exit_bb); + si = gsi_last_nondebug_bb (s_exit_bb); gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_RETURN); gsi_remove (&si, true); @@ -6138,7 +6138,7 @@ expand_omp_sections (struct omp_region *region) tree bfn_decl; /* Code to get the next section goes in L1_BB. */ - si = gsi_last_bb (l1_bb); + si = gsi_last_nondebug_bb (l1_bb); gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CONTINUE); bfn_decl = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_NEXT); @@ -6151,7 +6151,7 @@ expand_omp_sections (struct omp_region *region) } /* Cleanup function replaces GIMPLE_OMP_RETURN in EXIT_BB. */ - si = gsi_last_bb (l2_bb); + si = gsi_last_nondebug_bb (l2_bb); if (gimple_omp_return_nowait_p (gsi_stmt (si))) t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END_NOWAIT); else if (gimple_omp_return_lhs (gsi_stmt (si))) @@ -6179,12 +6179,12 @@ expand_omp_single (struct omp_region *region) entry_bb = region->entry; exit_bb = region->exit; - si = gsi_last_bb (entry_bb); + si = gsi_last_nondebug_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE); gsi_remove (&si, true); single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU; - si = gsi_last_bb (exit_bb); + si = gsi_last_nondebug_bb (exit_bb); if (!gimple_omp_return_nowait_p (gsi_stmt (si))) { tree t = gimple_omp_return_lhs (gsi_stmt (si)); @@ -6207,7 +6207,7 @@ expand_omp_synch (struct omp_region *region) entry_bb = region->entry; exit_bb = region->exit; - si = gsi_last_bb (entry_bb); + si = gsi_last_nondebug_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_MASTER || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_TASKGROUP @@ -6219,7 +6219,7 @@ expand_omp_synch (struct omp_region *region) if (exit_bb) { - si = gsi_last_bb (exit_bb); + si = gsi_last_nondebug_bb (exit_bb); gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_RETURN); gsi_remove (&si, true); single_succ_edge (exit_bb)->flags = EDGE_FALLTHRU; @@ -6240,7 +6240,7 @@ expand_omp_atomic_load (basic_block load_bb, tree addr, gimple *stmt; tree decl, call, type, itype; - gsi = gsi_last_bb (load_bb); + gsi = gsi_last_nondebug_bb (load_bb); stmt = gsi_stmt (gsi); gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_LOAD); loc = gimple_location (stmt); @@ -6270,7 +6270,7 @@ expand_omp_atomic_load (basic_block load_bb, tree addr, gsi_remove (&gsi, true); store_bb = single_succ (load_bb); - gsi = gsi_last_bb (store_bb); + gsi = gsi_last_nondebug_bb (store_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_STORE); gsi_remove (&gsi, true); @@ -6296,14 +6296,14 @@ expand_omp_atomic_store (basic_block load_bb, tree addr, machine_mode imode; bool exchange; - gsi = gsi_last_bb (load_bb); + gsi = gsi_last_nondebug_bb (load_bb); stmt = gsi_stmt (gsi); gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_LOAD); /* If the load value is needed, then this isn't a store but an exchange. */ exchange = gimple_omp_atomic_need_value_p (stmt); - gsi = gsi_last_bb (store_bb); + gsi = gsi_last_nondebug_bb (store_bb); stmt = gsi_stmt (gsi); gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_STORE); loc = gimple_location (stmt); @@ -6348,7 +6348,7 @@ expand_omp_atomic_store (basic_block load_bb, tree addr, gsi_remove (&gsi, true); /* Remove the GIMPLE_OMP_ATOMIC_LOAD that we verified above. */ - gsi = gsi_last_bb (load_bb); + gsi = gsi_last_nondebug_bb (load_bb); gsi_remove (&gsi, true); if (gimple_in_ssa_p (cfun)) @@ -6395,10 +6395,17 @@ expand_omp_atomic_fetch_op (basic_block load_bb, gsi = gsi_after_labels (store_bb); stmt = gsi_stmt (gsi); + if (is_gimple_debug (stmt)) + { + gsi_next_nondebug (&gsi); + if (gsi_end_p (gsi)) + return false; + stmt = gsi_stmt (gsi); + } loc = gimple_location (stmt); if (!is_gimple_assign (stmt)) return false; - gsi_next (&gsi); + gsi_next_nondebug (&gsi); if (gimple_code (gsi_stmt (gsi)) != GIMPLE_OMP_ATOMIC_STORE) return false; need_new = gimple_omp_atomic_need_value_p (gsi_stmt (gsi)); @@ -6462,7 +6469,7 @@ expand_omp_atomic_fetch_op (basic_block load_bb, if (!can_compare_and_swap_p (imode, true) || !can_atomic_load_p (imode)) return false; - gsi = gsi_last_bb (load_bb); + gsi = gsi_last_nondebug_bb (load_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_LOAD); /* OpenMP does not imply any barrier-like semantics on its atomic ops. @@ -6485,10 +6492,10 @@ expand_omp_atomic_fetch_op (basic_block load_bb, force_gimple_operand_gsi (&gsi, call, true, NULL_TREE, true, GSI_SAME_STMT); gsi_remove (&gsi, true); - gsi = gsi_last_bb (store_bb); + gsi = gsi_last_nondebug_bb (store_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_STORE); gsi_remove (&gsi, true); - gsi = gsi_last_bb (store_bb); + gsi = gsi_last_nondebug_bb (store_bb); stmt = gsi_stmt (gsi); gsi_remove (&gsi, true); @@ -6541,7 +6548,7 @@ expand_omp_atomic_pipeline (basic_block load_bb, basic_block store_bb, return false; /* Load the initial value, replacing the GIMPLE_OMP_ATOMIC_LOAD. */ - si = gsi_last_bb (load_bb); + si = gsi_last_nondebug_bb (load_bb); gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_LOAD); /* For floating-point values, we'll need to view-convert them to integers @@ -6621,7 +6628,7 @@ expand_omp_atomic_pipeline (basic_block load_bb, basic_block store_bb, } gsi_remove (&si, true); - si = gsi_last_bb (store_bb); + si = gsi_last_nondebug_bb (store_bb); gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_STORE); if (iaddr == addr) @@ -6724,7 +6731,7 @@ expand_omp_atomic_mutex (basic_block load_bb, basic_block store_bb, gassign *stmt; tree t; - si = gsi_last_bb (load_bb); + si = gsi_last_nondebug_bb (load_bb); gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_LOAD); t = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_START); @@ -6735,7 +6742,7 @@ expand_omp_atomic_mutex (basic_block load_bb, basic_block store_bb, gsi_insert_before (&si, stmt, GSI_SAME_STMT); gsi_remove (&si, true); - si = gsi_last_bb (store_bb); + si = gsi_last_nondebug_bb (store_bb); gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_STORE); stmt = gimple_build_assign (build_simple_mem_ref (unshare_expr (addr)), @@ -7234,7 +7241,7 @@ expand_omp_target (struct omp_region *region) /* Split ENTRY_BB at GIMPLE_*, so that it can be moved to the child function. */ - gsi = gsi_last_bb (entry_bb); + gsi = gsi_last_nondebug_bb (entry_bb); stmt = gsi_stmt (gsi); gcc_assert (stmt && gimple_code (stmt) == gimple_code (entry_stmt)); @@ -7246,7 +7253,7 @@ expand_omp_target (struct omp_region *region) /* Convert GIMPLE_OMP_RETURN into a RETURN_EXPR. */ if (exit_bb) { - gsi = gsi_last_bb (exit_bb); + gsi = gsi_last_nondebug_bb (exit_bb); gcc_assert (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN); stmt = gimple_build_return (NULL); @@ -7428,7 +7435,7 @@ expand_omp_target (struct omp_region *region) e = split_block_after_labels (new_bb); else { - gsi = gsi_last_bb (new_bb); + gsi = gsi_last_nondebug_bb (new_bb); gsi_prev (&gsi); e = split_block (new_bb, gsi_stmt (gsi)); } @@ -7463,11 +7470,11 @@ expand_omp_target (struct omp_region *region) make_edge (else_bb, new_bb, EDGE_FALLTHRU); device = tmp_var; - gsi = gsi_last_bb (new_bb); + gsi = gsi_last_nondebug_bb (new_bb); } else { - gsi = gsi_last_bb (new_bb); + gsi = gsi_last_nondebug_bb (new_bb); device = force_gimple_operand_gsi (&gsi, device, true, NULL_TREE, true, GSI_SAME_STMT); } @@ -7611,7 +7618,7 @@ expand_omp_target (struct omp_region *region) } if (data_region && region->exit) { - gsi = gsi_last_bb (region->exit); + gsi = gsi_last_nondebug_bb (region->exit); g = gsi_stmt (gsi); gcc_assert (g && gimple_code (g) == GIMPLE_OMP_RETURN); gsi_remove (&gsi, true); @@ -7692,17 +7699,17 @@ grid_expand_omp_for_loop (struct omp_region *kfor, bool intra_group) gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT); } /* Remove the omp for statement. */ - gsi = gsi_last_bb (kfor->entry); + gsi = gsi_last_nondebug_bb (kfor->entry); gsi_remove (&gsi, true); /* Remove the GIMPLE_OMP_CONTINUE statement. */ - gsi = gsi_last_bb (kfor->cont); + gsi = gsi_last_nondebug_bb (kfor->cont); gcc_assert (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_CONTINUE); gsi_remove (&gsi, true); /* Replace the GIMPLE_OMP_RETURN with a barrier, if necessary. */ - gsi = gsi_last_bb (kfor->exit); + gsi = gsi_last_nondebug_bb (kfor->exit); gcc_assert (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN); if (intra_group) @@ -7846,11 +7853,11 @@ grid_expand_target_grid_body (struct omp_region *target) grid_expand_omp_for_loop (kfor, false); /* Remove the omp for statement. */ - gimple_stmt_iterator gsi = gsi_last_bb (gpukernel->entry); + gimple_stmt_iterator gsi = gsi_last_nondebug_bb (gpukernel->entry); gsi_remove (&gsi, true); /* Replace the GIMPLE_OMP_RETURN at the end of the kernel region with a real return. */ - gsi = gsi_last_bb (gpukernel->exit); + gsi = gsi_last_nondebug_bb (gpukernel->exit); gcc_assert (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN); gimple *ret_stmt = gimple_build_return (NULL); @@ -8034,7 +8041,7 @@ build_omp_regions_1 (basic_block bb, struct omp_region *parent, gimple *stmt; basic_block son; - gsi = gsi_last_bb (bb); + gsi = gsi_last_nondebug_bb (bb); if (!gsi_end_p (gsi) && is_gimple_omp (gsi_stmt (gsi))) { struct omp_region *region; diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 33e633cd627b..528516b7d010 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -7033,6 +7033,8 @@ check_combined_parallel (gimple_stmt_iterator *gsi_p, { WALK_SUBSTMTS; + case GIMPLE_DEBUG: + break; case GIMPLE_OMP_FOR: case GIMPLE_OMP_SECTIONS: *info = *info == 0 ? 1 : -1; diff --git a/gcc/postreload.c b/gcc/postreload.c index 000ed341b034..8e4a81903f5e 100644 --- a/gcc/postreload.c +++ b/gcc/postreload.c @@ -836,7 +836,7 @@ fixup_debug_insns (rtx reg, rtx replacement, rtx_insn *from, rtx_insn *to) { rtx t; - if (!DEBUG_INSN_P (insn)) + if (!DEBUG_BIND_INSN_P (insn)) continue; t = INSN_VAR_LOCATION_LOC (insn); diff --git a/gcc/regcprop.c b/gcc/regcprop.c index 15d8b140ce7f..33e6e62a4c26 100644 --- a/gcc/regcprop.c +++ b/gcc/regcprop.c @@ -428,6 +428,8 @@ find_oldest_value_reg (enum reg_class cl, rtx reg, struct value_data *vd) machine_mode mode = GET_MODE (reg); unsigned int i; + gcc_assert (regno < FIRST_PSEUDO_REGISTER); + /* If we are accessing REG in some mode other that what we set it in, make sure that the replacement is valid. In particular, consider (set (reg:DI r11) (...)) diff --git a/gcc/sese.c b/gcc/sese.c index bbc72d4d7618..a69ea90622da 100644 --- a/gcc/sese.c +++ b/gcc/sese.c @@ -460,7 +460,7 @@ sese_trivially_empty_bb_p (basic_block bb) gimple_stmt_iterator gsi; for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - if (gimple_code (gsi_stmt (gsi)) != GIMPLE_DEBUG + if (!is_gimple_debug (gsi_stmt (gsi)) && gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL) return false; diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 17fe2b3002fe..f5cfe098c77f 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -545,14 +545,22 @@ make_blocks_1 (gimple_seq seq, basic_block bb) { gimple_stmt_iterator i = gsi_start (seq); gimple *stmt = NULL; + gimple *prev_stmt = NULL; bool start_new_block = true; bool first_stmt_of_seq = true; while (!gsi_end_p (i)) { - gimple *prev_stmt; - - prev_stmt = stmt; + /* PREV_STMT should only be set to a debug stmt if the debug + stmt is before nondebug stmts. Once stmt reaches a nondebug + nonlabel, prev_stmt will be set to it, so that + stmt_starts_bb_p will know to start a new block if a label is + found. However, if stmt was a label after debug stmts only, + keep the label in prev_stmt even if we find further debug + stmts, for there may be other labels after them, and they + should land in the same block. */ + if (!prev_stmt || !stmt || !is_gimple_debug (stmt)) + prev_stmt = stmt; stmt = gsi_stmt (i); if (stmt && is_gimple_call (stmt)) @@ -567,6 +575,7 @@ make_blocks_1 (gimple_seq seq, basic_block bb) gsi_split_seq_before (&i, &seq); bb = create_basic_block (seq, bb); start_new_block = false; + prev_stmt = NULL; } /* Now add STMT to BB and create the subgraphs for special statement @@ -980,7 +989,11 @@ make_edges (void) tree target; if (!label_stmt) - break; + { + if (is_gimple_debug (gsi_stmt (gsi))) + continue; + break; + } target = gimple_label_label (label_stmt); @@ -1492,6 +1505,9 @@ cleanup_dead_labels (void) for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) { + if (is_gimple_debug (gsi_stmt (i))) + continue; + tree label; glabel *label_stmt = dyn_cast (gsi_stmt (i)); @@ -1652,6 +1668,12 @@ cleanup_dead_labels (void) for (i = gsi_start_bb (bb); !gsi_end_p (i); ) { + if (is_gimple_debug (gsi_stmt (i))) + { + gsi_next (&i); + continue; + } + tree label; glabel *label_stmt = dyn_cast (gsi_stmt (i)); @@ -1820,6 +1842,8 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b) gsi_next (&gsi)) { tree lab; + if (is_gimple_debug (gsi_stmt (gsi))) + continue; glabel *label_stmt = dyn_cast (gsi_stmt (gsi)); if (!label_stmt) break; @@ -2621,6 +2645,13 @@ stmt_starts_bb_p (gimple *stmt, gimple *prev_stmt) if (stmt == NULL) return false; + /* PREV_STMT is only set to a debug stmt if the debug stmt is before + any nondebug stmts in the block. We don't want to start another + block in this case: the debug stmt will already have started the + one STMT would start if we weren't outputting debug stmts. */ + if (prev_stmt && is_gimple_debug (prev_stmt)) + return false; + /* Labels start a new basic block only if the preceding statement wasn't a label of the same type. This prevents the creation of consecutive blocks that have nothing but a single label. */ @@ -5439,6 +5470,10 @@ gimple_verify_flow_info (void) for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { tree label; + + if (is_gimple_debug (gsi_stmt (gsi))) + continue; + gimple *prev_stmt = stmt; stmt = gsi_stmt (gsi); @@ -5508,7 +5543,7 @@ gimple_verify_flow_info (void) } } - gsi = gsi_last_bb (bb); + gsi = gsi_last_nondebug_bb (bb); if (gsi_end_p (gsi)) continue; @@ -5763,8 +5798,10 @@ gimple_block_label (basic_block bb) tree label; glabel *stmt; - for (i = s; !gsi_end_p (i); first = false, gsi_next (&i)) + for (i = s; !gsi_end_p (i); gsi_next (&i)) { + if (is_gimple_debug (gsi_stmt (i))) + continue; stmt = dyn_cast (gsi_stmt (i)); if (!stmt) break; @@ -5775,6 +5812,7 @@ gimple_block_label (basic_block bb) gsi_move_before (&i, &s); return label; } + first = false; } label = create_artificial_label (UNKNOWN_LOCATION); @@ -5850,7 +5888,7 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest) return ret; } - gsi = gsi_last_bb (bb); + gsi = gsi_last_nondebug_bb (bb); stmt = gsi_end_p (gsi) ? NULL : gsi_stmt (gsi); switch (stmt ? gimple_code (stmt) : GIMPLE_ERROR_MARK) diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c index 9b7f08c586c3..346ce92669c9 100644 --- a/gcc/tree-cfgcleanup.c +++ b/gcc/tree-cfgcleanup.c @@ -554,13 +554,13 @@ remove_forwarder_block (basic_block bb) { tree decl; label = gsi_stmt (gsi); - if (is_gimple_debug (label)) - break; - decl = gimple_label_label (as_a (label)); - if (EH_LANDING_PAD_NR (decl) != 0 - || DECL_NONLOCAL (decl) - || FORCED_LABEL (decl) - || !DECL_ARTIFICIAL (decl)) + if (is_gimple_debug (label) + ? can_move_debug_stmts + : ((decl = gimple_label_label (as_a (label))), + EH_LANDING_PAD_NR (decl) != 0 + || DECL_NONLOCAL (decl) + || FORCED_LABEL (decl) + || !DECL_ARTIFICIAL (decl))) { gsi_remove (&gsi, false); gsi_insert_before (&gsi_to, label, GSI_SAME_STMT); @@ -569,20 +569,6 @@ remove_forwarder_block (basic_block bb) gsi_next (&gsi); } - /* Move debug statements if the destination has a single predecessor. */ - if (can_move_debug_stmts) - { - gsi_to = gsi_after_labels (dest); - for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); ) - { - gimple *debug = gsi_stmt (gsi); - if (!is_gimple_debug (debug)) - break; - gsi_remove (&gsi, false); - gsi_insert_before (&gsi_to, debug, GSI_SAME_STMT); - } - } - bitmap_set_bit (cfgcleanup_altered_bbs, dest->index); /* Update the dominators. */ @@ -1288,7 +1274,8 @@ execute_cleanup_cfg_post_optimizing (void) flag_dump_noaddr = flag_dump_unnumbered = 1; fprintf (final_output, "\n"); - dump_enumerated_decls (final_output, dump_flags | TDF_NOUID); + dump_enumerated_decls (final_output, + dump_flags | TDF_SLIM | TDF_NOUID); flag_dump_noaddr = save_noaddr; flag_dump_unnumbered = save_unnumbered; if (fclose (final_output)) diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 61a28c6757fb..8c7b6d67b44c 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -3387,7 +3387,10 @@ print_declaration (pretty_printer *pp, tree t, int spc, dump_flags_t flags) pp_space (pp); pp_equal (pp); pp_space (pp); - dump_generic_node (pp, DECL_INITIAL (t), spc, flags, false); + if (!(flags & TDF_SLIM)) + dump_generic_node (pp, DECL_INITIAL (t), spc, flags, false); + else + pp_string (pp, "<<< omitted >>>"); } } diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index 4a5cd87e25e7..0e485a683afa 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -256,7 +256,8 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive) easily locate the debug temp bind stmt for a use thereof, would could refrain from marking all debug temps here, and mark them only if they're used. */ - if (!gimple_debug_bind_p (stmt) + if (gimple_debug_nonbind_marker_p (stmt) + || !gimple_debug_bind_p (stmt) || gimple_debug_bind_has_value_p (stmt) || TREE_CODE (gimple_debug_bind_get_var (stmt)) != DEBUG_EXPR_DECL) mark_stmt_necessary (stmt, false); @@ -1442,8 +1443,7 @@ eliminate_unnecessary_stmts (void) dominate others. Walking backwards, this should be the common case. ??? Do we need to recompute dominators because of cfg_altered? */ - if (!MAY_HAVE_DEBUG_STMTS - || !first_dom_son (CDI_DOMINATORS, bb)) + if (!first_dom_son (CDI_DOMINATORS, bb)) delete_basic_block (bb); else { diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c index 6db33c566c86..613b194e6122 100644 --- a/gcc/tree-ssa-tail-merge.c +++ b/gcc/tree-ssa-tail-merge.c @@ -1295,14 +1295,14 @@ find_duplicate (same_succ *same_succ, basic_block bb1, basic_block bb2) tree label = gimple_label_label (as_a (gsi_stmt (gsi1))); if (DECL_NONLOCAL (label) || FORCED_LABEL (label)) return; - gsi_prev (&gsi1); + gsi_prev_nondebug (&gsi1); } while (!gsi_end_p (gsi2) && gimple_code (gsi_stmt (gsi2)) == GIMPLE_LABEL) { tree label = gimple_label_label (as_a (gsi_stmt (gsi2))); if (DECL_NONLOCAL (label) || FORCED_LABEL (label)) return; - gsi_prev (&gsi2); + gsi_prev_nondebug (&gsi2); } if (!(gsi_end_p (gsi1) && gsi_end_p (gsi2))) return; diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index 33bcca7d6f52..b324a2c97c28 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -9479,6 +9479,24 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set) } } +/* Return BB's head, unless BB is the block that succeeds ENTRY_BLOCK, + in which case it searches back from BB's head for the very first + insn. Use [get_first_insn (bb), BB_HEAD (bb->next_bb)[ as a range + to iterate over all insns of a function while iterating over its + BBs. */ + +static rtx_insn * +get_first_insn (basic_block bb) +{ + rtx_insn *insn = BB_HEAD (bb); + + if (bb->prev_bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)) + while (rtx_insn *prev = PREV_INSN (insn)) + insn = prev; + + return insn; +} + /* Emit notes for the whole function. */ static void @@ -9507,7 +9525,8 @@ vt_emit_notes (void) { /* Emit the notes for changes of variable locations between two subsequent basic blocks. */ - emit_notes_for_differences (BB_HEAD (bb), &cur, &VTI (bb)->in); + emit_notes_for_differences (get_first_insn (bb), + &cur, &VTI (bb)->in); if (MAY_HAVE_DEBUG_BIND_INSNS) local_get_addr_cache = new hash_map; @@ -10103,11 +10122,34 @@ vt_initialize (void) { HOST_WIDE_INT offset = VTI (bb)->out.stack_adjust; VTI (bb)->out.stack_adjust = VTI (bb)->in.stack_adjust; - for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); - insn = NEXT_INSN (insn)) + + /* If we are walking the first basic block, walk any HEADER + insns that might be before it too. Unfortunately, + BB_HEADER and BB_FOOTER are not set while we run this + pass. */ + insn = get_first_insn (bb); + for (rtx_insn *next; + insn != BB_HEAD (bb->next_bb) + ? next = NEXT_INSN (insn), true : false; + insn = next) { if (INSN_P (insn)) { + basic_block save_bb = BLOCK_FOR_INSN (insn); + if (!BLOCK_FOR_INSN (insn)) + { + BLOCK_FOR_INSN (insn) = bb; + gcc_assert (DEBUG_INSN_P (insn)); + /* Reset debug insns between basic blocks. + Their location is not reliable, because they + were probably not maintained up to date. */ + if (DEBUG_BIND_INSN_P (insn)) + INSN_VAR_LOCATION_LOC (insn) + = gen_rtx_UNKNOWN_VAR_LOC (); + } + else + gcc_assert (BLOCK_FOR_INSN (insn) == bb); + if (!frame_pointer_needed) { insn_stack_adjust_offset_pre_post (insn, &pre, &post); @@ -10175,6 +10217,7 @@ vt_initialize (void) } } } + BLOCK_FOR_INSN (insn) = save_bb; } } gcc_assert (offset == VTI (bb)->out.stack_adjust); @@ -10215,7 +10258,10 @@ delete_debug_insns (void) FOR_EACH_BB_FN (bb, cfun) { - FOR_BB_INSNS_SAFE (bb, insn, next) + for (insn = get_first_insn (bb); + insn != BB_HEAD (bb->next_bb) + ? next = NEXT_INSN (insn), true : false; + insn = next) if (DEBUG_INSN_P (insn)) { tree decl = INSN_VAR_LOCATION_DECL (insn); From patchwork Fri Nov 10 02:34:43 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Oliva X-Patchwork-Id: 836582 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-466474-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="YcDYvMNX"; dkim-atps=neutral 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 3yY4124CyQz9t2M for ; Fri, 10 Nov 2017 13:36:38 +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:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=qhkcKUneeerDkT5OhOTqllWMaCJe5/YKbIDPmlmNVaOcUaaMZwt82 mltWOMD9M87SfuJyBvNlOfwE5jva5WMg4d9UsWjRHjRFlZga2IuVMKQnqDamEJpq f8sk3NinIfpfamJX4FTFSNo1uBn7tC7T2FHwi3iKtsuuqefiIZIw+g= 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:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=cefe1DnSxoqFD7DGy/DDwx4rod0=; b=YcDYvMNXnCztjUjvMlMt oSqpIxM+inlJDRtqghU5ChwLy9T05+NfFpXk1TLTYEAMPwYbvwTyaexogSO2ruBt SbDZ+eCKILsymq5TNygosZGCIg8LSyVOIGXISUyCEGmSGk5tYzqUAyCyJw+Qeiik MakzIufxnXoSuJyNnlwp/Eo= Received: (qmail 96793 invoked by alias); 10 Nov 2017 02:36:15 -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 96761 invoked by uid 89); 10 Nov 2017 02:36:15 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=Weve, We've, beside 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 ESMTP; Fri, 10 Nov 2017 02:36:13 +0000 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 7B7A583F40; Fri, 10 Nov 2017 02:36:12 +0000 (UTC) Received: from freie.home (ovpn04.gateway.prod.ext.phx2.redhat.com [10.5.9.4]) by smtp.corp.redhat.com (Postfix) with ESMTPS id D042760F8C; Fri, 10 Nov 2017 02:36:09 +0000 (UTC) Received: from frit.home (frit.home [172.31.160.7]) by freie.home (8.15.2/8.15.2) with ESMTP id vAA2ZEBC003201; Fri, 10 Nov 2017 00:35:30 -0200 From: Alexandre Oliva To: Richard Biener , Jeff Law , Jason Merrill Cc: GCC Patches , Alexandre Oliva Subject: [SFN+LVU+IEPM v4 4/9] [SFN] stabilize find_bb_boundaries Date: Fri, 10 Nov 2017 00:34:43 -0200 Message-Id: <20171110023448.28164-4-aoliva@redhat.com> In-Reply-To: References: If find_bb_boundaries is given a block with zero or one nondebug insn beside debug insns, it shouldn't purge dead edges, because without debug insns we wouldn't purge them at that point. Doing so may change the order in which edges are processed, and ultimately lead to different transformations to the CFG and then to different optimizations. We shouldn't, however, retain debug insns after control flow insns, so if we find debug insns after a single insn that happens to be a control flow insn, do the debug insn cleanups, but still refrain from purging dead edges at that point. for gcc/ChangeLog * cfgbuild.c (find_bb_boundaries): Don't purge dead edges if, without debug insns, we wouldn't, but clean up debug insns after a control flow insn nevertheless. --- gcc/cfgbuild.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c index 8fa15fec45e4..7b57589f1dfa 100644 --- a/gcc/cfgbuild.c +++ b/gcc/cfgbuild.c @@ -444,10 +444,43 @@ find_bb_boundaries (basic_block bb) rtx_insn *flow_transfer_insn = NULL; rtx_insn *debug_insn = NULL; edge fallthru = NULL; + bool skip_purge; if (insn == end) return; + if (DEBUG_INSN_P (insn) || DEBUG_INSN_P (end)) + { + /* Check whether, without debug insns, the insn==end test above + would have caused us to return immediately, and behave the + same way even with debug insns. If we don't do this, debug + insns could cause us to purge dead edges at different times, + which could in turn change the cfg and affect codegen + decisions in subtle but undesirable ways. */ + while (insn != end && DEBUG_INSN_P (insn)) + insn = NEXT_INSN (insn); + rtx_insn *e = end; + while (insn != e && DEBUG_INSN_P (e)) + e = PREV_INSN (e); + if (insn == e) + { + /* If there are debug insns after a single insn that is a + control flow insn in the block, we'd have left right + away, but we should clean up the debug insns after the + control flow insn, because they can't remain in the same + block. So, do the debug insn cleaning up, but then bail + out without purging dead edges as we would if the debug + insns hadn't been there. */ + if (e != end && !DEBUG_INSN_P (e) && control_flow_insn_p (e)) + { + skip_purge = true; + flow_transfer_insn = e; + goto clean_up_debug_after_control_flow; + } + return; + } + } + if (LABEL_P (insn)) insn = NEXT_INSN (insn); @@ -475,7 +508,6 @@ find_bb_boundaries (basic_block bb) if (debug_insn && code != CODE_LABEL && code != BARRIER) prev = PREV_INSN (debug_insn); fallthru = split_block (bb, prev); - if (flow_transfer_insn) { BB_END (bb) = flow_transfer_insn; @@ -527,6 +559,9 @@ find_bb_boundaries (basic_block bb) ordinary jump, we need to take care and move basic block boundary. */ if (flow_transfer_insn && flow_transfer_insn != end) { + skip_purge = false; + + clean_up_debug_after_control_flow: BB_END (bb) = flow_transfer_insn; /* Clean up the bb field for the insns that do not belong to BB. */ @@ -543,6 +578,9 @@ find_bb_boundaries (basic_block bb) if (x == end) break; } + + if (skip_purge) + return; } /* We've possibly replaced the conditional jump by conditional jump From patchwork Fri Nov 10 02:34:44 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Oliva X-Patchwork-Id: 836585 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-466477-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="gRfF26wq"; dkim-atps=neutral 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 3yY42L1RxTz9t2M for ; Fri, 10 Nov 2017 13:37:46 +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:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=X5eaDyDf2YcOm8LCD2Hi9qCaihoD7s0e9iyFggGhsVjw01aVxvce6 cSgZk2Pab/RffUyPs6DaPtmoioiP/eL1deWzobFn8Z756q1Rv2Ol/Utnnm7a/zQr kVWlCdJn6hb9GHdHb7pOAyMUv6UnewuT0StAys7ERbsQq/L6Jq7llA= 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:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=3IN8djDXFm/QcN6z6I4fP76lh1E=; b=gRfF26wq396RmAJma8x4 NywHnT9lLV7o745PdkGNEdsN2dXSiP6KXgjvZMq1upM5vcEs+YYs5xSNt5Y1xV4/ lRoCnylOJYxqNDKqKae6eVKt13RqD+ivhaGkwNDK1NIuKznUK5xty1oNsd8JO5AJ Mpmm+yzi/jKsm+5pXXldO9Y= Received: (qmail 98793 invoked by alias); 10 Nov 2017 02:36:39 -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 98751 invoked by uid 89); 10 Nov 2017 02:36:39 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=brings, micro, Inheritance, arms 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 ESMTP; Fri, 10 Nov 2017 02:36:29 +0000 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 43FA180461; Fri, 10 Nov 2017 02:36:28 +0000 (UTC) Received: from freie.home (ovpn04.gateway.prod.ext.phx2.redhat.com [10.5.9.4]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 538B712A41; Fri, 10 Nov 2017 02:36:27 +0000 (UTC) Received: from frit.home (frit.home [172.31.160.7]) by freie.home (8.15.2/8.15.2) with ESMTP id vAA2ZEBD003201; Fri, 10 Nov 2017 00:35:37 -0200 From: Alexandre Oliva To: Richard Biener , Jeff Law , Jason Merrill Cc: GCC Patches , Alexandre Oliva Subject: [SFN+LVU+IEPM v4 5/9] [SFN] introduce statement frontier notes, still disabled Date: Fri, 10 Nov 2017 00:34:44 -0200 Message-Id: <20171110023448.28164-5-aoliva@redhat.com> In-Reply-To: References: This patch completes the infrastructure for the introduction of statement frontiers in C-family languages. It brings in all the code remaining code needed to introduce and transform begin stmt trees, gimple stmts, insns and notes, and ultimately use them to generate the is_stmt column in DWARF2+ line number tables/programs, however none of it is activated: the option that would do so will be introduced in a subsequent patch. This patch depends on an earlier patch with not-quite-boilerplate changes towards SFN. for gcc/c-family/ChangeLog * c-semantics.c (pop_stmt_list): Move begin stmt marker into subsequent statement list. for gcc/c/ChangeLog * c-objc-common.h (LANG_HOOKS_EMITS_BEGIN_STMT): Redefine as true. * c-parser.c (add_debug_begin_stmt): New. (c_parser_declaration_or_fndef): Call it. (c_parser_compound_statement_nostart): Likewise. (c_parser_statement_after_labels): Likewise. * c-typeck (c_finish_stmt_expr): Skip begin stmts markers. for gcc/cp/ChangeLog * constexpr.c (check_constexpr_ctor_body_1): Skip begin stmt markers. (constexpr_fn_retval): Likewise. (potential_constant_expression_1): Likewise. (cxx_eval_statement_list): Check that a begin stmt marker is not used as the value of a statement list. (cxx_eval_constant_expression): Return begin stmt markers unchanged. * cp-array-notation.c (stmt_location): New. (cp_expand_cond_array_notations): Use it. * cp-objcp-common.h (LANG_HOOKS_EMITS_BEGIN_STMT): Redefine as true. * parser.c (add_debug_begin_stmt): New. (cp_parser_statement): Call it. * pt.c (tsubst_copy): Handle begin stmt markers. for gcc/ChangeLog * cfgexpand.c (expand_gimple_basic_block): Handle begin stmt markers. Integrate source bind into debug stmt expand loop. (pass_expand::execute): Check debug marker limit. Avoid deep TER and expand debug locations for debug bind insns only. * cse.c (insn_live_p): Keep nonbind markers and debug bindings followed by them. * df-scan.c (df_insn_delete): Accept out-of-block debug insn. * final.c (reemit_insn_block_notes): Take current block from nonbind markers. Declare note where it's first set. (final_scan_insn): Handle begin stmt notes. Emit is_stmt according to begin stmt markers if enabled. (notice_source_line): Handle nonbind markers. Fail if their location is unknown or that of builtins. (rest_of_handle_final): Convert begin stmt markers to notes if var-tracking didn't run. (rest_of_clean_state): Skip begin stmt markers. * gimple-pretty-print.c (dump_gimple_debug): Handle begin stmt markers. * function.c (allocate_struct_function): Set begin_stmt_markers. * function.h (struct function): Add debug_marker_count counter and debug_nonbind_markers flag. * gimple-iterator.c (gsi_remove): Adjust debug_marker_count. * gimple-low.c (lower_function_body): Adjust debug_nonbind_markers. (lower_stmt): Drop or skip gimple debug stmts. (lower_try_catch): Skip debug stmts. * gimple.c (gimple_build_debug_begin_stmt): New. (gimple_copy): Increment debug_marker_count if copying one. * gimple.h (gimple_build_debug_begin_stmt): Declare. * gimplify.c (rexpr_location): New. (rexpr_has_location): New. (warn_switch_unreachable_r): Handle gimple debug stmts. (shortcut_cond_r): Call expr_location. (find_goto): New. (find_goto_label): New. (shortcut_cond_expr): Call expr_has_location, expr_location, and find_goto_label. (gimplify_cond_expr): Call find_goto_label, expr_has_location, and expr_location. (gimplify_expr): Handle begin stmt markers. Reject debug expr decls. * langhooks-def.h (LANG_HOOKS_EMITS_BEGIN_STMT): New. Add to... (LANG_HOOKS_INITIALIZER): ... this. * langhooks.h (struct lang_hooks): Add emits_begin_stmt. * lra-contraints.c (inherit_reload_reg): Tolerate between-blocks debug insns. (update_ebb_live_info): Skip debug insn markers. * lra.c (debug_insn_static_data): Rename to... (debug_bind_static_data): ... this. (debug_marker_static_data): New. (lra_set_insn_recog_data): Select one of the above depending on debug insn kind. (lra_update_isn_regno_info): Don't assume debug insns have freqs. (push_insns): Skip debug insns. * lto-streamer-in.c (input_function): Drop debug stmts depending on active options. Adjust debug_nonbind_markers. * params.def (PARAM_MAX_DEBUG_MARKER_COUNT): New. * print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle begin stmt marker notes. (print_insn): Likewise. * recog.c (extract_insn): Recognize rtl for debug markers. * rtl.def (DEBUG_MARKER): New. * tree-inline.c: Include params.h. (remap_gimple_stmt): Handle nonbind markers. (maybe_move_debug_stmts_to_successors): Likewise. (copy_debug_stmt): Likewise. * tree-iterator.c (append_to_statement_list_1): Append begin stmt markers regardless of no side effects. (tsi_link_before): Don't update container's side effects when adding a begin stmt marker. (tsi_link_after): Likewise. (expr_first): Skip begin stmt markers. (expr_last): Likewise. * tree-pretty-print (dump_generic_node): Handle begin stmt markers. * tree-ssa-threadedge.c (propagate_threaded_block_debug_info): Disregard nonbind markers. * tree.c (make_node_stat): Don't set side effects for begin stmt markers. (build1_stat): Likewise. * tree.def (DEBUG_BEGIN_STMT): New. * tree.h (GOTO_DESTINATION): Require a GOTO_EXPR. * var-tracking.c (delete_debug_insns): Renamed to... (delete_vta_debug_insns): ... this. (reemit_marker_as_note): New. (vt_initialize): Reemit markers. (delete_vta_debug_insns): Likewise. (vt_debug_insns_local): Reemit or delete markers. (variable_tracking_main_1): Likewise. * doc/generic.texi (DEBUG_BEGIN_STMT): Document. * doc/gimple.texi (gimple_debug_begin_stmt_p): New. (gimple_debug_nonbind_marker_p): New. (gimple_build_debug_bind): Adjust. (gimple_build_debug_begin_stmt): New. * doc/invoke.texi (max-debug-marker-count): New param. * doc/rtl.texi (debug_implicit_ptr, entry_value): New. (debug_parameter_ref, debug_marker): New. (NOTE_INSN_BEGIN_STMT): New. (DEBUG_INSN): Describe begin stmt markers. --- gcc/c-family/c-semantics.c | 21 ++++++ gcc/c/c-objc-common.h | 2 + gcc/c/c-parser.c | 20 ++++++ gcc/c/c-typeck.c | 8 ++- gcc/cfgexpand.c | 113 +++++++++++++++++--------------- gcc/cp/constexpr.c | 16 +++++ gcc/cp/cp-array-notation.c | 37 +++++++++-- gcc/cp/cp-objcp-common.h | 2 + gcc/cp/parser.c | 14 ++++ gcc/cp/pt.c | 6 ++ gcc/cse.c | 7 ++ gcc/df-scan.c | 2 +- gcc/doc/generic.texi | 5 ++ gcc/doc/gimple.texi | 24 ++++++- gcc/doc/invoke.texi | 7 ++ gcc/doc/rtl.texi | 53 ++++++++++++--- gcc/final.c | 89 +++++++++++++++++++------ gcc/function.c | 6 ++ gcc/function.h | 10 +++ gcc/gimple-iterator.c | 4 ++ gcc/gimple-low.c | 29 +++++++++ gcc/gimple-pretty-print.c | 7 ++ gcc/gimple.c | 24 +++++++ gcc/gimple.h | 1 + gcc/gimplify.c | 158 +++++++++++++++++++++++++++++++++++---------- gcc/langhooks-def.h | 2 + gcc/langhooks.h | 3 + gcc/lra-constraints.c | 10 ++- gcc/lra.c | 36 +++++++++-- gcc/lto-streamer-in.c | 12 +++- gcc/params.def | 9 +++ gcc/print-rtl.c | 24 +++++++ gcc/recog.c | 1 + gcc/rtl.def | 3 + gcc/tree-inline.c | 31 ++++++++- gcc/tree-iterator.c | 48 +++++++++++--- gcc/tree-pretty-print.c | 4 ++ gcc/tree-ssa-threadedge.c | 25 ++++--- gcc/tree.c | 8 ++- gcc/tree.def | 3 + gcc/tree.h | 2 +- gcc/var-tracking.c | 70 +++++++++++++++++--- 42 files changed, 798 insertions(+), 158 deletions(-) diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c index 3ceb714e4b16..cd872d8ac740 100644 --- a/gcc/c-family/c-semantics.c +++ b/gcc/c-family/c-semantics.c @@ -76,6 +76,27 @@ pop_stmt_list (tree t) free_stmt_list (t); t = u; } + /* If the statement list contained a debug begin stmt and a + statement list, move the debug begin stmt into the statement + list and return it. */ + else if (!tsi_end_p (i) + && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT) + { + u = tsi_stmt (i); + tsi_next (&i); + if (tsi_one_before_end_p (i) + && TREE_CODE (tsi_stmt (i)) == STATEMENT_LIST) + { + tree l = tsi_stmt (i); + tsi_prev (&i); + tsi_delink (&i); + tsi_delink (&i); + i = tsi_start (l); + free_stmt_list (t); + t = l; + tsi_link_before (&i, u, TSI_SAME_STMT); + } + } } return t; diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h index bee06e9a37ef..27ceabcdfb2f 100644 --- a/gcc/c/c-objc-common.h +++ b/gcc/c/c-objc-common.h @@ -60,6 +60,8 @@ along with GCC; see the file COPYING3. If not see #define LANG_HOOKS_BUILTIN_FUNCTION c_builtin_function #undef LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE #define LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE c_builtin_function_ext_scope +#undef LANG_HOOKS_EMITS_BEGIN_STMT +#define LANG_HOOKS_EMITS_BEGIN_STMT true /* Attribute hooks. */ #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 7bca5f1a2a7c..9903c5a1506a 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1659,6 +1659,19 @@ c_parser_external_declaration (c_parser *parser) static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec); static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool); +/* Build and add a DEBUG_BEGIN_STMT statement with location LOC. */ + +static void +add_debug_begin_stmt (location_t loc) +{ + if (!MAY_HAVE_DEBUG_MARKER_STMTS) + return; + + tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node); + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); +} + /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 6.7, 6.9.1, C11 6.7, 6.9.1). If FNDEF_OK is true, a function definition is accepted; otherwise (old-style parameter declarations) only other @@ -1759,6 +1772,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool diagnosed_no_specs = false; location_t here = c_parser_peek_token (parser)->location; + add_debug_begin_stmt (c_parser_peek_token (parser)->location); + if (static_assert_ok && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)) { @@ -5026,6 +5041,7 @@ c_parser_compound_statement_nostart (c_parser *parser) location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { + add_debug_begin_stmt (c_parser_peek_token (parser)->location); c_parser_consume_token (parser); return; } @@ -5480,6 +5496,10 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p, parser->in_if_block = false; if (if_p != NULL) *if_p = false; + + if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE) + add_debug_begin_stmt (loc); + switch (c_parser_peek_token (parser)->type) { case CPP_OPEN_BRACE: diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 4bdc48a9ea38..3f01b482bf20 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -10761,6 +10761,10 @@ c_finish_stmt_expr (location_t loc, tree body) } else i = tsi_last (last); + if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT) + do + tsi_prev (&i); + while (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT); last_p = tsi_stmt_ptr (i); last = *last_p; } @@ -10780,7 +10784,9 @@ c_finish_stmt_expr (location_t loc, tree body) /* In the case that the BIND_EXPR is not necessary, return the expression out from inside it. */ - if (last == BIND_EXPR_BODY (body) + if ((last == BIND_EXPR_BODY (body) + /* Skip nested debug stmts. */ + || last == expr_first (BIND_EXPR_BODY (body))) && BIND_EXPR_VARS (body) == NULL) { /* Even if this looks constant, do not allow it in a constant diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 6f64897d0688..3f17e90d50b3 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -5659,39 +5659,68 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls) if (new_bb) return new_bb; } - else if (gimple_debug_bind_p (stmt)) + else if (is_gimple_debug (stmt)) { location_t sloc = curr_insn_location (); gimple_stmt_iterator nsi = gsi; for (;;) { - tree var = gimple_debug_bind_get_var (stmt); - tree value; - rtx val; + tree var; + tree value = NULL_TREE; + rtx val = NULL_RTX; machine_mode mode; - if (TREE_CODE (var) != DEBUG_EXPR_DECL - && TREE_CODE (var) != LABEL_DECL - && !target_for_debug_bind (var)) - goto delink_debug_stmt; + if (!gimple_debug_nonbind_marker_p (stmt)) + { + if (gimple_debug_bind_p (stmt)) + { + var = gimple_debug_bind_get_var (stmt); - if (gimple_debug_bind_has_value_p (stmt)) - value = gimple_debug_bind_get_value (stmt); - else - value = NULL_TREE; + if (TREE_CODE (var) != DEBUG_EXPR_DECL + && TREE_CODE (var) != LABEL_DECL + && !target_for_debug_bind (var)) + goto delink_debug_stmt; - last = get_last_insn (); + if (DECL_P (var)) + mode = DECL_MODE (var); + else + mode = TYPE_MODE (TREE_TYPE (var)); - set_curr_insn_location (gimple_location (stmt)); + if (gimple_debug_bind_has_value_p (stmt)) + value = gimple_debug_bind_get_value (stmt); + + val = gen_rtx_VAR_LOCATION + (mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED); + } + else if (gimple_debug_source_bind_p (stmt)) + { + var = gimple_debug_source_bind_get_var (stmt); + + value = gimple_debug_source_bind_get_value (stmt); + + mode = DECL_MODE (var); - if (DECL_P (var)) - mode = DECL_MODE (var); + val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value, + VAR_INIT_STATUS_UNINITIALIZED); + } + else + gcc_unreachable (); + } + /* If this function was first compiled with markers + enabled, but they're now disable (e.g. LTO), drop + them on the floor. */ + else if (gimple_debug_nonbind_marker_p (stmt) + && !MAY_HAVE_DEBUG_MARKER_INSNS) + goto delink_debug_stmt; + else if (gimple_debug_begin_stmt_p (stmt)) + val = GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT (); else - mode = TYPE_MODE (TREE_TYPE (var)); + gcc_unreachable (); - val = gen_rtx_VAR_LOCATION - (mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED); + last = get_last_insn (); + + set_curr_insn_location (gimple_location (stmt)); emit_debug_insn (val); @@ -5699,9 +5728,14 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls) { /* We can't dump the insn with a TREE where an RTX is expected. */ - PAT_VAR_LOCATION_LOC (val) = const0_rtx; + if (GET_CODE (val) == VAR_LOCATION) + { + gcc_checking_assert (PAT_VAR_LOCATION_LOC (val) == (rtx)value); + PAT_VAR_LOCATION_LOC (val) = const0_rtx; + } maybe_dump_rtl_for_gimple_stmt (stmt, last); - PAT_VAR_LOCATION_LOC (val) = (rtx)value; + if (GET_CODE (val) == VAR_LOCATION) + PAT_VAR_LOCATION_LOC (val) = (rtx)value; } delink_debug_stmt: @@ -5717,42 +5751,12 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls) if (gsi_end_p (nsi)) break; stmt = gsi_stmt (nsi); - if (!gimple_debug_bind_p (stmt)) + if (!is_gimple_debug (stmt)) break; } set_curr_insn_location (sloc); } - else if (gimple_debug_source_bind_p (stmt)) - { - location_t sloc = curr_insn_location (); - tree var = gimple_debug_source_bind_get_var (stmt); - tree value = gimple_debug_source_bind_get_value (stmt); - rtx val; - machine_mode mode; - - last = get_last_insn (); - - set_curr_insn_location (gimple_location (stmt)); - - mode = DECL_MODE (var); - - val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value, - VAR_INIT_STATUS_UNINITIALIZED); - - emit_debug_insn (val); - - if (dump_file && (dump_flags & TDF_DETAILS)) - { - /* We can't dump the insn with a TREE where an RTX - is expected. */ - PAT_VAR_LOCATION_LOC (val) = const0_rtx; - maybe_dump_rtl_for_gimple_stmt (stmt, last); - PAT_VAR_LOCATION_LOC (val) = (rtx)value; - } - - set_curr_insn_location (sloc); - } else { gcall *call_stmt = dyn_cast (stmt); @@ -6385,6 +6389,11 @@ pass_expand::execute (function *fun) FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs) e->flags &= ~EDGE_EXECUTABLE; + /* If the function has too many markers, drop them while expanding. */ + if (cfun->debug_marker_count + >= PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT)) + cfun->debug_nonbind_markers = false; + lab_rtx_for_bb = new hash_map; FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR_FOR_FN (fun), next_bb) diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 670aae22dd66..b03337fe0e58 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -455,6 +455,7 @@ check_constexpr_ctor_body_1 (tree last, tree list) case USING_STMT: case STATIC_ASSERT: + case DEBUG_BEGIN_STMT: return true; default: @@ -694,6 +695,7 @@ constexpr_fn_retval (tree body) return constexpr_fn_retval (BIND_EXPR_BODY (body)); case USING_STMT: + case DEBUG_BEGIN_STMT: return NULL_TREE; case CALL_EXPR: @@ -3818,6 +3820,14 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t, if (returns (jump_target) || breaks (jump_target)) break; } + /* Make sure we don't use the "result" of a debug-only marker. That + would be wrong. We should be using the result of the previous + statement, or NULL if there isn't one. In practice, this should + never happen: the statement after the marker should override the + result of the marker, so its value shouldn't survive in R. Now, + should that ever change, we'll need some fixing here to stop + markers from modifying the generated executable code. */ + gcc_checking_assert (!r || TREE_CODE (r) != DEBUG_BEGIN_STMT); return r; } @@ -4043,6 +4053,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, } break; + case DEBUG_BEGIN_STMT: + /* ??? It might be nice to retain this information somehow, so + as to be able to step into a constexpr function call. */ + /* Fall through. */ + case FUNCTION_DECL: case TEMPLATE_DECL: case LABEL_DECL: @@ -5146,6 +5161,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case CONTINUE_STMT: case REQUIRES_EXPR: case STATIC_ASSERT: + case DEBUG_BEGIN_STMT: return true; case PARM_DECL: diff --git a/gcc/cp/cp-array-notation.c b/gcc/cp/cp-array-notation.c index 31be7d685ba7..17f0b35cc56c 100644 --- a/gcc/cp/cp-array-notation.c +++ b/gcc/cp/cp-array-notation.c @@ -780,6 +780,31 @@ error: return error_mark_node; } +/* Return a location associated with stmt. If it is an expresion, + that's the expression's location. If it is a STATEMENT_LIST, + instead of no location, use expr_first to skip any debug stmts and + take the location of the first nondebug stmt found. */ + +static location_t +stmt_location (tree stmt) +{ + location_t loc = UNKNOWN_LOCATION; + + if (!stmt) + return loc; + + loc = EXPR_LOCATION (stmt); + + if (loc != UNKNOWN_LOCATION || TREE_CODE (stmt) != STATEMENT_LIST) + return loc; + + stmt = expr_first (stmt); + if (stmt) + loc = EXPR_LOCATION (stmt); + + return loc; +} + /* Helper function for expand_conditonal_array_notations. Encloses the conditional statement passed in ORIG_STMT with a loop around it and replaces the condition in STMT with a ARRAY_REF tree-node to the array. @@ -835,10 +860,12 @@ cp_expand_cond_array_notations (tree orig_stmt) tree cond = IF_COND (orig_stmt); if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank) || (yes_expr - && !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true, + && !find_rank (stmt_location (yes_expr), + yes_expr, yes_expr, true, &yes_rank)) || (no_expr - && !find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true, + && !find_rank (stmt_location (no_expr), + no_expr, no_expr, true, &no_rank))) return error_mark_node; @@ -847,13 +874,15 @@ cp_expand_cond_array_notations (tree orig_stmt) return orig_stmt; else if (cond_rank != yes_rank && yes_rank != 0) { - error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling" + error_at (stmt_location (yes_expr), + "rank mismatch with controlling" " expression of parent if-statement"); return error_mark_node; } else if (cond_rank != no_rank && no_rank != 0) { - error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling " + error_at (stmt_location (no_expr), + "rank mismatch with controlling " "expression of parent if-statement"); return error_mark_node; } diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h index 3e4cc9c5d4ce..c1c82b61d5eb 100644 --- a/gcc/cp/cp-objcp-common.h +++ b/gcc/cp/cp-objcp-common.h @@ -105,6 +105,8 @@ extern void cp_register_dumps (gcc::dump_manager *); #define LANG_HOOKS_MISSING_NORETURN_OK_P cp_missing_noreturn_ok_p #undef LANG_HOOKS_BLOCK_MAY_FALLTHRU #define LANG_HOOKS_BLOCK_MAY_FALLTHRU cxx_block_may_fallthru +#undef LANG_HOOKS_EMITS_BEGIN_STMT +#define LANG_HOOKS_EMITS_BEGIN_STMT true /* Attribute hooks. */ #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 77b96376e136..a792e78e3dcf 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -10775,6 +10775,19 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) /* Statements [gram.stmt.stmt] */ +/* Build and add a DEBUG_BEGIN_STMT statement with location LOC. */ + +static void +add_debug_begin_stmt (location_t loc) +{ + if (!MAY_HAVE_DEBUG_MARKER_STMTS) + return; + + tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node); + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); +} + /* Parse a statement. statement: @@ -10850,6 +10863,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, token = cp_lexer_peek_token (parser->lexer); /* Remember the location of the first token in the statement. */ statement_location = token->location; + add_debug_begin_stmt (statement_location); /* If this is a keyword, then that will often determine what kind of statement we have. */ if (token->type == CPP_KEYWORD) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 710333ddabac..ad335bc08632 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -15284,6 +15284,12 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) case PREDICT_EXPR: return t; + case DEBUG_BEGIN_STMT: + /* ??? There's no point in copying it for now, but maybe some + day it will contain more information, such as a pointer back + to the containing function, inlined copy or so. */ + return t; + default: /* We shouldn't get here, but keep going if !flag_checking. */ if (flag_checking) diff --git a/gcc/cse.c b/gcc/cse.c index e449223cbb25..c0db32b9f11d 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -6962,11 +6962,18 @@ insn_live_p (rtx_insn *insn, int *counts) { rtx_insn *next; + if (DEBUG_MARKER_INSN_P (insn)) + return true; + for (next = NEXT_INSN (insn); next; next = NEXT_INSN (next)) if (NOTE_P (next)) continue; else if (!DEBUG_INSN_P (next)) return true; + /* If we find an inspection point, such as a debug begin stmt, + we want to keep the earlier debug insn. */ + else if (DEBUG_MARKER_INSN_P (next)) + return true; else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next)) return false; diff --git a/gcc/df-scan.c b/gcc/df-scan.c index 8ab3d716ea29..429dab8a99b4 100644 --- a/gcc/df-scan.c +++ b/gcc/df-scan.c @@ -945,7 +945,7 @@ df_insn_delete (rtx_insn *insn) In any case, we expect BB to be non-NULL at least up to register allocation, so disallow a non-NULL BB up to there. Not perfect but better than nothing... */ - gcc_checking_assert (bb != NULL || reload_completed); + gcc_checking_assert (bb != NULL || DEBUG_INSN_P (insn) || reload_completed); df_grow_bb_info (df_scan); df_grow_reg_info (); diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi index a51cfd6e9557..a13bce94020a 100644 --- a/gcc/doc/generic.texi +++ b/gcc/doc/generic.texi @@ -1930,6 +1930,11 @@ case 2 ... 5: The first value will be @code{CASE_LOW}, while the second will be @code{CASE_HIGH}. +@item DEBUG_BEGIN_STMT + +Marks the beginning of a source statement, for purposes of debug +information generation. + @end table diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi index fa98800a675b..492678705c6f 100644 --- a/gcc/doc/gimple.texi +++ b/gcc/doc/gimple.texi @@ -831,6 +831,16 @@ expression to a variable. Return true if g is any of the OpenMP codes. @end deftypefn +@deftypefn {GIMPLE function} gimple_debug_begin_stmt_p (gimple g) +Return true if g is a @code{GIMPLE_DEBUG} that marks the beginning of +a source statement. +@end deftypefn + +@deftypefn {GIMPLE function} gimple_debug_nonbind_marker_p (gimple g) +Return true if g is a @code{GIMPLE_DEBUG} that marks a program location, +without any variable binding. +@end deftypefn + @node Manipulating GIMPLE statements @section Manipulating GIMPLE statements @cindex Manipulating GIMPLE statements @@ -1530,10 +1540,11 @@ Set the conditional @code{COND_STMT} to be of the form 'if (1 == 1)'. @subsection @code{GIMPLE_DEBUG} @cindex @code{GIMPLE_DEBUG} @cindex @code{GIMPLE_DEBUG_BIND} +@cindex @code{GIMPLE_DEBUG_BEGIN_STMT} @deftypefn {GIMPLE function} gdebug *gimple_build_debug_bind (tree var, @ tree value, gimple stmt) -Build a @code{GIMPLE_DEBUG} statement with @code{GIMPLE_DEBUG_BIND} of +Build a @code{GIMPLE_DEBUG} statement with @code{GIMPLE_DEBUG_BIND} @code{subcode}. The effect of this statement is to tell debug information generation machinery that the value of user variable @code{var} is given by @code{value} at that point, and to remain with @@ -1604,6 +1615,17 @@ Return @code{TRUE} if @code{stmt} binds a user variable to a value, and @code{FALSE} if it unbinds the variable. @end deftypefn +@deftypefn {GIMPLE function} gimple gimple_build_debug_begin_stmt (tree block, location_t location) +Build a @code{GIMPLE_DEBUG} statement with +@code{GIMPLE_DEBUG_BEGIN_STMT} @code{subcode}. The effect of this +statement is to tell debug information generation machinery that the +user statement at the given @code{location} and @code{block} starts at +the point at which the statement is inserted. The intent is that side +effects (e.g. variable bindings) of all prior user statements are +observable, and that none of the side effects of subsequent user +statements are. +@end deftypefn + @node @code{GIMPLE_EH_FILTER} @subsection @code{GIMPLE_EH_FILTER} @cindex @code{GIMPLE_EH_FILTER} diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index e897d93070ae..6ff7c34cdd6c 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -10529,6 +10529,13 @@ debug information may end up not being used; setting this higher may enable the compiler to find more complex debug expressions, but compile time and memory use may grow. The default is 12. +@item max-debug-marker-count +Sets a threshold on the number of debug markers (e.g. begin stmt +markers) to avoid complexity explosion at inlining or expanding to RTL. +If a function has more such gimple stmts than the set limit, such stmts +will be dropped from the inlined copy of a function, and from its RTL +expansion. The default is 100000. + @item min-nondebug-insn-uid Use uids starting at this parameter for nondebug insns. The range below the parameter is reserved exclusively for debug insns created by diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi index 21524f546964..898574a01ad0 100644 --- a/gcc/doc/rtl.texi +++ b/gcc/doc/rtl.texi @@ -3436,6 +3436,25 @@ Stands for the value bound to the @code{DEBUG_EXPR_DECL} @var{decl}, that points back to it, within value expressions in @code{VAR_LOCATION} nodes. +@findex debug_implicit_ptr +@item (debug_implicit_ptr:@var{mode} @var{decl}) +Stands for the location of a @var{decl} that is no longer addressable. + +@findex entry_value +@item (entry_value:@var{mode} @var{decl}) +Stands for the value a @var{decl} had at the entry point of the +containing function. + +@findex debug_parameter_ref +@item (debug_parameter_ref:@var{mode} @var{decl}) +Refers to a parameter that was completely optimized out. + +@findex debug_marker +@item (debug_marker:@var{mode}) +Marks a program location. With @code{VOIDmode}, it stands for the +beginning of a statement, a recommended inspection point logically after +all prior side effects, and before any subsequent side effects. + @end table @node Insns @@ -3712,6 +3731,12 @@ can be computed by evaluating the RTL expression from that static point in the program up to the next such note for the same user variable. +@findex NOTE_INSN_BEGIN_STMT +@item NOTE_INSN_BEGIN_STMT +This note is used to generate @code{is_stmt} markers in line number +debuggign information. It indicates the beginning of a user +statement. + @end table These codes are printed symbolically when they appear in debugging dumps. @@ -3729,15 +3754,25 @@ binds a user variable tree to an RTL representation of the it stands for the value bound to the corresponding @code{DEBUG_EXPR_DECL}. -Throughout optimization passes, binding information is kept in -pseudo-instruction form, so that, unlike notes, it gets the same -treatment and adjustments that regular instructions would. It is the -variable tracking pass that turns these pseudo-instructions into var -location notes, analyzing control flow, value equivalences and changes -to registers and memory referenced in value expressions, propagating -the values of debug temporaries and determining expressions that can -be used to compute the value of each user variable at as many points -(ranges, actually) in the program as possible. +@code{GIMPLE_DEBUG_BEGIN_STMT} is expanded to RTL as a @code{DEBUG_INSN} +with a @code{VOIDmode} @code{DEBUG_MARKER} @code{PATTERN}. These +@code{DEBUG_INSN}s, that do not carry @code{VAR_LOCATION} information, +just @code{DEBUG_MARKER}s, can be detected by testing +@code{DEBUG_MARKER_INSN_P}, whereas those that do can be recognized as +@code{DEBUG_BIND_INSN_P}. + +Throughout optimization passes, @code{DEBUG_INSN}s are not reordered +with respect to each other, particularly during scheduling. Binding +information is kept in pseudo-instruction form, so that, unlike notes, +it gets the same treatment and adjustments that regular instructions +would. It is the variable tracking pass that turns these +pseudo-instructions into @code{NOTE_INSN_VAR_LOCATION} and +@code{NOTE_INSN_BEGIN_STMT} notes, +analyzing control flow, value equivalences and changes to registers and +memory referenced in value expressions, propagating the values of debug +temporaries and determining expressions that can be used to compute the +value of each user variable at as many points (ranges, actually) in the +program as possible. Unlike @code{NOTE_INSN_VAR_LOCATION}, the value expression in an @code{INSN_VAR_LOCATION} denotes a value at that specific point in the diff --git a/gcc/final.c b/gcc/final.c index 039c37a31352..b343063faa6d 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -1646,7 +1646,6 @@ reemit_insn_block_notes (void) { tree cur_block = DECL_INITIAL (cfun->decl); rtx_insn *insn; - rtx_note *note; insn = get_insns (); for (; insn; insn = NEXT_INSN (insn)) @@ -1654,17 +1653,29 @@ reemit_insn_block_notes (void) tree this_block; /* Prevent lexical blocks from straddling section boundaries. */ - if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS) - { - for (tree s = cur_block; s != DECL_INITIAL (cfun->decl); - s = BLOCK_SUPERCONTEXT (s)) - { - rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn); - NOTE_BLOCK (note) = s; - note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn); - NOTE_BLOCK (note) = s; - } - } + if (NOTE_P (insn)) + switch (NOTE_KIND (insn)) + { + case NOTE_INSN_SWITCH_TEXT_SECTIONS: + { + for (tree s = cur_block; s != DECL_INITIAL (cfun->decl); + s = BLOCK_SUPERCONTEXT (s)) + { + rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn); + NOTE_BLOCK (note) = s; + note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn); + NOTE_BLOCK (note) = s; + } + } + break; + + case NOTE_INSN_BEGIN_STMT: + this_block = LOCATION_BLOCK (NOTE_MARKER_LOCATION (insn)); + goto set_cur_block_to_this_block; + + default: + continue; + } if (!active_insn_p (insn)) continue; @@ -1685,6 +1696,7 @@ reemit_insn_block_notes (void) this_block = choose_inner_scope (this_block, insn_scope (body->insn (i))); } + set_cur_block_to_this_block: if (! this_block) { if (INSN_LOCATION (insn) == UNKNOWN_LOCATION) @@ -1701,7 +1713,7 @@ reemit_insn_block_notes (void) } /* change_scope emits before the insn, not after. */ - note = emit_note (NOTE_INSN_DELETED); + rtx_note *note = emit_note (NOTE_INSN_DELETED); change_scope (note, cur_block, DECL_INITIAL (cfun->decl)); delete_insn (note); @@ -2400,6 +2412,17 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, debug_hooks->var_location (insn); break; + case NOTE_INSN_BEGIN_STMT: + gcc_checking_assert (cfun->debug_nonbind_markers); + if (!DECL_IGNORED_P (current_function_decl) + && notice_source_line (insn, NULL)) + { + (*debug_hooks->source_line) (last_linenum, last_columnnum, + last_filename, last_discriminator, + true); + } + break; + default: gcc_unreachable (); break; @@ -2486,7 +2509,15 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, rtx body = PATTERN (insn); int insn_code_number; const char *templ; - bool is_stmt; + bool is_stmt, *is_stmt_p; + + if (MAY_HAVE_DEBUG_MARKER_INSNS && cfun->debug_nonbind_markers) + { + is_stmt = false; + is_stmt_p = NULL; + } + else + is_stmt_p = &is_stmt; /* Reset this early so it is correct for ASM statements. */ current_insn_predicate = NULL_RTX; @@ -2589,7 +2620,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, /* Output this line note if it is the first or the last line note in a row. */ if (!DECL_IGNORED_P (current_function_decl) - && notice_source_line (insn, &is_stmt)) + && notice_source_line (insn, is_stmt_p)) { if (flag_verbose_asm) asm_show_source (last_filename, last_linenum); @@ -3082,7 +3113,22 @@ notice_source_line (rtx_insn *insn, bool *is_stmt) const char *filename; int linenum, columnnum; - if (override_filename) + if (NOTE_MARKER_P (insn)) + { + location_t loc = NOTE_MARKER_LOCATION (insn); + expanded_location xloc = expand_location (loc); + if (xloc.line == 0) + { + gcc_checking_assert (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION + || LOCATION_LOCUS (loc) == BUILTINS_LOCATION); + return false; + } + filename = xloc.file; + linenum = xloc.line; + columnnum = xloc.column; + force_source_line = true; + } + else if (override_filename) { filename = override_filename; linenum = override_linenum; @@ -3115,7 +3161,8 @@ notice_source_line (rtx_insn *insn, bool *is_stmt) last_linenum = linenum; last_columnnum = columnnum; last_discriminator = discriminator; - *is_stmt = true; + if (is_stmt) + *is_stmt = true; high_block_linenum = MAX (last_linenum, high_block_linenum); high_function_linenum = MAX (last_linenum, high_function_linenum); return true; @@ -3127,7 +3174,8 @@ notice_source_line (rtx_insn *insn, bool *is_stmt) output the line table entry with is_stmt false so the debugger does not treat this as a breakpoint location. */ last_discriminator = discriminator; - *is_stmt = false; + if (is_stmt) + *is_stmt = false; return true; } @@ -4472,6 +4520,10 @@ rest_of_handle_final (void) { const char *fnname = get_fnname_from_decl (current_function_decl); + /* Turn debug markers into notes. */ + if (!MAY_HAVE_DEBUG_BIND_INSNS && MAY_HAVE_DEBUG_MARKER_INSNS) + variable_tracking_main (); + assemble_start_function (current_function_decl, fnname); final_start_function (get_insns (), asm_out_file, optimize); final (get_insns (), asm_out_file, optimize); @@ -4659,6 +4711,7 @@ rest_of_clean_state (void) if (final_output && (!NOTE_P (insn) || (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION + && NOTE_KIND (insn) != NOTE_INSN_BEGIN_STMT && NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END diff --git a/gcc/function.c b/gcc/function.c index 2f9f83117143..80f854b494e8 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -4932,6 +4932,12 @@ allocate_struct_function (tree fndecl, bool abstract_p) if (!profile_flag && !flag_instrument_function_entry_exit) DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1; } + + /* Don't enable begin stmt markers if var-tracking at assignments is + disabled. The markers make little sense without the variable + binding annotations among them. */ + cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt + && MAY_HAVE_DEBUG_MARKER_STMTS; } /* This is like allocate_struct_function, but pushes a new cfun for FNDECL diff --git a/gcc/function.h b/gcc/function.h index 76434cd59a50..1186116fc0b5 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -284,6 +284,12 @@ struct GTY(()) function { /* Last statement uid. */ int last_stmt_uid; + /* Debug marker counter. Count begin stmt markers. We don't have + to keep it exact, it's more of a rough estimate to enable us to + decide whether they are too many to copy during inlining, or when + expanding to RTL. */ + int debug_marker_count; + /* Function sequence number for profiling, debugging, etc. */ int funcdef_no; @@ -387,6 +393,10 @@ struct GTY(()) function { /* Set when the tail call has been identified. */ unsigned int tail_call_marked : 1; + + /* Set when the function was compiled with generation of debug + (begin stmt, inline entry, ...) markers enabled. */ + unsigned int debug_nonbind_markers : 1; }; /* Add the decl D to the local_decls list of FUN. */ diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c index fb75f993e9a1..2359760e9c24 100644 --- a/gcc/gimple-iterator.c +++ b/gcc/gimple-iterator.c @@ -573,6 +573,10 @@ gsi_remove (gimple_stmt_iterator *i, bool remove_permanently) if (remove_permanently) { + if (gimple_debug_nonbind_marker_p (stmt)) + /* We don't need this to be exact, but try to keep it at least + close. */ + cfun->debug_marker_count--; require_eh_edge_purge = remove_stmt_from_eh_lp (stmt); gimple_remove_stmt_histograms (cfun, stmt); } diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index 22db61bbd48a..95f3f4561f9f 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -110,6 +110,17 @@ lower_function_body (void) i = gsi_last (lowered_body); + /* If we had begin stmt markers from e.g. PCH, but this compilation + doesn't want them, lower_stmt will have cleaned them up; we can + now clear the flag that indicates we had them. */ + if (!MAY_HAVE_DEBUG_MARKER_STMTS && cfun->debug_nonbind_markers) + { + /* This counter needs not be exact, but before lowering it will + most certainly be. */ + gcc_assert (cfun->debug_marker_count == 0); + cfun->debug_nonbind_markers = false; + } + /* If the function falls off the end, we need a null return statement. If we've already got one in the return_statements vector, we don't need to do anything special. Otherwise build one by hand. */ @@ -296,6 +307,20 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) } break; + case GIMPLE_DEBUG: + gcc_checking_assert (cfun->debug_nonbind_markers); + /* We can't possibly have debug bind stmts before lowering, we + first emit them when entering SSA. */ + gcc_checking_assert (gimple_debug_nonbind_marker_p (stmt)); + /* Propagate fallthruness. */ + /* If the function (e.g. from PCH) had debug stmts, but they're + disabled for this compilation, remove them. */ + if (!MAY_HAVE_DEBUG_MARKER_STMTS) + gsi_remove (gsi, true); + else + gsi_next (gsi); + return; + case GIMPLE_NOP: case GIMPLE_ASM: case GIMPLE_ASSIGN: @@ -503,6 +528,10 @@ lower_try_catch (gimple_stmt_iterator *gsi, struct lower_data *data) cannot_fallthru = false; break; + case GIMPLE_DEBUG: + gcc_checking_assert (gimple_debug_begin_stmt_p (stmt)); + break; + default: /* This case represents statements to be executed when an exception occurs. Those statements are implicitly followed diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 55c623e37bb4..61b1f2c89cbb 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1363,6 +1363,13 @@ dump_gimple_debug (pretty_printer *buffer, gdebug *gs, int spc, gimple_debug_source_bind_get_value (gs)); break; + case GIMPLE_DEBUG_BEGIN_STMT: + if (flags & TDF_RAW) + dump_gimple_fmt (buffer, spc, flags, "%G BEGIN_STMT", gs); + else + dump_gimple_fmt (buffer, spc, flags, "# DEBUG BEGIN_STMT"); + break; + default: gcc_unreachable (); } diff --git a/gcc/gimple.c b/gcc/gimple.c index 37f2248f224d..66496d002a8d 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -852,6 +852,27 @@ gimple_build_debug_source_bind (tree var, tree value, } +/* Build a new GIMPLE_DEBUG_BEGIN_STMT statement in BLOCK at + LOCATION. */ + +gdebug * +gimple_build_debug_begin_stmt (tree block, location_t location + MEM_STAT_DECL) +{ + gdebug *p + = as_a ( + gimple_build_with_ops_stat (GIMPLE_DEBUG, + (unsigned)GIMPLE_DEBUG_BEGIN_STMT, 0 + PASS_MEM_STAT)); + + gimple_set_location (p, location); + gimple_set_block (p, block); + cfun->debug_marker_count++; + + return p; +} + + /* Build a GIMPLE_OMP_CRITICAL statement. BODY is the sequence of statements for which only one thread can execute. @@ -1914,6 +1935,9 @@ gimple_copy (gimple *stmt) gimple_set_modified (copy, true); } + if (gimple_debug_nonbind_marker_p (stmt)) + cfun->debug_marker_count++; + return copy; } diff --git a/gcc/gimple.h b/gcc/gimple.h index 103d9555e465..f44887ad7a9b 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -1455,6 +1455,7 @@ gswitch *gimple_build_switch (tree, tree, vec ); geh_dispatch *gimple_build_eh_dispatch (int); gdebug *gimple_build_debug_bind (tree, tree, gimple * CXX_MEM_STAT_INFO); gdebug *gimple_build_debug_source_bind (tree, tree, gimple * CXX_MEM_STAT_INFO); +gdebug *gimple_build_debug_begin_stmt (tree, location_t CXX_MEM_STAT_INFO); gomp_critical *gimple_build_omp_critical (gimple_seq, tree, tree); gomp_for *gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq); gomp_parallel *gimple_build_omp_parallel (gimple_seq, tree, tree, tree); diff --git a/gcc/gimplify.c b/gcc/gimplify.c index d252af04bcbf..78c7ba57ef8c 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -984,6 +984,48 @@ unshare_expr_without_location (tree expr) walk_tree (&expr, prune_expr_location, NULL, NULL); return expr; } + +/* Return the EXPR_LOCATION of EXPR, if it (maybe recursively) has + one, OR_ELSE otherwise. The location of a STATEMENT_LISTs + comprising at least one DEBUG_BEGIN_STMT followed by exactly one + EXPR is the location of the EXPR. */ + +static location_t +rexpr_location (tree expr, location_t or_else = UNKNOWN_LOCATION) +{ + if (!expr) + return or_else; + + if (EXPR_HAS_LOCATION (expr)) + return EXPR_LOCATION (expr); + + if (TREE_CODE (expr) != STATEMENT_LIST) + return or_else; + + tree_stmt_iterator i = tsi_start (expr); + + bool found = false; + while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT) + { + found = true; + tsi_next (&i); + } + + if (!found || !tsi_one_before_end_p (i)) + return or_else; + + return rexpr_location (tsi_stmt (i), or_else); +} + +/* Return TRUE iff EXPR (maybe recursively) has a location; see + rexpr_location for the potential recursion. */ + +static inline bool +rexpr_has_location (tree expr) +{ + return rexpr_location (expr) != UNKNOWN_LOCATION; +} + /* WRAPPER is a code such as BIND_EXPR or CLEANUP_POINT_EXPR which can both contain statements and have a value. Assign its value to a temporary @@ -1774,6 +1816,13 @@ warn_switch_unreachable_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, /* Walk the sub-statements. */ *handled_ops_p = false; break; + + case GIMPLE_DEBUG: + /* Ignore these. We may generate them before declarations that + are never executed. If there's something to warn about, + there will be non-debug stmts too, and we'll catch those. */ + break; + case GIMPLE_CALL: if (gimple_call_internal_p (stmt, IFN_ASAN_MARK)) { @@ -3443,7 +3492,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p, append_to_statement_list (t, &expr); /* Set the source location of the && on the second 'if'. */ - new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus; + new_locus = rexpr_location (pred, locus); t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p, new_locus); append_to_statement_list (t, &expr); @@ -3466,7 +3515,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p, append_to_statement_list (t, &expr); /* Set the source location of the || on the second 'if'. */ - new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus; + new_locus = rexpr_location (pred, locus); t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p, new_locus); append_to_statement_list (t, &expr); @@ -3488,7 +3537,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p, /* Keep the original source location on the first 'if'. Set the source location of the ? on the second 'if'. */ - new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus; + new_locus = rexpr_location (pred, locus); expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0), shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p, locus), @@ -3512,6 +3561,45 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p, return expr; } +/* If EXPR is a GOTO_EXPR, return it. If it is a STATEMENT_LIST, skip + any of its leading DEBUG_BEGIN_STMTS and recurse on the subsequent + statement, if it is the last one. Otherwise, return NULL. */ + +static tree +find_goto (tree expr) +{ + if (!expr) + return NULL_TREE; + + if (TREE_CODE (expr) == GOTO_EXPR) + return expr; + + if (TREE_CODE (expr) != STATEMENT_LIST) + return NULL_TREE; + + tree_stmt_iterator i = tsi_start (expr); + + while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT) + tsi_next (&i); + + if (!tsi_one_before_end_p (i)) + return NULL_TREE; + + return find_goto (tsi_stmt (i)); +} + +/* Same as find_goto, except that it returns NULL if the destination + is not a LABEL_DECL. */ + +static inline tree +find_goto_label (tree expr) +{ + tree dest = find_goto (expr); + if (dest && TREE_CODE (GOTO_DESTINATION (dest)) == LABEL_DECL) + return dest; + return NULL_TREE; +} + /* Given a conditional expression EXPR with short-circuit boolean predicates using TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR, break the predicate apart into the equivalent sequence of conditionals. */ @@ -3542,8 +3630,8 @@ shortcut_cond_expr (tree expr) location_t locus = EXPR_LOC_OR_LOC (expr, input_location); TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1); /* Set the source location of the && on the second 'if'. */ - if (EXPR_HAS_LOCATION (pred)) - SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred)); + if (rexpr_has_location (pred)) + SET_EXPR_LOCATION (expr, rexpr_location (pred)); then_ = shortcut_cond_expr (expr); then_se = then_ && TREE_SIDE_EFFECTS (then_); pred = TREE_OPERAND (pred, 0); @@ -3564,8 +3652,8 @@ shortcut_cond_expr (tree expr) location_t locus = EXPR_LOC_OR_LOC (expr, input_location); TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1); /* Set the source location of the || on the second 'if'. */ - if (EXPR_HAS_LOCATION (pred)) - SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred)); + if (rexpr_has_location (pred)) + SET_EXPR_LOCATION (expr, rexpr_location (pred)); else_ = shortcut_cond_expr (expr); else_se = else_ && TREE_SIDE_EFFECTS (else_); pred = TREE_OPERAND (pred, 0); @@ -3592,20 +3680,16 @@ shortcut_cond_expr (tree expr) /* If our arms just jump somewhere, hijack those labels so we don't generate jumps to jumps. */ - if (then_ - && TREE_CODE (then_) == GOTO_EXPR - && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL) + if (tree then_goto = find_goto_label (then_)) { - true_label = GOTO_DESTINATION (then_); + true_label = GOTO_DESTINATION (then_goto); then_ = NULL; then_se = false; } - if (else_ - && TREE_CODE (else_) == GOTO_EXPR - && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL) + if (tree else_goto = find_goto_label (else_)) { - false_label = GOTO_DESTINATION (else_); + false_label = GOTO_DESTINATION (else_goto); else_ = NULL; else_se = false; } @@ -3669,8 +3753,8 @@ shortcut_cond_expr (tree expr) { tree last = expr_last (expr); t = build_and_jump (&end_label); - if (EXPR_HAS_LOCATION (last)) - SET_EXPR_LOCATION (t, EXPR_LOCATION (last)); + if (rexpr_has_location (last)) + SET_EXPR_LOCATION (t, rexpr_location (last)); append_to_statement_list (t, &expr); } if (emit_false) @@ -3963,39 +4047,35 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback) gimple_push_condition (); have_then_clause_p = have_else_clause_p = false; - if (TREE_OPERAND (expr, 1) != NULL - && TREE_CODE (TREE_OPERAND (expr, 1)) == GOTO_EXPR - && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 1))) == LABEL_DECL - && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 1))) - == current_function_decl) + label_true = find_goto_label (TREE_OPERAND (expr, 1)); + if (label_true + && DECL_CONTEXT (GOTO_DESTINATION (label_true)) == current_function_decl /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR have different locations, otherwise we end up with incorrect location information on the branches. */ && (optimize || !EXPR_HAS_LOCATION (expr) - || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 1)) - || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 1)))) + || !rexpr_has_location (label_true) + || EXPR_LOCATION (expr) == rexpr_location (label_true))) { - label_true = GOTO_DESTINATION (TREE_OPERAND (expr, 1)); have_then_clause_p = true; + label_true = GOTO_DESTINATION (label_true); } else label_true = create_artificial_label (UNKNOWN_LOCATION); - if (TREE_OPERAND (expr, 2) != NULL - && TREE_CODE (TREE_OPERAND (expr, 2)) == GOTO_EXPR - && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 2))) == LABEL_DECL - && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 2))) - == current_function_decl) + label_false = find_goto_label (TREE_OPERAND (expr, 2)); + if (label_false + && DECL_CONTEXT (GOTO_DESTINATION (label_false)) == current_function_decl /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR have different locations, otherwise we end up with incorrect location information on the branches. */ && (optimize || !EXPR_HAS_LOCATION (expr) - || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 2)) - || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 2)))) + || !rexpr_has_location (label_false) + || EXPR_LOCATION (expr) == rexpr_location (label_false))) { - label_false = GOTO_DESTINATION (TREE_OPERAND (expr, 2)); have_else_clause_p = true; + label_false = GOTO_DESTINATION (label_false); } else label_false = create_artificial_label (UNKNOWN_LOCATION); @@ -11792,6 +11872,18 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, ret = GS_ALL_DONE; break; + case DEBUG_EXPR_DECL: + gcc_unreachable (); + + case DEBUG_BEGIN_STMT: + gimplify_seq_add_stmt (pre_p, + gimple_build_debug_begin_stmt + (TREE_BLOCK (*expr_p), + EXPR_LOCATION (*expr_p))); + ret = GS_ALL_DONE; + *expr_p = NULL; + break; + case SSA_NAME: /* Allow callbacks into the gimplifier during optimization. */ ret = GS_ALL_DONE; diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index 61b081bd7ccc..a3f02b219df7 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -130,6 +130,7 @@ extern int lhd_type_dwarf_attribute (const_tree, int); #define LANG_HOOKS_EH_USE_CXA_END_CLEANUP false #define LANG_HOOKS_DEEP_UNSHARING false #define LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS false +#define LANG_HOOKS_EMITS_BEGIN_STMT false #define LANG_HOOKS_RUN_LANG_SELFTESTS lhd_do_nothing #define LANG_HOOKS_GET_SUBSTRING_LOCATION lhd_get_substring_location @@ -343,6 +344,7 @@ extern void lhd_end_section (void); LANG_HOOKS_EH_USE_CXA_END_CLEANUP, \ LANG_HOOKS_DEEP_UNSHARING, \ LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS, \ + LANG_HOOKS_EMITS_BEGIN_STMT, \ LANG_HOOKS_RUN_LANG_SELFTESTS, \ LANG_HOOKS_GET_SUBSTRING_LOCATION \ } diff --git a/gcc/langhooks.h b/gcc/langhooks.h index d1288f1965d1..40c5bade6167 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -528,6 +528,9 @@ struct lang_hooks instead of trampolines. */ bool custom_function_descriptors; + /* True if this language emits begin stmt notes. */ + bool emits_begin_stmt; + /* Run all lang-specific selftests. */ void (*run_lang_selftests) (void); diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c index 3758409bb9c5..0f81ce6766a1 100644 --- a/gcc/lra-constraints.c +++ b/gcc/lra-constraints.c @@ -5264,10 +5264,11 @@ inherit_reload_reg (bool def_p, int original_regno, lra_update_insn_regno_info (as_a (usage_insn)); if (lra_dump_file != NULL) { + basic_block bb = BLOCK_FOR_INSN (usage_insn); fprintf (lra_dump_file, " Inheritance reuse change %d->%d (bb%d):\n", original_regno, REGNO (new_reg), - BLOCK_FOR_INSN (usage_insn)->index); + bb ? bb->index : -1); dump_insn_slim (lra_dump_file, as_a (usage_insn)); } } @@ -5806,6 +5807,13 @@ update_ebb_live_info (rtx_insn *head, rtx_insn *tail) if (NOTE_P (curr_insn) && NOTE_KIND (curr_insn) != NOTE_INSN_BASIC_BLOCK) continue; curr_bb = BLOCK_FOR_INSN (curr_insn); + if (!curr_bb) + { + gcc_assert (DEBUG_INSN_P (curr_insn)); + if (DEBUG_MARKER_INSN_P (curr_insn)) + continue; + curr_bb = prev_bb; + } if (curr_bb != prev_bb) { if (prev_bb != NULL) diff --git a/gcc/lra.c b/gcc/lra.c index 88d75c18e86c..d1de053abd65 100644 --- a/gcc/lra.c +++ b/gcc/lra.c @@ -602,9 +602,9 @@ static struct lra_operand_data debug_operand_data = }; /* The following data are used as static insn data for all debug - insns. If structure lra_static_insn_data is changed, the + bind insns. If structure lra_static_insn_data is changed, the initializer should be changed too. */ -static struct lra_static_insn_data debug_insn_static_data = +static struct lra_static_insn_data debug_bind_static_data = { &debug_operand_data, 0, /* Duplication operands #. */ @@ -618,6 +618,22 @@ static struct lra_static_insn_data debug_insn_static_data = NULL /* Descriptions of operands in alternatives. */ }; +/* The following data are used as static insn data for all debug + marker insns. If structure lra_static_insn_data is changed, the + initializer should be changed too. */ +static struct lra_static_insn_data debug_marker_static_data = + { + &debug_operand_data, + 0, /* Duplication operands #. */ + -1, /* Commutative operand #. */ + 0, /* Operands #. There isn't any operand. */ + 0, /* Duplications #. */ + 0, /* Alternatives #. We are not interesting in alternatives + because we does not proceed debug_insns for reloads. */ + NULL, /* Hard registers referenced in machine description. */ + NULL /* Descriptions of operands in alternatives. */ + }; + /* Called once per compiler work to initialize some LRA data related to insns. */ static void @@ -947,12 +963,20 @@ lra_set_insn_recog_data (rtx_insn *insn) data->regs = NULL; if (DEBUG_INSN_P (insn)) { - data->insn_static_data = &debug_insn_static_data; data->dup_loc = NULL; data->arg_hard_regs = NULL; data->preferred_alternatives = ALL_ALTERNATIVES; - data->operand_loc = XNEWVEC (rtx *, 1); - data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn); + if (DEBUG_BIND_INSN_P (insn)) + { + data->insn_static_data = &debug_bind_static_data; + data->operand_loc = XNEWVEC (rtx *, 1); + data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn); + } + else if (DEBUG_MARKER_INSN_P (insn)) + { + data->insn_static_data = &debug_marker_static_data; + data->operand_loc = NULL; + } return data; } if (icode < 0) @@ -1595,7 +1619,7 @@ lra_update_insn_regno_info (rtx_insn *insn) return; data = lra_get_insn_recog_data (insn); static_data = data->insn_static_data; - freq = get_insn_freq (insn); + freq = NONDEBUG_INSN_P (insn) ? get_insn_freq (insn) : 0; invalidate_insn_data_regno_info (data, insn, freq); uid = INSN_UID (insn); for (i = static_data->n_operands - 1; i >= 0; i--) diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c index acbbc9d68235..210a5eff210b 100644 --- a/gcc/lto-streamer-in.c +++ b/gcc/lto-streamer-in.c @@ -1125,7 +1125,10 @@ input_function (tree fn_decl, struct data_in *data_in, Similarly remove all IFN_*SAN_* internal calls */ if (!flag_wpa) { - if (!MAY_HAVE_DEBUG_STMTS && is_gimple_debug (stmt)) + if (is_gimple_debug (stmt) + && (gimple_debug_nonbind_marker_p (stmt) + ? !MAY_HAVE_DEBUG_MARKER_STMTS + : !MAY_HAVE_DEBUG_BIND_STMTS)) remove = true; if (is_gimple_call (stmt) && gimple_call_internal_p (stmt)) @@ -1179,6 +1182,13 @@ input_function (tree fn_decl, struct data_in *data_in, { gsi_next (&bsi); stmts[gimple_uid (stmt)] = stmt; + + /* Remember that the input function has begin stmt + markers, so that we know to expect them when emitting + debug info. */ + if (!cfun->debug_nonbind_markers + && gimple_debug_nonbind_marker_p (stmt)) + cfun->debug_nonbind_markers = true; } } } diff --git a/gcc/params.def b/gcc/params.def index 8881f4c403a0..c27eb6447a24 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -962,6 +962,15 @@ DEFPARAM (PARAM_MAX_VARTRACK_REVERSE_OP_SIZE, "Max. size of loc list for which reverse ops should be added.", 50, 0, 0) +/* Set a threshold to discard debug markers (e.g. debug begin stmt + markers) when expanding a function to RTL, or inlining it into + another function. */ + +DEFPARAM (PARAM_MAX_DEBUG_MARKER_COUNT, + "max-debug-marker-count", + "Max. count of debug markers to expand or inline.", + 100000, 0, 0) + /* Set minimum insn uid for non-debug insns. */ DEFPARAM (PARAM_MIN_NONDEBUG_INSN_UID, diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c index 28d99862cad2..acbe2f37748a 100644 --- a/gcc/print-rtl.c +++ b/gcc/print-rtl.c @@ -258,6 +258,16 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED, fputc ('\t', m_outfile); break; + case NOTE_INSN_BEGIN_STMT: +#ifndef GENERATOR_FILE + { + expanded_location xloc + = expand_location (NOTE_MARKER_LOCATION (in_rtx)); + fprintf (m_outfile, " %s:%i", xloc.file, xloc.line); + } +#endif + break; + default: break; } @@ -1791,6 +1801,20 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose) case DEBUG_INSN: { + if (DEBUG_MARKER_INSN_P (x)) + { + switch (INSN_DEBUG_MARKER_KIND (x)) + { + case NOTE_INSN_BEGIN_STMT: + pp_string (pp, "debug begin stmt marker"); + break; + + default: + gcc_unreachable (); + } + break; + } + const char *name = "?"; char idbuf[32]; diff --git a/gcc/recog.c b/gcc/recog.c index 4f11c579137c..3eb7fb8b14ab 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -2252,6 +2252,7 @@ extract_insn (rtx_insn *insn) case ADDR_VEC: case ADDR_DIFF_VEC: case VAR_LOCATION: + case DEBUG_MARKER: return; case SET: diff --git a/gcc/rtl.def b/gcc/rtl.def index ee7b7e195243..0000808c9e99 100644 --- a/gcc/rtl.def +++ b/gcc/rtl.def @@ -766,6 +766,9 @@ DEF_RTL_EXPR(ENTRY_VALUE, "entry_value", "0", RTX_OBJ) been optimized away completely. */ DEF_RTL_EXPR(DEBUG_PARAMETER_REF, "debug_parameter_ref", "t", RTX_OBJ) +/* Used in marker DEBUG_INSNs to avoid being recognized as an insn. */ +DEF_RTL_EXPR(DEBUG_MARKER, "debug_marker", "", RTX_EXTRA) + /* All expressions from this point forward appear only in machine descriptions. */ #ifdef GENERATOR_FILE diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 0d2a31763f1f..f858d426a500 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa.h" #include "except.h" #include "debug.h" +#include "params.h" #include "value-prof.h" #include "cfgloop.h" #include "builtins.h" @@ -1354,7 +1355,9 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id) gimple_seq stmts = NULL; if (is_gimple_debug (stmt) - && !opt_for_fn (id->dst_fn, flag_var_tracking_assignments)) + && (gimple_debug_nonbind_marker_p (stmt) + ? !DECL_STRUCT_FUNCTION (id->dst_fn)->debug_nonbind_markers + : !opt_for_fn (id->dst_fn, flag_var_tracking_assignments))) return stmts; /* Begin by recognizing trees that we'll completely rewrite for the @@ -1637,6 +1640,20 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id) gimple_seq_add_stmt (&stmts, copy); return stmts; } + if (gimple_debug_nonbind_marker_p (stmt)) + { + /* If the inlined function has too many debug markers, + don't copy them. */ + if (id->src_cfun->debug_marker_count + > PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT)) + return stmts; + + gdebug *copy = as_a (gimple_copy (stmt)); + id->debug_stmts.safe_push (copy); + gimple_seq_add_stmt (&stmts, copy); + return stmts; + } + gcc_checking_assert (!is_gimple_debug (stmt)); /* Create a new deep copy of the statement. */ copy = gimple_copy (stmt); @@ -1732,7 +1749,8 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id) gimple_set_block (copy, *n); } - if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy)) + if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy) + || gimple_debug_nonbind_marker_p (copy)) { gimple_seq_add_stmt (&stmts, copy); return stmts; @@ -2585,6 +2603,8 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb) value = gimple_debug_source_bind_get_value (stmt); new_stmt = gimple_build_debug_source_bind (var, value, stmt); } + else if (gimple_debug_nonbind_marker_p (stmt)) + new_stmt = as_a (gimple_copy (stmt)); else gcc_unreachable (); gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT); @@ -2849,6 +2869,9 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id) gimple_set_block (stmt, n ? *n : id->block); } + if (gimple_debug_nonbind_marker_p (stmt)) + return; + /* Remap all the operands in COPY. */ memset (&wi, 0, sizeof (wi)); wi.info = id; @@ -2857,8 +2880,10 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id) if (gimple_debug_source_bind_p (stmt)) t = gimple_debug_source_bind_get_var (stmt); - else + else if (gimple_debug_bind_p (stmt)) t = gimple_debug_bind_get_var (stmt); + else + gcc_unreachable (); if (TREE_CODE (t) == PARM_DECL && id->debug_map && (n = id->debug_map->get (t))) diff --git a/gcc/tree-iterator.c b/gcc/tree-iterator.c index c485413b5e50..10e510db0921 100644 --- a/gcc/tree-iterator.c +++ b/gcc/tree-iterator.c @@ -89,7 +89,7 @@ append_to_statement_list_1 (tree t, tree *list_p) void append_to_statement_list (tree t, tree *list_p) { - if (t && TREE_SIDE_EFFECTS (t)) + if (t && (TREE_SIDE_EFFECTS (t) || TREE_CODE (t) == DEBUG_BEGIN_STMT)) append_to_statement_list_1 (t, list_p); } @@ -137,7 +137,8 @@ tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode) tail = head; } - TREE_SIDE_EFFECTS (i->container) = 1; + if (TREE_CODE (t) != DEBUG_BEGIN_STMT) + TREE_SIDE_EFFECTS (i->container) = 1; cur = i->ptr; @@ -213,7 +214,8 @@ tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode) tail = head; } - TREE_SIDE_EFFECTS (i->container) = 1; + if (TREE_CODE (t) != DEBUG_BEGIN_STMT) + TREE_SIDE_EFFECTS (i->container) = 1; cur = i->ptr; @@ -279,8 +281,9 @@ tsi_delink (tree_stmt_iterator *i) i->ptr = next; } -/* Return the first expression in a sequence of COMPOUND_EXPRs, - or in a STATEMENT_LIST. */ +/* Return the first expression in a sequence of COMPOUND_EXPRs, or in + a STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a + STATEMENT_LIST if that's the first non-DEBUG_BEGIN_STMT. */ tree expr_first (tree expr) @@ -291,7 +294,20 @@ expr_first (tree expr) if (TREE_CODE (expr) == STATEMENT_LIST) { struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr); - return n ? n->stmt : NULL_TREE; + if (!n) + return NULL_TREE; + while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT) + { + n = n->next; + if (!n) + return NULL_TREE; + } + /* If the first non-debug stmt is not a statement list, we + already know it's what we're looking for. */ + if (TREE_CODE (n->stmt) != STATEMENT_LIST) + return n->stmt; + + return expr_first (n->stmt); } while (TREE_CODE (expr) == COMPOUND_EXPR) @@ -300,8 +316,9 @@ expr_first (tree expr) return expr; } -/* Return the last expression in a sequence of COMPOUND_EXPRs, - or in a STATEMENT_LIST. */ +/* Return the last expression in a sequence of COMPOUND_EXPRs, or in a + STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a + STATEMENT_LIST if that's the last non-DEBUG_BEGIN_STMT. */ tree expr_last (tree expr) @@ -312,7 +329,20 @@ expr_last (tree expr) if (TREE_CODE (expr) == STATEMENT_LIST) { struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr); - return n ? n->stmt : NULL_TREE; + if (!n) + return NULL_TREE; + while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT) + { + n = n->prev; + if (!n) + return NULL_TREE; + } + /* If the last non-debug stmt is not a statement list, we + already know it's what we're looking for. */ + if (TREE_CODE (n->stmt) != STATEMENT_LIST) + return n->stmt; + + return expr_last (n->stmt); } while (TREE_CODE (expr) == COMPOUND_EXPR) diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 8c7b6d67b44c..0ce96c5b88cb 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -3292,6 +3292,10 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags, pp_string (pp, "_Cilk_sync"); break; + case DEBUG_BEGIN_STMT: + pp_string (pp, "# DEBUG BEGIN STMT"); + break; + default: NIY; } diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c index 70675e4a3fcd..91793bfa59d3 100644 --- a/gcc/tree-ssa-threadedge.c +++ b/gcc/tree-ssa-threadedge.c @@ -712,6 +712,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src) gimple *stmt = gsi_stmt (si); if (!is_gimple_debug (stmt)) break; + if (gimple_debug_nonbind_marker_p (stmt)) + continue; i++; } @@ -739,6 +741,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src) var = gimple_debug_bind_get_var (stmt); else if (gimple_debug_source_bind_p (stmt)) var = gimple_debug_source_bind_get_var (stmt); + else if (gimple_debug_nonbind_marker_p (stmt)) + continue; else gcc_unreachable (); @@ -766,17 +770,23 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src) var = gimple_debug_bind_get_var (stmt); else if (gimple_debug_source_bind_p (stmt)) var = gimple_debug_source_bind_get_var (stmt); + else if (gimple_debug_nonbind_marker_p (stmt)) + continue; else gcc_unreachable (); - /* Discard debug bind overlaps. ??? Unlike stmts from src, + /* Discard debug bind overlaps. Unlike stmts from src, copied into a new block that will precede BB, debug bind stmts in bypassed BBs may actually be discarded if - they're overwritten by subsequent debug bind stmts, which - might be a problem once we introduce stmt frontier notes - or somesuch. Adding `&& bb == src' to the condition - below will preserve all potentially relevant debug - notes. */ + they're overwritten by subsequent debug bind stmts. We + want to copy binds for all modified variables, so that we + retain a bind to the shared def if there is one, or to a + newly introduced PHI node if there is one. Our bind will + end up reset if the value is dead, but that implies the + variable couldn't have survived, so it's fine. We are + not actually running the code that performed the binds at + this point, we're just adding binds so that they survive + the new confluence, so markers should not be copied. */ if (vars && vars->add (var)) continue; else if (!vars) @@ -787,8 +797,7 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src) break; if (i >= 0) continue; - - if (fewvars.length () < (unsigned) alloc_count) + else if (fewvars.length () < (unsigned) alloc_count) fewvars.quick_push (var); else { diff --git a/gcc/tree.c b/gcc/tree.c index 28e157f5fd28..e76ff12ec304 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -1030,7 +1030,8 @@ make_node (enum tree_code code MEM_STAT_DECL) switch (type) { case tcc_statement: - TREE_SIDE_EFFECTS (t) = 1; + if (code != DEBUG_BEGIN_STMT) + TREE_SIDE_EFFECTS (t) = 1; break; case tcc_declaration: @@ -4428,7 +4429,10 @@ build1 (enum tree_code code, tree type, tree node MEM_STAT_DECL) } if (TREE_CODE_CLASS (code) == tcc_statement) - TREE_SIDE_EFFECTS (t) = 1; + { + if (code != DEBUG_BEGIN_STMT) + TREE_SIDE_EFFECTS (t) = 1; + } else switch (code) { case VA_ARG_EXPR: diff --git a/gcc/tree.def b/gcc/tree.def index 3d2bd95d6665..97c05275e90c 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -382,6 +382,9 @@ DEFTREECODE (RESULT_DECL, "result_decl", tcc_declaration, 0) DEBUG stmts. */ DEFTREECODE (DEBUG_EXPR_DECL, "debug_expr_decl", tcc_declaration, 0) +/* A stmt that marks the beginning of a source statement. */ +DEFTREECODE (DEBUG_BEGIN_STMT, "debug_begin_stmt", tcc_statement, 0) + /* A namespace declaration. Namespaces appear in DECL_CONTEXT of other _DECLs, providing a hierarchy of names. */ DEFTREECODE (NAMESPACE_DECL, "namespace_decl", tcc_declaration, 0) diff --git a/gcc/tree.h b/gcc/tree.h index efc7947f4ab7..94375adcda84 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1204,7 +1204,7 @@ extern void protected_set_expr_location (tree, location_t); /* GOTO_EXPR accessor. This gives access to the label associated with a goto statement. */ -#define GOTO_DESTINATION(NODE) TREE_OPERAND ((NODE), 0) +#define GOTO_DESTINATION(NODE) TREE_OPERAND (GOTO_EXPR_CHECK (NODE), 0) /* ASM_EXPR accessors. ASM_STRING returns a STRING_CST for the instruction (e.g., "mov x, y"). ASM_OUTPUTS, ASM_INPUTS, and diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index b324a2c97c28..8e500b144712 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -9926,6 +9926,36 @@ vt_init_cfa_base (void) cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx)); } +/* Reemit INSN, a MARKER_DEBUG_INSN, as a note. */ + +static rtx_insn * +reemit_marker_as_note (rtx_insn *insn, basic_block *bb) +{ + gcc_checking_assert (DEBUG_MARKER_INSN_P (insn)); + + enum insn_note kind = INSN_DEBUG_MARKER_KIND (insn); + + switch (kind) + { + case NOTE_INSN_BEGIN_STMT: + { + rtx_insn *note = NULL; + if (cfun->debug_nonbind_markers) + { + note = emit_note_before (kind, insn); + NOTE_MARKER_LOCATION (note) = INSN_LOCATION (insn); + if (bb) + BLOCK_FOR_INSN (note) = *bb; + } + delete_insn (insn); + return note; + } + + default: + gcc_unreachable (); + } +} + /* Allocate and initialize the data structures for variable tracking and parse the RTL to get the micro operations. */ @@ -10169,6 +10199,12 @@ vt_initialize (void) cselib_hook_called = false; adjust_insn (bb, insn); + if (DEBUG_MARKER_INSN_P (insn)) + { + insn = reemit_marker_as_note (insn, &save_bb); + continue; + } + if (MAY_HAVE_DEBUG_BIND_INSNS) { if (CALL_P (insn)) @@ -10245,10 +10281,11 @@ vt_initialize (void) static int debug_label_num = 1; -/* Get rid of all debug insns from the insn stream. */ +/* Remove from the insn stream all debug insns used for variable + tracking at assignments. */ static void -delete_debug_insns (void) +delete_vta_debug_insns (void) { basic_block bb; rtx_insn *insn, *next; @@ -10264,6 +10301,12 @@ delete_debug_insns (void) insn = next) if (DEBUG_INSN_P (insn)) { + if (DEBUG_MARKER_INSN_P (insn)) + { + insn = reemit_marker_as_note (insn, NULL); + continue; + } + tree decl = INSN_VAR_LOCATION_DECL (insn); if (TREE_CODE (decl) == LABEL_DECL && DECL_NAME (decl) @@ -10289,10 +10332,13 @@ delete_debug_insns (void) handled as well.. */ static void -vt_debug_insns_local (bool skipped ATTRIBUTE_UNUSED) +vt_debug_insns_local (bool skipped) { - /* ??? Just skip it all for now. */ - delete_debug_insns (); + /* ??? Just skip it all for now. If we skipped the global pass, + arrange for stmt markers to be dropped as well. */ + if (skipped) + cfun->debug_nonbind_markers = 0; + delete_vta_debug_insns (); } /* Free the data structures needed for variable tracking. */ @@ -10357,15 +10403,21 @@ variable_tracking_main_1 (void) { bool success; - if (flag_var_tracking_assignments < 0 + /* We won't be called as a separate pass if flag_var_tracking is not + set, but final may call us to turn debug markers into notes. */ + if ((!flag_var_tracking && MAY_HAVE_DEBUG_INSNS) + || flag_var_tracking_assignments < 0 /* Var-tracking right now assumes the IR doesn't contain any pseudos at this point. */ || targetm.no_register_allocation) { - delete_debug_insns (); + delete_vta_debug_insns (); return 0; } + if (!flag_var_tracking) + return 0; + if (n_basic_blocks_for_fn (cfun) > 500 && n_edges_for_fn (cfun) / n_basic_blocks_for_fn (cfun) >= 20) { @@ -10387,7 +10439,9 @@ variable_tracking_main_1 (void) { vt_finalize (); - delete_debug_insns (); + cfun->debug_nonbind_markers = 0; + + delete_vta_debug_insns (); /* This is later restored by our caller. */ flag_var_tracking_assignments = 0; From patchwork Fri Nov 10 02:34:45 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Oliva X-Patchwork-Id: 836584 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-466476-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="n0cp9Aa6"; dkim-atps=neutral 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 3yY41t4rwsz9t2M for ; Fri, 10 Nov 2017 13:37:22 +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:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=tP0IQUtsTlz3aR8IqwzYJquSjLLVutxE6BOY1J9/RE+HKIaM3M/c1 IzG5qNZ9Ol41kQlq7Qmc/H9+ezaZ1yC8aM0GrLlSvE0YPMJMnAwLOtdN4pQT1gBy GCKTkDcyTiWT3W5VbGilCgH7XM+WTLAWrSWKwbV6L/+gMTI5elSa4I= 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:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=AUjhobJ0gUY9FIb7GT/kfFPPjY4=; b=n0cp9Aa6RQk3M3hMYppz SWdrzMb8ZS7qdPpOhgfwhCKLJnvynGz47qUR9VWiuz5MuRTuv9QKWXjRrxzUfTWW SN4jcpOsxG6e3DFooHc0FYvH0/4DTkYw/nH4pyFXc06+OiurV/X4jrpRTM9aFmZO /QA205lRU12ocye1U6x0f+8= Received: (qmail 97648 invoked by alias); 10 Nov 2017 02:36:26 -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 97603 invoked by uid 89); 10 Nov 2017 02:36:26 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=gxcoff, progressive 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 ESMTP; Fri, 10 Nov 2017 02:36:24 +0000 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 94E00883C4; Fri, 10 Nov 2017 02:36:23 +0000 (UTC) Received: from freie.home (ovpn04.gateway.prod.ext.phx2.redhat.com [10.5.9.4]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 54FE86BF7F; Fri, 10 Nov 2017 02:36:22 +0000 (UTC) Received: from frit.home (frit.home [172.31.160.7]) by freie.home (8.15.2/8.15.2) with ESMTP id vAA2ZEBE003201; Fri, 10 Nov 2017 00:35:40 -0200 From: Alexandre Oliva To: Richard Biener , Jeff Law , Jason Merrill Cc: GCC Patches , Alexandre Oliva Subject: [SFN+LVU+IEPM v4 6/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers Date: Fri, 10 Nov 2017 00:34:45 -0200 Message-Id: <20171110023448.28164-6-aoliva@redhat.com> In-Reply-To: References: Introduce a command line option to enable statement frontiers, enabled by default in optimized builds with DWARF2+ debug information. This patch depends on an earlier patch that completed the infrastructure for debug markers, and on another patch that turns -g into a negatable option prefix. gcc/ChangeLog * common.opt (gstatement-frontiers): New, setting debug_nonbind_markers_p. * rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): Activate. * toplev.c (process_options): Autodetect value for debug statement frontiers option. * tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): Activate. * doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers): New. --- gcc/common.opt | 4 ++++ gcc/doc/invoke.texi | 12 ++++++++++++ gcc/rtl.h | 2 +- gcc/toplev.c | 4 ++++ gcc/tree.h | 2 +- 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/gcc/common.opt b/gcc/common.opt index f8f2ed3db8ae..421b4a2ce2a1 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -2936,6 +2936,10 @@ gstabs+ Common Driver JoinedOrMissing Negative(gvms) Generate debug information in extended STABS format. +gstatement-frontiers +Common Driver Var(debug_nonbind_markers_p) Init(2) +Emit progressive recommended breakpoint locations. + gstrict-dwarf Common Driver Report Var(dwarf_strict) Init(0) Don't emit DWARF additions beyond selected version. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 6ff7c34cdd6c..9509c95acf14 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -346,6 +346,7 @@ Objective-C and Objective-C++ Dialects}. -ggdb -grecord-gcc-switches -gno-record-gcc-switches @gol -gstabs -gstabs+ -gstrict-dwarf -gno-strict-dwarf @gol -gcolumn-info -gno-column-info @gol +-gstatement-frontiers -gno-statement-frontiers @gol -gvms -gxcoff -gxcoff+ -gz@r{[}=@var{type}@r{]} @gol -fdebug-prefix-map=@var{old}=@var{new} -fdebug-types-section @gol -fno-eliminate-unused-debug-types @gol @@ -7081,6 +7082,17 @@ Emit location column information into DWARF debugging information, rather than just file and line. This option is enabled by default. +@item -gstatement-frontiers +@item -gno-statement-frontiers +@opindex gstatement-frontiers +@opindex gno-statement-frontiers +This option causes GCC to create markers in the internal representation +at the beginning of statements, and to keep them roughly in place +throughout compilation, using them to guide the output of @code{is_stmt} +markers in the line number table. This is enabled by default when +compiling with optimization (@option{-Os}, @option{-O}, @option{-O2}, +@dots{}), and outputting DWARF 2 debug information at the normal level. + @item -gz@r{[}=@var{type}@r{]} @opindex gz Produce compressed debug sections in DWARF format, if that is supported. diff --git a/gcc/rtl.h b/gcc/rtl.h index 4de167d982cf..3ef687e5a371 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -816,7 +816,7 @@ struct GTY(()) rtvec_def { #define NONDEBUG_INSN_P(X) (INSN_P (X) && !DEBUG_INSN_P (X)) /* Nonzero if DEBUG_MARKER_INSN_P may possibly hold. */ -#define MAY_HAVE_DEBUG_MARKER_INSNS 0 /* debug_nonbind_markers_p */ +#define MAY_HAVE_DEBUG_MARKER_INSNS debug_nonbind_markers_p /* Nonzero if DEBUG_BIND_INSN_P may possibly hold. */ #define MAY_HAVE_DEBUG_BIND_INSNS flag_var_tracking_assignments /* Nonzero if DEBUG_INSN_P may possibly hold. */ diff --git a/gcc/toplev.c b/gcc/toplev.c index eff169008d13..0b9f1f546279 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -1537,6 +1537,10 @@ process_options (void) warning_at (UNKNOWN_LOCATION, 0, "var-tracking-assignments changes selective scheduling"); + if (debug_nonbind_markers_p == AUTODETECT_VALUE) + debug_nonbind_markers_p = optimize && debug_info_level >= DINFO_LEVEL_NORMAL + && (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG); + if (flag_tree_cselim == AUTODETECT_VALUE) { if (HAVE_conditional_move) diff --git a/gcc/tree.h b/gcc/tree.h index 94375adcda84..5dd653ea7f69 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1106,7 +1106,7 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, ((int)TREE_INT_CST_LOW (VL_EXP_CHECK (NODE)->exp.operands[0])) /* Nonzero if gimple_debug_nonbind_marker_p() may possibly hold. */ -#define MAY_HAVE_DEBUG_MARKER_STMTS 0 /* debug_nonbind_markers_p */ +#define MAY_HAVE_DEBUG_MARKER_STMTS debug_nonbind_markers_p /* Nonzero if gimple_debug_bind_p() (and thus gimple_debug_source_bind_p()) may possibly hold. */ #define MAY_HAVE_DEBUG_BIND_STMTS flag_var_tracking_assignments From patchwork Fri Nov 10 02:34:46 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Oliva X-Patchwork-Id: 836587 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-466479-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="Xx41vZb3"; dkim-atps=neutral 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 3yY4382QnGz9t2M for ; Fri, 10 Nov 2017 13:38:28 +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:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=xihTJLzYZdK763RuxBoR1roZPxm/4CzPfQB/mzLp+GN5jSWjiKmVM u4FiCsjk/UuVJJZNT31JSsLE94u6XpX/bJ+t0pt9/Za/0t7sxLAsVVBsQDMG8zxz oXYX65GFwdEm+9OL8/M/mHJnI/F+hLzs2y7hTIr2WhR6C60FnD/x6M= 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:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=zAtK+QMkIg4nKK6es+3wDq5Vqrc=; b=Xx41vZb3JUuhMmAGznN5 OMKCTicQfGfVRD8atUyIHCnCNc0zJ+n15rS5sofo++ZJzjQ91gPORi21JeXe4POZ HTsqMuHNRp6GHSPHYTwY7pnnECah+GPktmVb7qGOx0z7kN1FfFhHngNum3i4wDLK Ffu50IproiCzDL21CTehUkw= Received: (qmail 99959 invoked by alias); 10 Nov 2017 02:36:55 -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 99921 invoked by uid 89); 10 Nov 2017 02:36:54 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=Former 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 ESMTP; Fri, 10 Nov 2017 02:36:45 +0000 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1B599C054C29; Fri, 10 Nov 2017 02:36:44 +0000 (UTC) Received: from freie.home (ovpn04.gateway.prod.ext.phx2.redhat.com [10.5.9.4]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 1DC1F17A7D; Fri, 10 Nov 2017 02:36:41 +0000 (UTC) Received: from frit.home (frit.home [172.31.160.7]) by freie.home (8.15.2/8.15.2) with ESMTP id vAA2ZEBF003201; Fri, 10 Nov 2017 00:35:49 -0200 From: Alexandre Oliva To: Richard Biener , Jeff Law , Jason Merrill Cc: GCC Patches , Alexandre Oliva Subject: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views Date: Fri, 10 Nov 2017 00:34:46 -0200 Message-Id: <20171110023448.28164-7-aoliva@redhat.com> In-Reply-To: References: This patch introduces an option to enable the generation of location views along with location lists. The exact format depends on the DWARF version: it can be a separate attribute (DW_AT_GNU_locviews) or (DW_LLE_view_pair) entries in DWARF5+ loclists. Line number tables are also affected. If the assembler is found, at compiler build time, to support .loc views, we use them and assembler-computed view labels, otherwise we output compiler-generated line number programs with conservatively-computed view labels. In either case, we output view information next to line number changes when verbose assembly output is requested. This patch requires an LVU patch that modifies the exported API of final_scan_insn. It also expects the entire SFN patchset to be installed first, although SFN is not a requirement for LVU. for include/ChangeLog * dwarf2.def (DW_AT_GNU_locviews): New. * dwarf2.h (enum dwarf_location_list_entry_type): Add DW_LLE_GNU_view_pair. (DW_LLE_view_pair): Define. for gcc/ChangeLog * common.opt (gvariable-location-views): New. * config.in: Rebuilt. * configure: Rebuilt. * configure.ac: Test assembler for view support. * dwarf2asm.c (dw2_asm_output_symname_uleb128): New. * dwarf2asm.h (dw2_asm_output_symname_uleb128): Declare. * dwarf2out.c (var_loc_view): New typedef. (struct dw_loc_list_struct): Add vl_symbol, vbegin, vend. (dwarf2out_locviews_in_attribute): New. (dwarf2out_locviews_in_loclist): New. (dw_val_equal_p): Compare val_view_list of dw_val_class_view_lists. (enum dw_line_info_opcode): Add LI_adv_address. (struct dw_line_info_table): Add view. (RESET_NEXT_VIEW, RESETTING_VIEW_P): New macros. (DWARF2_ASM_VIEW_DEBUG_INFO): Define default. (zero_view_p): New variable. (ZERO_VIEW_P): New macro. (output_asm_line_debug_info): New. (struct var_loc_node): Add view. (add_AT_view_list, AT_loc_list): New. (add_var_loc_to_decl): Add view param. Test it against last. (new_loc_list): Add view params. Record them. (AT_loc_list_ptr): Handle loc and view lists. (view_list_to_loc_list_val_node): New. (print_dw_val): Handle dw_val_class_view_list. (size_of_die): Likewise. (value_format): Likewise. (loc_list_has_views): New. (gen_llsym): Set vl_symbol too. (maybe_gen_llsym, skip_loc_list_entry): New. (dwarf2out_maybe_output_loclist_view_pair): New. (output_loc_list): Output view list or entries too. (output_view_list_offset): New. (output_die): Handle dw_val_class_view_list. (output_dwarf_version): New. (output_compilation_unit_header): Use it. (output_skeleton_debug_sections): Likewise. (output_rnglists, output_line_info): Likewise. (output_pubnames, output_aranges): Update version comments. (output_one_line_info_table): Output view numbers in asm comments. (dw_loc_list): Determine current endview, pass it to new_loc_list. Call maybe_gen_llsym. (loc_list_from_tree_1): Adjust. (add_AT_location_description): Create view list attribute if needed, check it's absent otherwise. (convert_cfa_to_fb_loc_list): Adjust. (maybe_emit_file): Call output_asm_line_debug_info for test. (dwarf2out_var_location): Reset views as needed. Precompute add_var_loc_to_decl args. Call get_attr_min_length only if we have the attribute. Set view. (new_line_info_table): Reset next view. (set_cur_line_info_table): Call output_asm_line_debug_info for test. (dwarf2out_source_line): Likewise. Output view resets and labels to the assembler, or select appropriate line info opcodes. (prune_unused_types_walk_attribs): Handle dw_val_class_view_list. (optimize_string_length): Catch it. Adjust. (resolve_addr): Copy vl_symbol along with ll_symbol. Handle dw_val_class_view_list, and remove it if no longer needed. (hash_loc_list): Hash view numbers. (loc_list_hasher::equal): Compare them. (optimize_location_lists): Check whether a view list symbol is needed, and whether the locview attribute is present, and whether they match. Remove the locview attribute if no longer needed. (index_location_lists): Call skip_loc_list_entry for test. (dwarf2out_finish): Call output_asm_line_debug_info for test. Use output_dwarf_version. * dwarf2out.h (enum dw_val_class): Add dw_val_class_view_list. (struct dw_val_node): Add val_view_list. * final.c: Include langhooks.h. (SEEN_NEXT_VIEW): New. (set_next_view_needed): New. (clear_next_view_needed): New. (maybe_output_next_view): New. (final_start_function): Rename to... (final_start_function_1): ... this. Take pointer to FIRST, add SEEN parameter. Emit param bindings in the initial view. (final_start_function): Reintroduce SEEN-less interface. (final): Rename to... (final_1): ... this. Take SEEN parameter. Output final pending next view at the end. (final): Reintroduce seen-less interface. (final_scan_insn): Output pending next view before switching sections or ending a block. Mark the next view as needed when outputting variable locations. Notify debug backend of section changes, and of location view changes. (rest_of_handle_final): Adjust. * opts.c (common_handle_option): Accept -gdwarf version 6. * toplev.c (process_options): Autodetect value for debug variable location views option. * doc/invoke.texi (gvariable-location-views): New. (gno-variable-location-views): New. --- gcc/common.opt | 4 + gcc/config.in | 6 + gcc/configure | 46 ++++ gcc/configure.ac | 18 +- gcc/doc/invoke.texi | 19 ++ gcc/dwarf2asm.c | 25 ++ gcc/dwarf2asm.h | 4 + gcc/dwarf2out.c | 646 ++++++++++++++++++++++++++++++++++++++++++++++------ gcc/dwarf2out.h | 4 +- gcc/final.c | 149 +++++++++++- gcc/opts.c | 2 +- gcc/toplev.c | 8 + include/dwarf2.def | 1 + include/dwarf2.h | 8 + 14 files changed, 858 insertions(+), 82 deletions(-) diff --git a/gcc/common.opt b/gcc/common.opt index 421b4a2ce2a1..f37bafce3f48 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -2948,6 +2948,10 @@ gtoggle Common Driver Report Var(flag_gtoggle) Toggle debug information generation. +gvariable-location-views +Common Driver Var(debug_variable_location_views) Init(2) +Augment variable location lists with progressive views. + gvms Common Driver JoinedOrMissing Negative(gxcoff) Generate debug information in VMS format. diff --git a/gcc/config.in b/gcc/config.in index 5651bcba431c..e4154f666f96 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -358,6 +358,12 @@ #endif +/* Define if your assembler supports views in dwarf2 .loc directives. */ +#ifndef USED_FOR_TARGET +#undef HAVE_AS_DWARF2_DEBUG_VIEW +#endif + + /* Define if your assembler supports the R_PPC64_ENTRY relocation. */ #ifndef USED_FOR_TARGET #undef HAVE_AS_ENTRY_MARKERS diff --git a/gcc/configure b/gcc/configure index fb40ead92046..5992d8b75ffe 100755 --- a/gcc/configure +++ b/gcc/configure @@ -27777,6 +27777,52 @@ $as_echo "$gcc_cv_as_dwarf2_file_buggy" >&6; } $as_echo "#define HAVE_AS_DWARF2_DEBUG_LINE 1" >>confdefs.h + + if test $gcc_cv_as_leb128 = yes; then + conftest_s="\ + .file 1 \"conftest.s\" + .loc 1 3 0 view .LVU1 + $insn + .data + .uleb128 .LVU1 + .uleb128 .LVU1 +" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for dwarf2 debug_view support" >&5 +$as_echo_n "checking assembler for dwarf2 debug_view support... " >&6; } +if test "${gcc_cv_as_dwarf2_debug_view+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + gcc_cv_as_dwarf2_debug_view=no + if test $in_tree_gas = yes; then + if test $in_tree_gas_is_elf = yes \ + && test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 27 \) \* 1000 + 0` + then gcc_cv_as_dwarf2_debug_view=yes +fi + elif test x$gcc_cv_as != x; then + $as_echo "$conftest_s" > conftest.s + if { ac_try='$gcc_cv_as $gcc_cv_as_flags -o conftest.o conftest.s >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } + then + gcc_cv_as_dwarf2_debug_view=yes + else + echo "configure: failed program was" >&5 + cat conftest.s >&5 + fi + rm -f conftest.o conftest.s + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_dwarf2_debug_view" >&5 +$as_echo "$gcc_cv_as_dwarf2_debug_view" >&6; } +if test $gcc_cv_as_dwarf2_debug_view = yes; then + +$as_echo "#define HAVE_AS_DWARF2_DEBUG_VIEW 1" >>confdefs.h + +fi + fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for --gdwarf2 option" >&5 diff --git a/gcc/configure.ac b/gcc/configure.ac index 0e5167695a23..c6761832071f 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -4862,9 +4862,25 @@ if test x"$insn" != x; then if test $gcc_cv_as_dwarf2_debug_line = yes \ && test $gcc_cv_as_dwarf2_file_buggy = no; then - AC_DEFINE(HAVE_AS_DWARF2_DEBUG_LINE, 1, + AC_DEFINE(HAVE_AS_DWARF2_DEBUG_LINE, 1, [Define if your assembler supports dwarf2 .file/.loc directives, and preserves file table indices exactly as given.]) + + if test $gcc_cv_as_leb128 = yes; then + conftest_s="\ + .file 1 \"conftest.s\" + .loc 1 3 0 view .LVU1 + $insn + .data + .uleb128 .LVU1 + .uleb128 .LVU1 +" + gcc_GAS_CHECK_FEATURE([dwarf2 debug_view support], + gcc_cv_as_dwarf2_debug_view, + [elf,2,27,0],,[$conftest_s],, + [AC_DEFINE(HAVE_AS_DWARF2_DEBUG_VIEW, 1, + [Define if your assembler supports views in dwarf2 .loc directives.])]) + fi fi gcc_GAS_CHECK_FEATURE([--gdwarf2 option], diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 9509c95acf14..2d574ad3d496 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -347,6 +347,7 @@ Objective-C and Objective-C++ Dialects}. -gstabs -gstabs+ -gstrict-dwarf -gno-strict-dwarf @gol -gcolumn-info -gno-column-info @gol -gstatement-frontiers -gno-statement-frontiers @gol +-gvariable-location-views -gno-variable-location-views @gol -gvms -gxcoff -gxcoff+ -gz@r{[}=@var{type}@r{]} @gol -fdebug-prefix-map=@var{old}=@var{new} -fdebug-types-section @gol -fno-eliminate-unused-debug-types @gol @@ -7093,6 +7094,24 @@ markers in the line number table. This is enabled by default when compiling with optimization (@option{-Os}, @option{-O}, @option{-O2}, @dots{}), and outputting DWARF 2 debug information at the normal level. +@item -gvariable-location-views +@item -gno-variable-location-views +@opindex gvariable-location-views +@opindex gno-variable-location-views +Augment variable location lists with progressive view numbers implied +from the line number table. This enables debug information consumers to +inspect state at certain points of the program, even if no instructions +associated with the corresponding source locations are present at that +point. If the assembler lacks support for view numbers in line number +tables, this will cause the compiler to emit the line number table, +which generally makes them somewhat less compact. The augmented line +number tables and location lists are fully backward-compatible, so they +can be consumed by debug information consumers that are not aware of +these augmentations, but they won't derive any benefit from them either. +This is enabled by default when outputting DWARF 2 debug information at +the normal level, as long as @code{-fvar-tracking-assignments} is +enabled and @code{-gstrict-dwarf} is not. + @item -gz@r{[}=@var{type}@r{]} @opindex gz Produce compressed debug sections in DWARF format, if that is supported. diff --git a/gcc/dwarf2asm.c b/gcc/dwarf2asm.c index 8e3e86f224c1..f19e6d65020e 100644 --- a/gcc/dwarf2asm.c +++ b/gcc/dwarf2asm.c @@ -768,6 +768,31 @@ dw2_asm_output_data_sleb128 (HOST_WIDE_INT value, } void +dw2_asm_output_symname_uleb128 (const char *lab1 ATTRIBUTE_UNUSED, + const char *comment, ...) +{ + va_list ap; + + va_start (ap, comment); + +#ifdef HAVE_AS_LEB128 + fputs ("\t.uleb128 ", asm_out_file); + assemble_name (asm_out_file, lab1); +#else + gcc_unreachable (); +#endif + + if (flag_debug_asm && comment) + { + fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START); + vfprintf (asm_out_file, comment, ap); + } + fputc ('\n', asm_out_file); + + va_end (ap); +} + +void dw2_asm_output_delta_uleb128 (const char *lab1 ATTRIBUTE_UNUSED, const char *lab2 ATTRIBUTE_UNUSED, const char *comment, ...) diff --git a/gcc/dwarf2asm.h b/gcc/dwarf2asm.h index 7fc87a0b0c94..d8370df0ac71 100644 --- a/gcc/dwarf2asm.h +++ b/gcc/dwarf2asm.h @@ -70,6 +70,10 @@ extern void dw2_asm_output_data_sleb128 (HOST_WIDE_INT, const char *, ...) ATTRIBUTE_NULL_PRINTF_2; +extern void dw2_asm_output_symname_uleb128 (const char *, + const char *, ...) + ATTRIBUTE_NULL_PRINTF_2; + extern void dw2_asm_output_delta_uleb128 (const char *, const char *, const char *, ...) ATTRIBUTE_NULL_PRINTF_3; diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 4f808b95519c..1d92a6eed5dd 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -1276,6 +1276,8 @@ struct GTY((for_user)) addr_table_entry { GTY ((desc ("%1.kind"))) addr; }; +typedef unsigned int var_loc_view; + /* Location lists are ranges + location descriptions for that range, so you can track variables that are in different places over their entire life. */ @@ -1285,9 +1287,11 @@ typedef struct GTY(()) dw_loc_list_struct { addr_table_entry *begin_entry; const char *end; /* Label for end of range */ char *ll_symbol; /* Label for beginning of location list. - Only on head of list */ + Only on head of list. */ + char *vl_symbol; /* Label for beginning of view list. Ditto. */ const char *section; /* Section this loclist is relative to */ dw_loc_descr_ref expr; + var_loc_view vbegin, vend; hashval_t hash; /* True if all addresses in this and subsequent lists are known to be resolved. */ @@ -1324,6 +1328,31 @@ dwarf_stack_op_name (unsigned int op) return "OP_"; } +/* Return TRUE iff we're to output location view lists as a separate + attribute next to the location lists, as an extension compatible + with DWARF 2 and above. */ + +static inline bool +dwarf2out_locviews_in_attribute () +{ + return debug_variable_location_views + && dwarf_version <= 5; +} + +/* Return TRUE iff we're to output location view lists as part of the + location lists, as proposed for standardization after DWARF 5. */ + +static inline bool +dwarf2out_locviews_in_loclist () +{ +#ifndef DW_LLE_view_pair + return false; +#else + return debug_variable_location_views + && dwarf_version >= 6; +#endif +} + /* Return a pointer to a newly allocated location description. Location descriptions are simple expression terms that can be strung together to form more complicated location (address) descriptions. */ @@ -1399,6 +1428,8 @@ dw_val_equal_p (dw_val_node *a, dw_val_node *b) return a->v.val_loc == b->v.val_loc; case dw_val_class_loc_list: return a->v.val_loc_list == b->v.val_loc_list; + case dw_val_class_view_list: + return a->v.val_view_list == b->v.val_view_list; case dw_val_class_die_ref: return a->v.val_die_ref.die == b->v.val_die_ref.die; case dw_val_class_fde_ref: @@ -2844,7 +2875,15 @@ enum dw_line_info_opcode { LI_set_epilogue_begin, /* Emit a DW_LNE_set_discriminator. */ - LI_set_discriminator + LI_set_discriminator, + + /* Output a Fixed Advance PC; the target PC is the label index; the + base PC is the previous LI_adv_address or LI_set_address entry. + We only use this when emitting debug views without assembler + support, at explicit user request. Ideally, we should only use + it when the offset might be zero but we can't tell: it's the only + way to maybe change the PC without resetting the view number. */ + LI_adv_address }; typedef struct GTY(()) dw_line_info_struct { @@ -2866,6 +2905,25 @@ struct GTY(()) dw_line_info_table { bool is_stmt; bool in_use; + /* This denotes the NEXT view number. + + If it is 0, it is known that the NEXT view will be the first view + at the given PC. + + If it is -1, we've advanced PC but we haven't emitted a line location yet, + so we shouldn't use this view number. + + The meaning of other nonzero values depends on whether we're + computing views internally or leaving it for the assembler to do + so. If we're emitting them internally, view denotes the view + number since the last known advance of PC. If we're leaving it + for the assembler, it denotes the LVU label number that we're + going to ask the assembler to assign. */ + var_loc_view view; + +#define RESET_NEXT_VIEW(x) ((x) = (var_loc_view)0) +#define RESETTING_VIEW_P(x) ((x) == (var_loc_view)0) + vec *entries; }; @@ -3067,6 +3125,41 @@ skeleton_chain_node; #endif #endif +/* Use assembler views in line directives if available. */ +#ifndef DWARF2_ASM_VIEW_DEBUG_INFO +#ifdef HAVE_AS_DWARF2_DEBUG_VIEW +#define DWARF2_ASM_VIEW_DEBUG_INFO 1 +#else +#define DWARF2_ASM_VIEW_DEBUG_INFO 0 +#endif +#endif + +/* A bit is set in ZERO_VIEW_P if we are using the assembler-supported + view computation, and it is refers to a view identifier for which + will not emit a label because it is known to map to a view number + zero. We won't allocate the bitmap if we're not using assembler + support for location views, but we have to make the variable + visible for GGC and for code that will be optimized out for lack of + support but that's still parsed and compiled. We could abstract it + out with macros, but it's not worth it. */ +static GTY(()) bitmap zero_view_p; + +/* Evaluate to TRUE iff N is known to identify the first location view + at its PC. When not using assembler location view computation, + that must be view number zero. Otherwise, ZERO_VIEW_P is allocated + and views label numbers recorded in it are the ones known to be + zero. */ +#define ZERO_VIEW_P(N) (zero_view_p \ + ? bitmap_bit_p (zero_view_p, (N)) \ + : (N) == 0) + +static bool +output_asm_line_debug_info (void) +{ + return DWARF2_ASM_VIEW_DEBUG_INFO + || (DWARF2_ASM_LINE_DEBUG_INFO && !debug_variable_location_views); +} + /* Minimum line offset in a special line info. opcode. This value was chosen to give a reasonable range of values. */ #define DWARF_LINE_BASE -10 @@ -3176,6 +3269,7 @@ struct GTY ((chain_next ("%h.next"))) var_loc_node { rtx GTY (()) loc; const char * GTY (()) label; struct var_loc_node * GTY (()) next; + var_loc_view view; }; /* Variable location list. */ @@ -3384,6 +3478,8 @@ static inline dw_loc_descr_ref AT_loc (dw_attr_node *); static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute, dw_loc_list_ref); static inline dw_loc_list_ref AT_loc_list (dw_attr_node *); +static void add_AT_view_list (dw_die_ref, enum dwarf_attribute); +static inline dw_loc_list_ref AT_loc_list (dw_attr_node *); static addr_table_entry *add_addr_table_entry (void *, enum ate_kind); static void remove_addr_table_entry (addr_table_entry *); static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool); @@ -3420,7 +3516,7 @@ static void equate_type_number_to_die (tree, dw_die_ref); static dw_die_ref lookup_decl_die (tree); static var_loc_list *lookup_decl_loc (const_tree); static void equate_decl_number_to_die (tree, dw_die_ref); -static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *); +static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *, var_loc_view); static void print_spaces (FILE *); static void print_die (dw_die_ref, FILE *); static void loc_checksum (dw_loc_descr_ref, struct md5_ctx *); @@ -3620,8 +3716,8 @@ static void gen_tagged_type_die (tree, dw_die_ref, enum debug_info_usage); static void gen_type_die_with_usage (tree, dw_die_ref, enum debug_info_usage); static void splice_child_die (dw_die_ref, dw_die_ref); static int file_info_cmp (const void *, const void *); -static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *, - const char *, const char *); +static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *, var_loc_view, + const char *, var_loc_view, const char *); static void output_loc_list (dw_loc_list_ref); static char *gen_internal_sym (const char *); static bool want_pubnames (void); @@ -4617,11 +4713,55 @@ AT_loc_list (dw_attr_node *a) return a->dw_attr_val.v.val_loc_list; } +static inline void +add_AT_view_list (dw_die_ref die, enum dwarf_attribute attr_kind) +{ + dw_attr_node attr; + + if (XCOFF_DEBUGGING_INFO && !HAVE_XCOFF_DWARF_EXTRAS) + return; + + attr.dw_attr = attr_kind; + attr.dw_attr_val.val_class = dw_val_class_view_list; + attr.dw_attr_val.val_entry = NULL; + attr.dw_attr_val.v.val_view_list = die; + add_dwarf_attr (die, &attr); + gcc_checking_assert (get_AT (die, DW_AT_location)); + gcc_assert (have_location_lists); +} + static inline dw_loc_list_ref * AT_loc_list_ptr (dw_attr_node *a) { - gcc_assert (a && AT_class (a) == dw_val_class_loc_list); - return &a->dw_attr_val.v.val_loc_list; + gcc_assert (a); + switch (AT_class (a)) + { + case dw_val_class_loc_list: + return &a->dw_attr_val.v.val_loc_list; + case dw_val_class_view_list: + { + dw_attr_node *l; + l = get_AT (a->dw_attr_val.v.val_view_list, DW_AT_location); + if (!l) + return NULL; + gcc_checking_assert (l + 1 == a); + return AT_loc_list_ptr (l); + } + default: + gcc_unreachable (); + } +} + +static inline dw_val_node * +view_list_to_loc_list_val_node (dw_val_node *val) +{ + gcc_assert (val->val_class == dw_val_class_view_list); + dw_attr_node *loc = get_AT (val->v.val_view_list, DW_AT_location); + if (!loc) + return NULL; + gcc_checking_assert (&(loc + 1)->dw_attr_val == val); + gcc_assert (AT_class (loc) == dw_val_class_loc_list); + return &loc->dw_attr_val; } struct addr_hasher : ggc_ptr_hash @@ -5891,7 +6031,7 @@ adjust_piece_list (rtx *dest, rtx *src, rtx *inner, /* Add a variable location node to the linked list for DECL. */ static struct var_loc_node * -add_var_loc_to_decl (tree decl, rtx loc_note, const char *label) +add_var_loc_to_decl (tree decl, rtx loc_note, const char *label, var_loc_view view) { unsigned int decl_id; var_loc_list *temp; @@ -5982,7 +6122,7 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label) /* TEMP->LAST here is either pointer to the last but one or last element in the chained list, LAST is pointer to the last element. */ - if (label && strcmp (last->label, label) == 0) + if (label && strcmp (last->label, label) == 0 && last->view == view) { /* For SRA optimized variables if there weren't any real insns since last note, just modify the last node. */ @@ -5998,7 +6138,7 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label) temp->last->next = NULL; unused = last; last = temp->last; - gcc_assert (strcmp (last->label, label) != 0); + gcc_assert (strcmp (last->label, label) != 0 || last->view != view); } else { @@ -6133,6 +6273,12 @@ print_dw_val (dw_val_node *val, bool recurse, FILE *outfile) fprintf (outfile, "location list -> label:%s", val->v.val_loc_list->ll_symbol); break; + case dw_val_class_view_list: + val = view_list_to_loc_list_val_node (val); + fprintf (outfile, "location list with views -> labels:%s and %s", + val->v.val_loc_list->ll_symbol, + val->v.val_loc_list->vl_symbol); + break; case dw_val_class_range_list: fprintf (outfile, "range list"); break; @@ -8993,6 +9139,7 @@ size_of_die (dw_die_ref die) } break; case dw_val_class_loc_list: + case dw_val_class_view_list: if (dwarf_split_debug_info && dwarf_version >= 5) { gcc_assert (AT_loc_list (a)->num_assigned); @@ -9364,6 +9511,7 @@ value_format (dw_attr_node *a) gcc_unreachable (); } case dw_val_class_loc_list: + case dw_val_class_view_list: if (dwarf_split_debug_info && dwarf_version >= 5 && AT_loc_list (a)->num_assigned) @@ -9638,7 +9786,8 @@ output_abbrev_section (void) expression. */ static inline dw_loc_list_ref -new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end, +new_loc_list (dw_loc_descr_ref expr, const char *begin, var_loc_view vbegin, + const char *end, var_loc_view vend, const char *section) { dw_loc_list_ref retlist = ggc_cleared_alloc (); @@ -9648,10 +9797,28 @@ new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end, retlist->end = end; retlist->expr = expr; retlist->section = section; + retlist->vbegin = vbegin; + retlist->vend = vend; return retlist; } +/* Return true iff there's any nonzero view number in the loc list. */ + +static bool +loc_list_has_views (dw_loc_list_ref list) +{ + if (!debug_variable_location_views) + return false; + + for (dw_loc_list_ref loc = list; + loc != NULL; loc = loc->dw_loc_next) + if (!ZERO_VIEW_P (loc->vbegin) || !ZERO_VIEW_P (loc->vend)) + return true; + + return false; +} + /* Generate a new internal symbol for this location list node, if it hasn't got one yet. */ @@ -9660,6 +9827,99 @@ gen_llsym (dw_loc_list_ref list) { gcc_assert (!list->ll_symbol); list->ll_symbol = gen_internal_sym ("LLST"); + + if (!loc_list_has_views (list)) + return; + + if (dwarf2out_locviews_in_attribute ()) + { + /* Use the same label_num for the view list. */ + label_num--; + list->vl_symbol = gen_internal_sym ("LVUS"); + } + else + list->vl_symbol = list->ll_symbol; +} + +/* Generate a symbol for the list, but only if we really want to emit + it as a list. */ + +static inline void +maybe_gen_llsym (dw_loc_list_ref list) +{ + if (!list || (!list->dw_loc_next && !loc_list_has_views (list))) + return; + + gen_llsym (list); +} + +/* Determine whether or not to skip loc_list entry CURR. If we're not + to skip it, and SIZEP is non-null, store the size of CURR->expr's + representation in *SIZEP. */ + +static bool +skip_loc_list_entry (dw_loc_list_ref curr, unsigned long *sizep = 0) +{ + /* Don't output an entry that starts and ends at the same address. */ + if (strcmp (curr->begin, curr->end) == 0 + && curr->vbegin == curr->vend && !curr->force) + return true; + + unsigned long size = size_of_locs (curr->expr); + + /* If the expression is too large, drop it on the floor. We could + perhaps put it into DW_TAG_dwarf_procedure and refer to that + in the expression, but >= 64KB expressions for a single value + in a single range are unlikely very useful. */ + if (dwarf_version < 5 && size > 0xffff) + return true; + + if (sizep) + *sizep = size; + + return false; +} + +/* Output a view pair loclist entry for CURR, if it requires one. */ + +static void +dwarf2out_maybe_output_loclist_view_pair (dw_loc_list_ref curr) +{ + if (!dwarf2out_locviews_in_loclist ()) + return; + + if (ZERO_VIEW_P (curr->vbegin) && ZERO_VIEW_P (curr->vend)) + return; + +#ifdef DW_LLE_view_pair + dw2_asm_output_data (1, DW_LLE_view_pair, + "DW_LLE_view_pair"); + +# if DWARF2_ASM_VIEW_DEBUG_INFO + if (ZERO_VIEW_P (curr->vbegin)) + dw2_asm_output_data_uleb128 (0, "Location view begin"); + else + { + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin); + dw2_asm_output_symname_uleb128 (label, "Location view begin"); + } + + if (ZERO_VIEW_P (curr->vend)) + dw2_asm_output_data_uleb128 (0, "Location view end"); + else + { + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend); + dw2_asm_output_symname_uleb128 (label, "Location view end"); + } +# else /* !DWARF2_ASM_VIEW_DEBUG_INFO */ + dw2_asm_output_data_uleb128 (curr->vbegin, "Location view begin"); + dw2_asm_output_data_uleb128 (curr->vend, "Location view end"); +# endif /* DWARF2_ASM_VIEW_DEBUG_INFO */ +#endif /* DW_LLE_view_pair */ + + return; } /* Output the location list given to us. */ @@ -9667,34 +9927,85 @@ gen_llsym (dw_loc_list_ref list) static void output_loc_list (dw_loc_list_ref list_head) { + int vcount = 0, lcount = 0; + if (list_head->emitted) return; list_head->emitted = true; + if (list_head->vl_symbol && dwarf2out_locviews_in_attribute ()) + { + ASM_OUTPUT_LABEL (asm_out_file, list_head->vl_symbol); + + for (dw_loc_list_ref curr = list_head; curr != NULL; + curr = curr->dw_loc_next) + { + if (skip_loc_list_entry (curr)) + continue; + + vcount++; + + /* ?? dwarf_split_debug_info? */ +#if DWARF2_ASM_VIEW_DEBUG_INFO + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + if (!ZERO_VIEW_P (curr->vbegin)) + { + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin); + dw2_asm_output_symname_uleb128 (label, + "View list begin (%s)", + list_head->vl_symbol); + } + else + dw2_asm_output_data_uleb128 (0, + "View list begin (%s)", + list_head->vl_symbol); + + if (!ZERO_VIEW_P (curr->vend)) + { + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend); + dw2_asm_output_symname_uleb128 (label, + "View list end (%s)", + list_head->vl_symbol); + } + else + dw2_asm_output_data_uleb128 (0, + "View list end (%s)", + list_head->vl_symbol); +#else /* !DWARF2_ASM_VIEW_DEBUG_INFO */ + dw2_asm_output_data_uleb128 (curr->vbegin, + "View list begin (%s)", + list_head->vl_symbol); + dw2_asm_output_data_uleb128 (curr->vend, + "View list end (%s)", + list_head->vl_symbol); +#endif + } + } + ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol); - dw_loc_list_ref curr = list_head; const char *last_section = NULL; const char *base_label = NULL; /* Walk the location list, and output each range + expression. */ - for (curr = list_head; curr != NULL; curr = curr->dw_loc_next) + for (dw_loc_list_ref curr = list_head; curr != NULL; + curr = curr->dw_loc_next) { unsigned long size; - /* Don't output an entry that starts and ends at the same address. */ - if (strcmp (curr->begin, curr->end) == 0 && !curr->force) - continue; - size = size_of_locs (curr->expr); - /* If the expression is too large, drop it on the floor. We could - perhaps put it into DW_TAG_dwarf_procedure and refer to that - in the expression, but >= 64KB expressions for a single value - in a single range are unlikely very useful. */ - if (dwarf_version < 5 && size > 0xffff) + + /* Skip this entry? If we skip it here, we must skip it in the + view list above as well. */ + if (skip_loc_list_entry (curr, &size)) continue; + + lcount++; + if (dwarf_version >= 5) { if (dwarf_split_debug_info) { + dwarf2out_maybe_output_loclist_view_pair (curr); /* For -gsplit-dwarf, emit DW_LLE_starx_length, which has uleb128 index into .debug_addr and uleb128 length. */ dw2_asm_output_data (1, DW_LLE_startx_length, @@ -9712,6 +10023,7 @@ output_loc_list (dw_loc_list_ref list_head) } else if (!have_multiple_function_sections && HAVE_AS_LEB128) { + dwarf2out_maybe_output_loclist_view_pair (curr); /* If all code is in .text section, the base address is already provided by the CU attributes. Use DW_LLE_offset_pair where both addresses are uleb128 encoded @@ -9762,6 +10074,7 @@ output_loc_list (dw_loc_list_ref list_head) length. */ if (last_section == NULL) { + dwarf2out_maybe_output_loclist_view_pair (curr); dw2_asm_output_data (1, DW_LLE_start_length, "DW_LLE_start_length (%s)", list_head->ll_symbol); @@ -9776,6 +10089,7 @@ output_loc_list (dw_loc_list_ref list_head) DW_LLE_base_address. */ else { + dwarf2out_maybe_output_loclist_view_pair (curr); dw2_asm_output_data (1, DW_LLE_offset_pair, "DW_LLE_offset_pair (%s)", list_head->ll_symbol); @@ -9791,6 +10105,7 @@ output_loc_list (dw_loc_list_ref list_head) DW_LLE_start_end with a pair of absolute addresses. */ else { + dwarf2out_maybe_output_loclist_view_pair (curr); dw2_asm_output_data (1, DW_LLE_start_end, "DW_LLE_start_end (%s)", list_head->ll_symbol); @@ -9869,6 +10184,9 @@ output_loc_list (dw_loc_list_ref list_head) "Location list terminator end (%s)", list_head->ll_symbol); } + + gcc_assert (!list_head->vl_symbol + || vcount == lcount * (dwarf2out_locviews_in_attribute () ? 1 : 0)); } /* Output a range_list offset into the .debug_ranges or .debug_rnglists @@ -9933,6 +10251,22 @@ output_loc_list_offset (dw_attr_node *a) "%s", dwarf_attr_name (a->dw_attr)); } +/* Output the offset into the debug_loc section. */ + +static void +output_view_list_offset (dw_attr_node *a) +{ + char *sym = (*AT_loc_list_ptr (a))->vl_symbol; + + gcc_assert (sym); + if (dwarf_split_debug_info) + dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label, + "%s", dwarf_attr_name (a->dw_attr)); + else + dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section, + "%s", dwarf_attr_name (a->dw_attr)); +} + /* Output an attribute's index or value appropriately. */ static void @@ -10158,6 +10492,10 @@ output_die (dw_die_ref die) output_loc_list_offset (a); break; + case dw_val_class_view_list: + output_view_list_offset (a); + break; + case dw_val_class_die_ref: if (AT_ref_external (a)) { @@ -10342,6 +10680,28 @@ output_die (dw_die_ref die) (unsigned long) die->die_offset); } +/* Output the dwarf version number. */ + +static void +output_dwarf_version () +{ + /* ??? For now, if -gdwarf-6 is specified, we output version 5 with + views in loclist. That will change eventually. */ + if (dwarf_version == 6) + { + static bool once; + if (!once) + { + warning (0, + "-gdwarf-6 is output as version 5 with incompatibilities"); + once = true; + } + dw2_asm_output_data (2, 5, "DWARF version number"); + } + else + dw2_asm_output_data (2, dwarf_version, "DWARF version number"); +} + /* Output the compilation unit that appears at the beginning of the .debug_info section, and precedes the DIE descriptions. */ @@ -10358,7 +10718,7 @@ output_compilation_unit_header (enum dwarf_unit_type ut) "Length of Compilation Unit Info"); } - dw2_asm_output_data (2, dwarf_version, "DWARF version number"); + output_dwarf_version (); if (dwarf_version >= 5) { const char *name; @@ -10570,7 +10930,7 @@ output_skeleton_debug_sections (dw_die_ref comp_unit, - DWARF_INITIAL_LENGTH_SIZE + size_of_die (comp_unit), "Length of Compilation Unit Info"); - dw2_asm_output_data (2, dwarf_version, "DWARF version number"); + output_dwarf_version (); if (dwarf_version >= 5) { dw2_asm_output_data (1, DW_UT_skeleton, "DW_UT_skeleton"); @@ -10869,7 +11229,7 @@ output_pubnames (vec *names) } /* Version number for pubnames/pubtypes is independent of dwarf version. */ - dw2_asm_output_data (2, 2, "DWARF Version"); + dw2_asm_output_data (2, 2, "DWARF pubnames/pubtypes version"); if (dwarf_split_debug_info) dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label, @@ -10951,7 +11311,7 @@ output_aranges (void) } /* Version number for aranges is still 2, even up to DWARF5. */ - dw2_asm_output_data (2, 2, "DWARF Version"); + dw2_asm_output_data (2, 2, "DWARF aranges version"); if (dwarf_split_debug_info) dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label, debug_skeleton_info_section, @@ -11212,7 +11572,7 @@ output_rnglists (void) dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1, "Length of Range Lists"); ASM_OUTPUT_LABEL (asm_out_file, l1); - dw2_asm_output_data (2, dwarf_version, "DWARF Version"); + output_dwarf_version (); dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size"); dw2_asm_output_data (1, 0, "Segment Size"); /* Emit the offset table only for -gsplit-dwarf. If we don't care @@ -11846,8 +12206,11 @@ output_one_line_info_table (dw_line_info_table *table) char line_label[MAX_ARTIFICIAL_LABEL_BYTES]; unsigned int current_line = 1; bool current_is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START; - dw_line_info_entry *ent; + dw_line_info_entry *ent, *prev_addr; size_t i; + unsigned int view; + + view = 0; FOR_EACH_VEC_SAFE_ELT (table->entries, i, ent) { @@ -11862,14 +12225,36 @@ output_one_line_info_table (dw_line_info_table *table) to determine when it is safe to use DW_LNS_fixed_advance_pc. */ ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, ent->val); + view = 0; + /* This can handle any delta. This takes 4+DWARF2_ADDR_SIZE bytes. */ - dw2_asm_output_data (1, 0, "set address %s", line_label); + dw2_asm_output_data (1, 0, "set address %s%s", line_label, + debug_variable_location_views + ? ", reset view to 0" : ""); dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL); dw2_asm_output_data (1, DW_LNE_set_address, NULL); dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL); + + prev_addr = ent; break; + case LI_adv_address: + { + ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, ent->val); + char prev_label[MAX_ARTIFICIAL_LABEL_BYTES]; + ASM_GENERATE_INTERNAL_LABEL (prev_label, LINE_CODE_LABEL, prev_addr->val); + + view++; + + dw2_asm_output_data (1, DW_LNS_fixed_advance_pc, "fixed advance PC, increment view to %i", view); + dw2_asm_output_delta (2, line_label, prev_label, + "from %s to %s", prev_label, line_label); + + prev_addr = ent; + break; + } + case LI_set_line: if (ent->val == current_line) { @@ -11977,7 +12362,7 @@ output_line_info (bool prologue_only) ASM_OUTPUT_LABEL (asm_out_file, l1); - dw2_asm_output_data (2, dwarf_version, "DWARF Version"); + output_dwarf_version (); if (dwarf_version >= 5) { dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size"); @@ -16343,6 +16728,7 @@ static dw_loc_list_ref dw_loc_list (var_loc_list *loc_list, tree decl, int want_address) { const char *endname, *secname; + var_loc_view endview; rtx varloc; enum var_init_status initialized; struct var_loc_node *node; @@ -16398,24 +16784,27 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address) && current_function_decl) { endname = cfun->fde->dw_fde_end; + endview = 0; range_across_switch = true; } /* The variable has a location between NODE->LABEL and NODE->NEXT->LABEL. */ else if (node->next) - endname = node->next->label; + endname = node->next->label, endview = node->next->view; /* If the variable has a location at the last label it keeps its location until the end of function. */ else if (!current_function_decl) - endname = text_end_label; + endname = text_end_label, endview = 0; else { ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL, current_function_funcdef_no); endname = ggc_strdup (label_id); + endview = 0; } - *listp = new_loc_list (descr, node->label, endname, secname); + *listp = new_loc_list (descr, node->label, node->view, + endname, endview, secname); if (TREE_CODE (decl) == PARM_DECL && node == loc_list->first && NOTE_P (node->loc) @@ -16438,12 +16827,12 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address) /* The variable has a location between NODE->LABEL and NODE->NEXT->LABEL. */ if (node->next) - endname = node->next->label; + endname = node->next->label, endview = node->next->view; else - endname = cfun->fde->dw_fde_second_end; + endname = cfun->fde->dw_fde_second_end, endview = 0; *listp = new_loc_list (descr, - cfun->fde->dw_fde_second_begin, - endname, secname); + cfun->fde->dw_fde_second_begin, 0, + endname, endview, secname); listp = &(*listp)->dw_loc_next; } } @@ -16455,8 +16844,7 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address) representable, we don't want to pretend a single entry that was applies to the entire scope in which the variable is available. */ - if (list && loc_list->first->next) - gen_llsym (list); + maybe_gen_llsym (list); return list; } @@ -17276,7 +17664,7 @@ loc_list_from_tree_1 (tree loc, int want_address, { if (dwarf_version >= 3 || !dwarf_strict) return new_loc_list (new_loc_descr (DW_OP_push_object_address, 0, 0), - NULL, NULL, NULL); + NULL, 0, NULL, 0, NULL); else return NULL; } @@ -18089,7 +18477,7 @@ loc_list_from_tree_1 (tree loc, int want_address, add_loc_descr_to_each (list_ret, new_loc_descr (op, size, 0)); } if (ret) - list_ret = new_loc_list (ret, NULL, NULL, NULL); + list_ret = new_loc_list (ret, NULL, 0, NULL, 0, NULL); return list_ret; } @@ -18413,12 +18801,25 @@ static inline void add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_list_ref descr) { + bool check_no_locviews = true; if (descr == 0) return; if (single_element_loc_list_p (descr)) add_AT_loc (die, attr_kind, descr->expr); else - add_AT_loc_list (die, attr_kind, descr); + { + add_AT_loc_list (die, attr_kind, descr); + gcc_assert (descr->ll_symbol); + if (attr_kind == DW_AT_location && descr->vl_symbol + && dwarf2out_locviews_in_attribute ()) + { + add_AT_view_list (die, DW_AT_GNU_locviews); + check_no_locviews = false; + } + } + + if (check_no_locviews) + gcc_assert (!get_AT (die, DW_AT_GNU_locviews)); } /* Add DW_AT_accessibility attribute to DIE if needed. */ @@ -19600,7 +20001,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) /* If the first partition contained no CFI adjustments, the CIE opcodes apply to the whole first partition. */ *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), - fde->dw_fde_begin, fde->dw_fde_end, section); + fde->dw_fde_begin, 0, fde->dw_fde_end, 0, section); list_tail =&(*list_tail)->dw_loc_next; start_label = last_label = fde->dw_fde_second_begin; } @@ -19616,7 +20017,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) if (!cfa_equal_p (&last_cfa, &next_cfa)) { *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), - start_label, last_label, section); + start_label, 0, last_label, 0, section); list_tail = &(*list_tail)->dw_loc_next; last_cfa = next_cfa; @@ -19638,14 +20039,14 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) if (!cfa_equal_p (&last_cfa, &next_cfa)) { *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), - start_label, last_label, section); + start_label, 0, last_label, 0, section); list_tail = &(*list_tail)->dw_loc_next; last_cfa = next_cfa; start_label = last_label; } *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), - start_label, fde->dw_fde_end, section); + start_label, 0, fde->dw_fde_end, 0, section); list_tail = &(*list_tail)->dw_loc_next; start_label = last_label = fde->dw_fde_second_begin; } @@ -19654,19 +20055,18 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) if (!cfa_equal_p (&last_cfa, &next_cfa)) { *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), - start_label, last_label, section); + start_label, 0, last_label, 0, section); list_tail = &(*list_tail)->dw_loc_next; start_label = last_label; } *list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset), - start_label, + start_label, 0, fde->dw_fde_second_begin - ? fde->dw_fde_second_end : fde->dw_fde_end, + ? fde->dw_fde_second_end : fde->dw_fde_end, 0, section); - if (list && list->dw_loc_next) - gen_llsym (list); + maybe_gen_llsym (list); return list; } @@ -26029,7 +26429,7 @@ maybe_emit_file (struct dwarf_file_data * fd) fd->emitted_number = 1; last_emitted_file = fd; - if (DWARF2_ASM_LINE_DEBUG_INFO) + if (output_asm_line_debug_info ()) { fprintf (asm_out_file, "\t.file %u ", fd->emitted_number); output_quoted_string (asm_out_file, @@ -26223,11 +26623,13 @@ dwarf2out_var_location (rtx_insn *loc_note) static rtx_insn *expected_next_loc_note; tree decl; bool var_loc_p; + var_loc_view view = 0; if (!NOTE_P (loc_note)) { if (CALL_P (loc_note)) { + RESET_NEXT_VIEW (cur_line_info_table->view); call_site_count++; if (SIBLING_CALL_P (loc_note)) tail_call_site_count++; @@ -26261,6 +26663,18 @@ dwarf2out_var_location (rtx_insn *loc_note) } } } + else if (!debug_variable_location_views) + gcc_unreachable (); + else if (JUMP_TABLE_DATA_P (loc_note)) + RESET_NEXT_VIEW (cur_line_info_table->view); + else if (GET_CODE (loc_note) == USE + || GET_CODE (loc_note) == CLOBBER + || GET_CODE (loc_note) == ASM_INPUT + || asm_noperands (loc_note) >= 0) + ; + else if (get_attr_min_length (loc_note) > 0) + RESET_NEXT_VIEW (cur_line_info_table->view); + return; } @@ -26324,10 +26738,11 @@ create_label: if (var_loc_p) { + const char *label = NOTE_DURING_CALL_P (loc_note) + ? last_postcall_label : last_label; + view = cur_line_info_table->view; decl = NOTE_VAR_LOCATION_DECL (loc_note); - newloc = add_var_loc_to_decl (decl, loc_note, - NOTE_DURING_CALL_P (loc_note) - ? last_postcall_label : last_label); + newloc = add_var_loc_to_decl (decl, loc_note, label, view); if (newloc == NULL) return; } @@ -26368,8 +26783,8 @@ create_label: else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0) continue; -#ifdef HAVE_attr_length - else if (get_attr_min_length (insn) == 0) +#ifdef HAVE_ATTR_length /* ??? We don't include insn-attr.h. */ + else if (HAVE_ATTR_length && get_attr_min_length (insn) == 0) continue; #endif else @@ -26437,7 +26852,10 @@ create_label: call_arg_loc_last = ca_loc; } else if (loc_note != NULL_RTX && !NOTE_DURING_CALL_P (loc_note)) - newloc->label = last_label; + { + newloc->label = last_label; + newloc->view = view; + } else { if (!last_postcall_label) @@ -26446,6 +26864,7 @@ create_label: last_postcall_label = ggc_strdup (loclabel); } newloc->label = last_postcall_label; + newloc->view = view; } if (var_loc_p && flag_debug_asm) @@ -26512,6 +26931,7 @@ new_line_info_table (void) table->file_num = 1; table->line_num = 1; table->is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START; + RESET_NEXT_VIEW (table->view); return table; } @@ -26560,7 +26980,7 @@ set_cur_line_info_table (section *sec) vec_safe_push (separate_line_info, table); } - if (DWARF2_ASM_LINE_DEBUG_INFO) + if (output_asm_line_debug_info ()) table->is_stmt = (cur_line_info_table ? cur_line_info_table->is_stmt : DWARF_LINE_DEFAULT_IS_STMT_START); @@ -26741,7 +27161,7 @@ dwarf2out_source_line (unsigned int line, unsigned int column, filename, line); } - if (DWARF2_ASM_LINE_DEBUG_INFO) + if (output_asm_line_debug_info ()) { /* Emit the .loc directive understood by GNU as. */ /* "\t.loc %u %u 0 is_stmt %u discriminator %u", @@ -26764,6 +27184,33 @@ dwarf2out_source_line (unsigned int line, unsigned int column, fputs (" discriminator ", asm_out_file); fprint_ul (asm_out_file, (unsigned long) discriminator); } + if (debug_variable_location_views) + { + static var_loc_view lvugid; + if (!lvugid) + { + gcc_assert (!zero_view_p); + zero_view_p = BITMAP_GGC_ALLOC (); + bitmap_set_bit (zero_view_p, 0); + } + if (RESETTING_VIEW_P (table->view)) + { + if (!table->in_use) + fputs (" view -0", asm_out_file); + else + fputs (" view 0", asm_out_file); + bitmap_set_bit (zero_view_p, lvugid); + table->view = ++lvugid; + } + else + { + fputs (" view ", asm_out_file); + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", table->view); + assemble_name (asm_out_file, label); + table->view = ++lvugid; + } + } putc ('\n', asm_out_file); } else @@ -26772,7 +27219,19 @@ dwarf2out_source_line (unsigned int line, unsigned int column, targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, label_num); - push_dw_line_info_entry (table, LI_set_address, label_num); + if (debug_variable_location_views && table->view) + push_dw_line_info_entry (table, LI_adv_address, label_num); + else + push_dw_line_info_entry (table, LI_set_address, label_num); + if (debug_variable_location_views) + { + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s view %s%d\n", + ASM_COMMENT_START, + table->in_use ? "" : "-", + table->view); + table->view++; + } if (file_num != table->file_num) push_dw_line_info_entry (table, LI_set_file, file_num); if (discriminator != table->discrim_num) @@ -27447,9 +27906,10 @@ init_sections_and_labels (bool early_lto_debug) SECTION_DEBUG, NULL); debug_str_section = get_section (DEBUG_STR_SECTION, DEBUG_STR_SECTION_FLAGS, NULL); - if (!dwarf_split_debug_info && !DWARF2_ASM_LINE_DEBUG_INFO) + if (!dwarf_split_debug_info && !output_asm_line_debug_info ()) debug_line_str_section = get_section (DEBUG_LINE_STR_SECTION, DEBUG_STR_SECTION_FLAGS, NULL); + debug_ranges_section = get_section (dwarf_version >= 5 ? DEBUG_RNGLISTS_SECTION : DEBUG_RANGES_SECTION, @@ -27828,6 +28288,11 @@ prune_unused_types_walk_attribs (dw_die_ref die) prune_unused_types_walk_loc_descr (list->expr); break; + case dw_val_class_view_list: + /* This points to a loc_list in another attribute, so it's + already covered. */ + break; + case dw_val_class_die_ref: /* A reference to another DIE. Make sure that it will get emitted. @@ -28927,6 +29392,8 @@ optimize_string_length (dw_attr_node *a) if (d->expr && non_dwarf_expression (d->expr)) non_dwarf_expr = true; break; + case dw_val_class_view_list: + gcc_unreachable (); case dw_val_class_loc: lv = AT_loc (av); if (lv == NULL) @@ -28971,7 +29438,7 @@ optimize_string_length (dw_attr_node *a) lv = copy_deref_exprloc (d->expr); if (lv) { - *p = new_loc_list (lv, d->begin, d->end, d->section); + *p = new_loc_list (lv, d->begin, d->vbegin, d->end, d->vend, d->section); p = &(*p)->dw_loc_next; } else if (!dwarf_strict && d->expr) @@ -29041,6 +29508,7 @@ resolve_addr (dw_die_ref die) { gcc_assert (!next->ll_symbol); next->ll_symbol = (*curr)->ll_symbol; + next->vl_symbol = (*curr)->vl_symbol; } if (dwarf_split_debug_info) remove_loc_list_addr_table_entries (l); @@ -29066,6 +29534,21 @@ resolve_addr (dw_die_ref die) ix--; } break; + case dw_val_class_view_list: + { + gcc_checking_assert (a->dw_attr == DW_AT_GNU_locviews); + gcc_checking_assert (dwarf2out_locviews_in_attribute ()); + dw_val_node *llnode + = view_list_to_loc_list_val_node (&a->dw_attr_val); + /* If we no longer have a loclist, or it no longer needs + views, drop this attribute. */ + if (!llnode || !llnode->v.val_loc_list->vl_symbol) + { + remove_AT (die, a->dw_attr); + ix--; + } + break; + } case dw_val_class_loc: { dw_loc_descr_ref l = AT_loc (a); @@ -29462,6 +29945,8 @@ hash_loc_list (dw_loc_list_ref list_head) { hstate.add (curr->begin, strlen (curr->begin) + 1); hstate.add (curr->end, strlen (curr->end) + 1); + hstate.add_object (curr->vbegin); + hstate.add_object (curr->vend); if (curr->section) hstate.add (curr->section, strlen (curr->section) + 1); hash_locs (curr->expr, hstate); @@ -29683,6 +30168,7 @@ loc_list_hasher::equal (const dw_loc_list_struct *a, || strcmp (a->end, b->end) != 0 || (a->section == NULL) != (b->section == NULL) || (a->section && strcmp (a->section, b->section) != 0) + || a->vbegin != b->vbegin || a->vend != b->vend || !compare_locs (a->expr, b->expr)) break; return a == NULL && b == NULL; @@ -29701,6 +30187,8 @@ optimize_location_lists_1 (dw_die_ref die, loc_list_hash_type *htab) dw_attr_node *a; unsigned ix; dw_loc_list_struct **slot; + bool drop_locviews = false; + bool has_locviews = false; FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a) if (AT_class (a) == dw_val_class_loc_list) @@ -29711,11 +30199,33 @@ optimize_location_lists_1 (dw_die_ref die, loc_list_hash_type *htab) hash_loc_list (list); slot = htab->find_slot_with_hash (list, list->hash, INSERT); if (*slot == NULL) - *slot = list; + { + *slot = list; + if (loc_list_has_views (list)) + gcc_assert (list->vl_symbol); + else if (list->vl_symbol) + { + drop_locviews = true; + list->vl_symbol = NULL; + } + } else - a->dw_attr_val.v.val_loc_list = *slot; + { + if (list->vl_symbol && !(*slot)->vl_symbol) + drop_locviews = true; + a->dw_attr_val.v.val_loc_list = *slot; + } + } + else if (AT_class (a) == dw_val_class_view_list) + { + gcc_checking_assert (a->dw_attr == DW_AT_GNU_locviews); + has_locviews = true; } + + if (drop_locviews && has_locviews) + remove_AT (die, DW_AT_GNU_locviews); + FOR_EACH_CHILD (die, c, optimize_location_lists_1 (c, htab)); } @@ -29740,7 +30250,7 @@ index_location_lists (dw_die_ref die) /* Don't index an entry that has already been indexed or won't be output. */ if (curr->begin_entry != NULL - || (strcmp (curr->begin, curr->end) == 0 && !curr->force)) + || skip_loc_list_entry (curr)) continue; curr->begin_entry @@ -30164,7 +30674,7 @@ dwarf2out_finish (const char *) dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1, "Length of Location Lists"); ASM_OUTPUT_LABEL (asm_out_file, l1); - dw2_asm_output_data (2, dwarf_version, "DWARF Version"); + output_dwarf_version (); dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size"); dw2_asm_output_data (1, 0, "Segment Size"); dw2_asm_output_data (4, dwarf_split_debug_info ? loc_list_idx : 0, @@ -30223,7 +30733,7 @@ dwarf2out_finish (const char *) used by the debug_info section are marked as 'used'. */ switch_to_section (debug_line_section); ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label); - if (! DWARF2_ASM_LINE_DEBUG_INFO) + if (! output_asm_line_debug_info ()) output_line_info (false); if (dwarf_split_debug_info && info_section_emitted) diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h index 940247316d39..a7653ceb6182 100644 --- a/gcc/dwarf2out.h +++ b/gcc/dwarf2out.h @@ -157,7 +157,8 @@ enum dw_val_class dw_val_class_discr_list, dw_val_class_const_implicit, dw_val_class_unsigned_const_implicit, - dw_val_class_file_implicit + dw_val_class_file_implicit, + dw_val_class_view_list }; /* Describe a floating point constant value, or a vector constant value. */ @@ -200,6 +201,7 @@ struct GTY(()) dw_val_node { rtx GTY ((tag ("dw_val_class_addr"))) val_addr; unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_offset"))) val_offset; dw_loc_list_ref GTY ((tag ("dw_val_class_loc_list"))) val_loc_list; + dw_die_ref GTY ((tag ("dw_val_class_view_list"))) val_view_list; dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc; HOST_WIDE_INT GTY ((default)) val_int; unsigned HOST_WIDE_INT diff --git a/gcc/final.c b/gcc/final.c index b343063faa6d..c6a1d5b7e05a 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -81,6 +81,7 @@ along with GCC; see the file COPYING3. If not see #include "asan.h" #include "rtl-iter.h" #include "print-rtl.h" +#include "langhooks.h" #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" /* Needed for external data declarations. */ @@ -110,6 +111,7 @@ along with GCC; see the file COPYING3. If not see /* Bitflags used by final_scan_insn. */ #define SEEN_NOTE 1 #define SEEN_EMITTED 2 +#define SEEN_NEXT_VIEW 4 /* Last insn processed by final_scan_insn. */ static rtx_insn *debug_insn; @@ -1752,6 +1754,66 @@ get_some_local_dynamic_name () return 0; } +/* Arrange for us to emit a source location note before any further + real insns or section changes, by setting the SEEN_NEXT_VIEW bit in + *SEEN, as long as we are keeping track of location views. The bit + indicates we have referenced the next view at the current PC, so we + have to emit it. This should be called next to the var_location + debug hook. */ + +static inline void +set_next_view_needed (int *seen) +{ + if (debug_variable_location_views) + *seen |= SEEN_NEXT_VIEW; +} + +/* Clear the flag in *SEEN indicating we need to emit the next view. + This should be called next to the source_line debug hook. */ + +static inline void +clear_next_view_needed (int *seen) +{ + *seen &= ~SEEN_NEXT_VIEW; +} + +/* Test whether we have a pending request to emit the next view in + *SEEN, and emit it if needed, clearing the request bit. */ + +static inline void +maybe_output_next_view (int *seen) +{ + if ((*seen & SEEN_NEXT_VIEW) != 0) + { + clear_next_view_needed (seen); + (*debug_hooks->source_line) (last_linenum, last_columnnum, + last_filename, last_discriminator, + false); + } +} + +/* We want to emit param bindings (before the first begin_stmt) in the + initial view, if we are emitting views. To that end, we may + consume initial notes in the function, processing them in + final_start_function, before signaling the beginning of the + prologue, rather than in final. + + We don't test whether the DECLs are PARM_DECLs: the assumption is + that there will be a NOTE_INSN_BEGIN_STMT marker before any + non-parameter NOTE_INSN_VAR_LOCATION. It's ok if the marker is not + there, we'll just have more variable locations bound in the initial + view, which is consistent with their being bound without any code + that would give them a value. */ + +static inline bool +in_initial_view_p (rtx_insn *insn) +{ + return !DECL_IGNORED_P (current_function_decl) + && debug_variable_location_views + && insn && GET_CODE (insn) == NOTE + && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION; +} + /* Output assembler code for the start of a function, and initialize some of the variables in this file for the new function. The label for the function and associated @@ -1759,12 +1821,15 @@ get_some_local_dynamic_name () FIRST is the first insn of the rtl for the function being compiled. FILE is the file to write assembler code to. + SEEN should be initially set to zero, and it may be updated to + indicate we have references to the next location view, that would + require us to emit it at the current PC. OPTIMIZE_P is nonzero if we should eliminate redundant test and compare insns. */ -void -final_start_function (rtx_insn *first, FILE *file, - int optimize_p ATTRIBUTE_UNUSED) +static void +final_start_function_1 (rtx_insn **firstp, FILE *file, int *seen, + int optimize_p ATTRIBUTE_UNUSED) { block_depth = 0; @@ -1782,8 +1847,21 @@ final_start_function (rtx_insn *first, FILE *file, if (flag_sanitize & SANITIZE_ADDRESS) asan_function_start (); + rtx_insn *first = *firstp; + if (in_initial_view_p (first)) + { + do + { + final_scan_insn (first, file, 0, 0, seen); + first = NEXT_INSN (first); + } + while (in_initial_view_p (first)); + *firstp = first; + } + if (!DECL_IGNORED_P (current_function_decl)) - debug_hooks->begin_prologue (last_linenum, last_columnnum, last_filename); + debug_hooks->begin_prologue (last_linenum, last_columnnum, + last_filename); if (!dwarf2_debug_info_emitted_p (current_function_decl)) dwarf2out_begin_prologue (0, 0, NULL); @@ -1858,6 +1936,17 @@ final_start_function (rtx_insn *first, FILE *file, profile_after_prologue (file); } +/* This is an exported final_start_function_1, callable without SEEN. */ + +void +final_start_function (rtx_insn *first, FILE *file, + int optimize_p ATTRIBUTE_UNUSED) +{ + int seen = 0; + final_start_function_1 (&first, file, &seen, optimize_p); + gcc_assert (seen == 0); +} + static void profile_after_prologue (FILE *file ATTRIBUTE_UNUSED) { @@ -1987,11 +2076,10 @@ dump_basic_block_info (FILE *file, rtx_insn *insn, basic_block *start_to_bb, /* Output assembler code for some insns: all or part of a function. For description of args, see `final_start_function', above. */ -void -final (rtx_insn *first, FILE *file, int optimize_p) +static void +final_1 (rtx_insn *first, FILE *file, int seen, int optimize_p) { rtx_insn *insn, *next; - int seen = 0; /* Used for -dA dump. */ basic_block *start_to_bb = NULL; @@ -2058,6 +2146,8 @@ final (rtx_insn *first, FILE *file, int optimize_p) insn = final_scan_insn (insn, file, optimize_p, 0, &seen); } + maybe_output_next_view (&seen); + if (flag_debug_asm) { free (start_to_bb); @@ -2074,6 +2164,23 @@ final (rtx_insn *first, FILE *file, int optimize_p) delete_insn (insn); } } + +/* This is an exported final_1, callable without SEEN. */ + +void +final (rtx_insn *first, FILE *file, int optimize_p) +{ + /* Those that use the internal final_start_function_1/final_1 API + skip initial debug bind notes in final_start_function_1, and pass + the modified FIRST to final_1. But those that use the public + final_start_function/final APIs, final_start_function can't move + FIRST because it's not passed by reference, so if they were + skipped there, skip them again here. */ + while (in_initial_view_p (first)) + first = NEXT_INSN (first); + + final_1 (first, file, 0, optimize_p); +} const char * get_insn_template (int code, rtx insn) @@ -2214,6 +2321,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, break; case NOTE_INSN_SWITCH_TEXT_SECTIONS: + maybe_output_next_view (seen); + in_cold_section_p = !in_cold_section_p; if (dwarf2out_do_frame ()) @@ -2353,6 +2462,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, break; case NOTE_INSN_BLOCK_END: + maybe_output_next_view (seen); + if (debug_info_level == DINFO_LEVEL_NORMAL || debug_info_level == DINFO_LEVEL_VERBOSE || write_symbols == DWARF2_DEBUG @@ -2409,7 +2520,10 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, case NOTE_INSN_VAR_LOCATION: case NOTE_INSN_CALL_ARG_LOCATION: if (!DECL_IGNORED_P (current_function_decl)) - debug_hooks->var_location (insn); + { + debug_hooks->var_location (insn); + set_next_view_needed (seen); + } break; case NOTE_INSN_BEGIN_STMT: @@ -2420,6 +2534,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, (*debug_hooks->source_line) (last_linenum, last_columnnum, last_filename, last_discriminator, true); + clear_next_view_needed (seen); } break; @@ -2615,6 +2730,10 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, switch_to_section (current_function_section ()); + if (debug_variable_location_views + && !DECL_IGNORED_P (current_function_decl)) + debug_hooks->var_location (insn); + break; } /* Output this line note if it is the first or the last line @@ -2627,7 +2746,12 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, (*debug_hooks->source_line) (last_linenum, last_columnnum, last_filename, last_discriminator, is_stmt); + clear_next_view_needed (seen); } + else + maybe_output_next_view (seen); + + gcc_checking_assert (!DEBUG_INSN_P (insn)); if (GET_CODE (body) == PARALLEL && GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT) @@ -3094,7 +3218,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, /* Let the debug info back-end know about this call. We do this only after the instruction has been emitted because labels that may be created to reference the call instruction must appear after it. */ - if (call_insn != NULL && !DECL_IGNORED_P (current_function_decl)) + if ((debug_variable_location_views || call_insn != NULL) + && !DECL_IGNORED_P (current_function_decl)) debug_hooks->var_location (insn); current_output_insn = debug_insn = 0; @@ -4525,8 +4650,10 @@ rest_of_handle_final (void) variable_tracking_main (); assemble_start_function (current_function_decl, fnname); - final_start_function (get_insns (), asm_out_file, optimize); - final (get_insns (), asm_out_file, optimize); + rtx_insn *first = get_insns (); + int seen = 0; + final_start_function_1 (&first, asm_out_file, &seen, optimize); + final_1 (first, asm_out_file, seen, optimize); if (flag_ipa_ra && !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl))) collect_fn_hard_reg_usage (); diff --git a/gcc/opts.c b/gcc/opts.c index ac383d48ec18..2abae2da47e5 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -2364,7 +2364,7 @@ common_handle_option (struct gcc_options *opts, /* FALLTHRU */ case OPT_gdwarf_: - if (value < 2 || value > 5) + if (value < 2 || value > 6) error_at (loc, "dwarf version %d is not supported", value); else opts->x_dwarf_version = value; diff --git a/gcc/toplev.c b/gcc/toplev.c index 0b9f1f546279..55d6f21aaeb7 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -1541,6 +1541,14 @@ process_options (void) debug_nonbind_markers_p = optimize && debug_info_level >= DINFO_LEVEL_NORMAL && (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG); + if (debug_variable_location_views == AUTODETECT_VALUE) + { + debug_variable_location_views = flag_var_tracking + && debug_info_level >= DINFO_LEVEL_NORMAL + && (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG) + && !dwarf_strict; + } + if (flag_tree_cselim == AUTODETECT_VALUE) { if (HAVE_conditional_move) diff --git a/include/dwarf2.def b/include/dwarf2.def index 2a3b23fef873..f3fa4009207b 100644 --- a/include/dwarf2.def +++ b/include/dwarf2.def @@ -443,6 +443,7 @@ DW_AT (DW_AT_GNU_pubtypes, 0x2135) /* Attribute for discriminator. See http://gcc.gnu.org/wiki/Discriminator */ DW_AT (DW_AT_GNU_discriminator, 0x2136) +DW_AT (DW_AT_GNU_locviews, 0x2137) /* VMS extensions. */ DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201) /* GNAT extensions. */ diff --git a/include/dwarf2.h b/include/dwarf2.h index a2e022dbdb35..fd76d82e6eb7 100644 --- a/include/dwarf2.h +++ b/include/dwarf2.h @@ -298,6 +298,14 @@ enum dwarf_location_list_entry_type DW_LLE_start_end = 0x07, DW_LLE_start_length = 0x08, + /* + has the proposal for now; only available to list members. + + A (possibly updated) copy of the proposal is available at + . */ + DW_LLE_GNU_view_pair = 0x09, +#define DW_LLE_view_pair DW_LLE_GNU_view_pair + /* Former extension for Fission. See http://gcc.gnu.org/wiki/DebugFission. */ DW_LLE_GNU_end_of_list_entry = 0x00, From patchwork Fri Nov 10 02:34:47 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Oliva X-Patchwork-Id: 836586 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-466478-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="MRf7liIq"; dkim-atps=neutral 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 3yY42h31Vpz9t2M for ; Fri, 10 Nov 2017 13:38:04 +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:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=T90z6931FeNbNngBa5dRhDJWhi8mpXfXIYcoZFitWSlsOn0M9wZ0x eofWzWSFal6XyTxUqleHEpxutzmkHZ0muIhiyS7BL2nIdA5VbLd9LH7PUzP2z/Ny 3bZfrDOmwosyJmT5YmR4OOiqAOq0yBuavbCegLtzRM8acWNvGC3bDU= 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:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=aElB8+wKoMbbA4VQ0W1gHAOA+Pk=; b=MRf7liIqHAMSZJgj8bxw mTpWRDhtsVuNYYkdPhPbnHFdbikx59NjDpUxYulFaK1/WsnuTs2fZ+nSCDmujmOE 468WNWRh76OMH7vkeLuS+TQfxaEC412AGBtQNO2etmujnyDjB2PepDfJDVwtttQH +zlOJ429Oafq6ECFWDuL6Tg= Received: (qmail 99394 invoked by alias); 10 Nov 2017 02:36:45 -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 99309 invoked by uid 89); 10 Nov 2017 02:36:45 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=4227 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 ESMTP; Fri, 10 Nov 2017 02:36:43 +0000 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E291C4A6E6; Fri, 10 Nov 2017 02:36:41 +0000 (UTC) Received: from freie.home (ovpn04.gateway.prod.ext.phx2.redhat.com [10.5.9.4]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 6FA1462460; Fri, 10 Nov 2017 02:36:39 +0000 (UTC) Received: from frit.home (frit.home [172.31.160.7]) by freie.home (8.15.2/8.15.2) with ESMTP id vAA2ZEBG003201; Fri, 10 Nov 2017 00:35:55 -0200 From: Alexandre Oliva To: Richard Biener , Jeff Law , Jason Merrill Cc: GCC Patches , Alexandre Oliva Subject: [SFN+LVU+IEPM v4 8/9] [IEPM] Introduce debug hook for inline entry point markers Date: Fri, 10 Nov 2017 00:34:47 -0200 Message-Id: <20171110023448.28164-8-aoliva@redhat.com> In-Reply-To: References: The inline_entry hook will be given a definition in a later patch. for gcc/ChangeLog * debug.h (gcc_debug_hooks): Add inline_entry. * dbxout.c (dbx_debug_hooks, xcoff_debug_hooks): Likewise. * debug.c (do_nothing_debug_hooks): Likewise. * vmsdbgout.c (vmsdbg_debug_hooks): Likewise. * dwarf2out.c (dwarf2_debug_hooks): Likewise. (dwarf2_lineno_debug_hooks): Likewise. --- gcc/dbxout.c | 2 ++ gcc/debug.c | 1 + gcc/debug.h | 3 +++ gcc/dwarf2out.c | 2 ++ gcc/vmsdbgout.c | 1 + 5 files changed, 9 insertions(+) diff --git a/gcc/dbxout.c b/gcc/dbxout.c index 49a858339f8c..bb0650ddcacf 100644 --- a/gcc/dbxout.c +++ b/gcc/dbxout.c @@ -379,6 +379,7 @@ const struct gcc_debug_hooks dbx_debug_hooks = debug_nothing_rtx_code_label, /* label */ dbxout_handle_pch, /* handle_pch */ debug_nothing_rtx_insn, /* var_location */ + debug_nothing_tree, /* inline_entry */ debug_nothing_tree, /* size_function */ debug_nothing_void, /* switch_text_section */ debug_nothing_tree_tree, /* set_name */ @@ -421,6 +422,7 @@ const struct gcc_debug_hooks xcoff_debug_hooks = debug_nothing_rtx_code_label, /* label */ dbxout_handle_pch, /* handle_pch */ debug_nothing_rtx_insn, /* var_location */ + debug_nothing_tree, /* inline_entry */ debug_nothing_tree, /* size_function */ debug_nothing_void, /* switch_text_section */ debug_nothing_tree_tree, /* set_name */ diff --git a/gcc/debug.c b/gcc/debug.c index 4db94c3e675d..c0bc66764121 100644 --- a/gcc/debug.c +++ b/gcc/debug.c @@ -55,6 +55,7 @@ const struct gcc_debug_hooks do_nothing_debug_hooks = debug_nothing_rtx_code_label, /* label */ debug_nothing_int, /* handle_pch */ debug_nothing_rtx_insn, /* var_location */ + debug_nothing_tree, /* inline_entry */ debug_nothing_tree, /* size_function */ debug_nothing_void, /* switch_text_section */ debug_nothing_tree_tree, /* set_name */ diff --git a/gcc/debug.h b/gcc/debug.h index 19b27848ca8b..b521d7dbf856 100644 --- a/gcc/debug.h +++ b/gcc/debug.h @@ -176,6 +176,9 @@ struct gcc_debug_hooks /* Called from final_scan_insn for any NOTE_INSN_VAR_LOCATION note. */ void (* var_location) (rtx_insn *); + /* Called from final_scan_insn for any NOTE_INSN_INLINE_ENTRY note. */ + void (* inline_entry) (tree block); + /* Called from finalize_size_functions for size functions so that their body can be encoded in the debug info to describe the layout of variable-length structures. */ diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 1d92a6eed5dd..5fdac8269654 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -2773,6 +2773,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = debug_nothing_rtx_code_label, /* label */ debug_nothing_int, /* handle_pch */ dwarf2out_var_location, + debug_nothing_tree, /* inline_entry */ dwarf2out_size_function, /* size_function */ dwarf2out_switch_text_section, dwarf2out_set_name, @@ -2813,6 +2814,7 @@ const struct gcc_debug_hooks dwarf2_lineno_debug_hooks = debug_nothing_rtx_code_label, /* label */ debug_nothing_int, /* handle_pch */ debug_nothing_rtx_insn, /* var_location */ + debug_nothing_tree, /* inline_entry */ debug_nothing_tree, /* size_function */ debug_nothing_void, /* switch_text_section */ debug_nothing_tree_tree, /* set_name */ diff --git a/gcc/vmsdbgout.c b/gcc/vmsdbgout.c index 580dd2840162..83ba2aee7ad4 100644 --- a/gcc/vmsdbgout.c +++ b/gcc/vmsdbgout.c @@ -205,6 +205,7 @@ const struct gcc_debug_hooks vmsdbg_debug_hooks debug_nothing_rtx_code_label, /* label */ debug_nothing_int, /* handle_pch */ debug_nothing_rtx_insn, /* var_location */ + debug_nothing_tree, /* inline_entry */ debug_nothing_tree, /* size_function */ debug_nothing_void, /* switch_text_section */ debug_nothing_tree_tree, /* set_name */ From patchwork Fri Nov 10 02:34:48 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Oliva X-Patchwork-Id: 836588 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-466480-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="qTgDLulH"; dkim-atps=neutral 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 3yY43Y65Gcz9t2M for ; Fri, 10 Nov 2017 13:38:49 +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:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=X6G1VhW1WG7YEKgpQMZGlqroVk928y8gOKCq0mrKH2vUrJ7DE0lfE Qivz+8gfBLH+6LLpgCx0QeO4znvgzuvEXRhxzrWVjjx3yU9BSjl3+cvoKYFYlFRa LOuDfCsakmMbyip3TcuWi5VjmXDoHiix8rmj22ikMXdyaFSnbI/ZJQ= 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:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=h0h8NtrceyzNdmVra+BFYb0NNps=; b=qTgDLulHJz+jSW5LelwQ HuwonMD6Q3k8x8v+M7D+ptT5SS+BuScIS37lf6paa92KtD7p4WH57V/M9RaJSLnz X8HCHAz3FWkHvfzlkKwv6QeVbrkgZvdOnj9/yTUvDTviOeSBA8vB4AVBJdgUXhCB SPU4JF+dHVX3OcUhCulWvTA= Received: (qmail 101035 invoked by alias); 10 Nov 2017 02:37:11 -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 100985 invoked by uid 89); 10 Nov 2017 02:37:10 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=sk:DW_AT_s, sk:dw_at_s 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 ESMTP; Fri, 10 Nov 2017 02:37:05 +0000 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 7F56A81226; Fri, 10 Nov 2017 02:37:04 +0000 (UTC) Received: from freie.home (ovpn04.gateway.prod.ext.phx2.redhat.com [10.5.9.4]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 6328F12A41; Fri, 10 Nov 2017 02:37:03 +0000 (UTC) Received: from frit.home (frit.home [172.31.160.7]) by freie.home (8.15.2/8.15.2) with ESMTP id vAA2ZEBH003201; Fri, 10 Nov 2017 00:36:00 -0200 From: Alexandre Oliva To: Richard Biener , Jeff Law , Jason Merrill Cc: GCC Patches , Alexandre Oliva Subject: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers Date: Fri, 10 Nov 2017 00:34:48 -0200 Message-Id: <20171110023448.28164-9-aoliva@redhat.com> In-Reply-To: References: Output DW_AT_entry_pc based on markers. Introduce DW_AT_GNU_entry_view as a DWARF extension. If views are enabled are we're not in strict compliance mode, output DW_AT_GNU_entry_view if it might be nonzero. This patch depends on SFN and LVU patchsets, and on the IEPM patch that introduces the inline_entry debug hook. for include/ChangeLog * dwarf2.def (DW_AT_GNU_entry_view): New. for gcc/ChangeLog * cfgexpand.c (expand_gimple_basic_block): Handle inline entry markers. * dwarf2out.c (dwarf2_debug_hooks): Enable inline_entry hook. (BLOCK_INLINE_ENTRY_LABEL): New. (dwarf2out_var_location): Disregard inline entry markers. (inline_entry_data): New struct. (inline_entry_data_hasher): New hashtable type. (inline_entry_data_hasher::hash): New. (inline_entry_data_hasher::equal): New. (inline_entry_data_table): New variable. (add_high_low_attributes): Add DW_AT_entry_pc and DW_AT_GNU_entry_view attributes if a pending entry is found in inline_entry_data_table. Add old entry_pc attribute only if debug nonbinding markers are disabled. (gen_inlined_subroutine_die): Set BLOCK_DIE if nonbinding markers are enabled. (block_within_block_p, dwarf2out_inline_entry): New. (dwarf2out_finish): Check that no entries remained in inline_entry_data_table. * final.c (reemit_insn_block_notes): Handle inline entry notes. (final_scan_insn, notice_source_line): Likewise. (rest_of_clean_state): Skip inline entry markers. * gimple-pretty-print.c (dump_gimple_debug): Handle inline entry markers. * gimple.c (gimple_build_debug_inline_entry): New. * gimple.h (enum gimple_debug_subcode): Add GIMPLE_DEBUG_INLINE_ENTRY. (gimple_build_debug_inline_entry): Declare. (gimple_debug_inline_entry_p): New. (gimple_debug_nonbind_marker_p): Adjust. * insn-notes.def (INLINE_ENTRY): New. * print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle inline entry marker notes. (print_insn): Likewise. * rtl.h (NOTE_MARKER_P): Add INLINE_ENTRY support. (INSN_DEBUG_MARKER_KIND): Likewise. (GEN_RTX_DEBUG_MARKER_INLINE_ENTRY_PAT): New. * tree-inline.c (expand_call_inline): Build and insert debug_inline_entry stmt. * tree-ssa-live.c (remove_unused_scope_block_p): Preserve inline entry blocks early, if nonbind markers are enabled. (dump_scope_block): Dump fragment info. * var-tracking.c (reemit_marker_as_note): Handle inline entry note. * doc/gimple.texi (gimple_debug_inline_entry_p): New. (gimple_build_debug_inline_entry): New. * doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers): Enable/disable inline entry points too. * doc/rtl.texi (NOTE_INSN_INLINE_ENTRY): New. (DEBUG_INSN): Describe inline entry markers. --- gcc/cfgexpand.c | 9 +++ gcc/doc/gimple.texi | 18 +++++ gcc/doc/rtl.texi | 24 ++++-- gcc/dwarf2out.c | 199 +++++++++++++++++++++++++++++++++++++++++++++- gcc/final.c | 26 ++++++ gcc/gimple-pretty-print.c | 13 +++ gcc/gimple.c | 21 +++++ gcc/gimple.h | 18 ++++- gcc/insn-notes.def | 4 + gcc/print-rtl.c | 5 ++ gcc/rtl.h | 7 +- gcc/tree-inline.c | 7 ++ gcc/tree-ssa-live.c | 27 +++++-- gcc/var-tracking.c | 1 + include/dwarf2.def | 1 + 15 files changed, 364 insertions(+), 16 deletions(-) diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 3f17e90d50b3..a9531e86a662 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -5715,6 +5715,15 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls) goto delink_debug_stmt; else if (gimple_debug_begin_stmt_p (stmt)) val = GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT (); + else if (gimple_debug_inline_entry_p (stmt)) + { + tree block = gimple_block (stmt); + + if (block) + val = GEN_RTX_DEBUG_MARKER_INLINE_ENTRY_PAT (); + else + goto delink_debug_stmt; + } else gcc_unreachable (); diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi index 492678705c6f..3825378080fa 100644 --- a/gcc/doc/gimple.texi +++ b/gcc/doc/gimple.texi @@ -836,6 +836,11 @@ Return true if g is a @code{GIMPLE_DEBUG} that marks the beginning of a source statement. @end deftypefn +@deftypefn {GIMPLE function} gimple_debug_inline_entry_p (gimple g) +Return true if g is a @code{GIMPLE_DEBUG} that marks the entry +point of an inlined function. +@end deftypefn + @deftypefn {GIMPLE function} gimple_debug_nonbind_marker_p (gimple g) Return true if g is a @code{GIMPLE_DEBUG} that marks a program location, without any variable binding. @@ -1541,6 +1546,7 @@ Set the conditional @code{COND_STMT} to be of the form 'if (1 == 1)'. @cindex @code{GIMPLE_DEBUG} @cindex @code{GIMPLE_DEBUG_BIND} @cindex @code{GIMPLE_DEBUG_BEGIN_STMT} +@cindex @code{GIMPLE_DEBUG_INLINE_ENTRY} @deftypefn {GIMPLE function} gdebug *gimple_build_debug_bind (tree var, @ tree value, gimple stmt) @@ -1626,6 +1632,18 @@ observable, and that none of the side effects of subsequent user statements are. @end deftypefn +@deftypefn {GIMPLE function} gimple gimple_build_debug_inline_entry (tree block, location_t location) +Build a @code{GIMPLE_DEBUG} statement with +@code{GIMPLE_DEBUG_INLINE_ENTRY} @code{subcode}. The effect of this +statement is to tell debug information generation machinery that a +function call at @code{location} underwent inline substitution, that +@code{block} is the enclosing lexical block created for the +substitution, and that at the point of the program in which the stmt is +inserted, all parameters for the inlined function are bound to the +respective arguments, and none of the side effects of its stmts are +observable. +@end deftypefn + @node @code{GIMPLE_EH_FILTER} @subsection @code{GIMPLE_EH_FILTER} @cindex @code{GIMPLE_EH_FILTER} diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi index 898574a01ad0..8d7d32177c16 100644 --- a/gcc/doc/rtl.texi +++ b/gcc/doc/rtl.texi @@ -3453,7 +3453,10 @@ Refers to a parameter that was completely optimized out. @item (debug_marker:@var{mode}) Marks a program location. With @code{VOIDmode}, it stands for the beginning of a statement, a recommended inspection point logically after -all prior side effects, and before any subsequent side effects. +all prior side effects, and before any subsequent side effects. With +@code{BLKmode}, it indicates an inline entry point: the lexical block +encoded in the @code{INSN_LOCATION} is the enclosing block that encloses +the inlined function. @end table @@ -3737,6 +3740,13 @@ This note is used to generate @code{is_stmt} markers in line number debuggign information. It indicates the beginning of a user statement. +@findex NOTE_INSN_INLINE_ENTRY +@item NOTE_INSN_INLINE_ENTRY +This note is used to generate @code{entry_pc} for inlined subroutines in +debugging information. It indicates an inspection point at which all +arguments for the inlined function have been bound, and before its first +statement. + @end table These codes are printed symbolically when they appear in debugging dumps. @@ -3754,8 +3764,12 @@ binds a user variable tree to an RTL representation of the it stands for the value bound to the corresponding @code{DEBUG_EXPR_DECL}. -@code{GIMPLE_DEBUG_BEGIN_STMT} is expanded to RTL as a @code{DEBUG_INSN} -with a @code{VOIDmode} @code{DEBUG_MARKER} @code{PATTERN}. These +@code{GIMPLE_DEBUG_BEGIN_STMT} and @code{GIMPLE_DEBUG_INLINE_ENTRY} are +expanded to RTL as a @code{DEBUG_INSN} with a @code{DEBUG_MARKER} +@code{PATTERN}; the difference is the RTL mode: the former's +@code{DEBUG_MARKER} is @code{VOIDmode}, whereas the latter is +@code{BLKmode}; information about the inlined function can be taken from +the lexical block encoded in the @code{INSN_LOCATION}. These @code{DEBUG_INSN}s, that do not carry @code{VAR_LOCATION} information, just @code{DEBUG_MARKER}s, can be detected by testing @code{DEBUG_MARKER_INSN_P}, whereas those that do can be recognized as @@ -3766,8 +3780,8 @@ with respect to each other, particularly during scheduling. Binding information is kept in pseudo-instruction form, so that, unlike notes, it gets the same treatment and adjustments that regular instructions would. It is the variable tracking pass that turns these -pseudo-instructions into @code{NOTE_INSN_VAR_LOCATION} and -@code{NOTE_INSN_BEGIN_STMT} notes, +pseudo-instructions into @code{NOTE_INSN_VAR_LOCATION}, +@code{NOTE_INSN_BEGIN_STMT} and @code{NOTE_INSN_INLINE_ENTRY} notes, analyzing control flow, value equivalences and changes to registers and memory referenced in value expressions, propagating the values of debug temporaries and determining expressions that can be used to compute the diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 5fdac8269654..9e2f73525b6a 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -2720,6 +2720,7 @@ static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree, dw_die_ref); static void dwarf2out_abstract_function (tree); static void dwarf2out_var_location (rtx_insn *); +static void dwarf2out_inline_entry (tree); static void dwarf2out_size_function (tree); static void dwarf2out_begin_function (tree); static void dwarf2out_end_function (unsigned int); @@ -2773,7 +2774,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = debug_nothing_rtx_code_label, /* label */ debug_nothing_int, /* handle_pch */ dwarf2out_var_location, - debug_nothing_tree, /* inline_entry */ + dwarf2out_inline_entry, /* inline_entry */ dwarf2out_size_function, /* size_function */ dwarf2out_switch_text_section, dwarf2out_set_name, @@ -4011,6 +4012,9 @@ static char ranges_base_label[2 * MAX_ARTIFICIAL_LABEL_BYTES]; #ifndef BLOCK_BEGIN_LABEL #define BLOCK_BEGIN_LABEL "LBB" #endif +#ifndef BLOCK_INLINE_ENTRY_LABEL +#define BLOCK_INLINE_ENTRY_LABEL "LBI" +#endif #ifndef BLOCK_END_LABEL #define BLOCK_END_LABEL "LBE" #endif @@ -23046,6 +23050,48 @@ block_die_hasher::equal (die_struct *x, die_struct *y) return x->decl_id == y->decl_id && x->die_parent == y->die_parent; } +/* Hold information about markers for inlined entry points. */ +struct GTY ((for_user)) inline_entry_data +{ + /* The block that's the inlined_function_outer_scope for an inlined + function. */ + tree block; + + /* The label at the inlined entry point. */ + const char *label_pfx; + unsigned int label_num; + + /* The view number to be used as the inlined entry point. */ + var_loc_view view; +}; + +struct inline_entry_data_hasher : ggc_ptr_hash +{ + typedef tree compare_type; + static inline hashval_t hash (const inline_entry_data *); + static inline bool equal (const inline_entry_data *, const_tree); +}; + +/* Hash table routines for inline_entry_data. */ + +inline hashval_t +inline_entry_data_hasher::hash (const inline_entry_data *data) +{ + return htab_hash_pointer (data->block); +} + +inline bool +inline_entry_data_hasher::equal (const inline_entry_data *data, + const_tree block) +{ + return data->block == block; +} + +/* Inlined entry points pending DIE creation in this compilation unit. */ + +static GTY(()) hash_table *inline_entry_data_table; + + /* 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 @@ -23500,6 +23546,42 @@ add_high_low_attributes (tree stmt, dw_die_ref die) { char label[MAX_ARTIFICIAL_LABEL_BYTES]; + if (inline_entry_data **iedp + = !inline_entry_data_table ? NULL + : inline_entry_data_table->find_slot_with_hash (stmt, + htab_hash_pointer (stmt), + NO_INSERT)) + { + inline_entry_data *ied = *iedp; + gcc_assert (MAY_HAVE_DEBUG_MARKER_INSNS); + gcc_assert (inlined_function_outer_scope_p (stmt)); + ASM_GENERATE_INTERNAL_LABEL (label, ied->label_pfx, ied->label_num); + add_AT_lbl_id (die, DW_AT_entry_pc, label); + + if (debug_variable_location_views && !ZERO_VIEW_P (ied->view)) + { + if (!output_asm_line_debug_info ()) + add_AT_unsigned (die, DW_AT_GNU_entry_view, ied->view); + else + { + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", ied->view); + /* FIXME: this will resolve to a small number. Could we + possibly emit smaller data? Ideally we'd emit a + uleb128, but that would make the size of DIEs + impossible for the compiler to compute, since it's + the assembler that computes the value of the view + label in this case. Ideally, we'd have a single form + encompassing both the address and the view, and + indirecting them through a table might make things + easier, but even that would be more wasteful, + space-wise, than what we have now. */ + add_AT_lbl_id (die, DW_AT_GNU_entry_view, label); + } + } + + inline_entry_data_table->clear_slot (iedp); + } + if (BLOCK_FRAGMENT_CHAIN (stmt) && (dwarf_version >= 3 || !dwarf_strict)) { @@ -23507,7 +23589,7 @@ add_high_low_attributes (tree stmt, dw_die_ref die) dw_die_ref pdie; dw_attr_node *attr = NULL; - if (inlined_function_outer_scope_p (stmt)) + if (!MAY_HAVE_DEBUG_MARKER_INSNS && inlined_function_outer_scope_p (stmt)) { ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL, BLOCK_NUMBER (stmt)); @@ -23672,7 +23754,7 @@ gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die) dw_die_ref subr_die = new_die (DW_TAG_inlined_subroutine, context_die, stmt); - if (call_arg_locations) + if (call_arg_locations || MAY_HAVE_DEBUG_MARKER_INSNS) BLOCK_DIE (stmt) = subr_die; add_abstract_origin_attribute (subr_die, decl); if (TREE_ASM_WRITTEN (stmt)) @@ -26701,6 +26783,7 @@ dwarf2out_var_location (rtx_insn *loc_note) || ! NOTE_P (next_note) || (NOTE_KIND (next_note) != NOTE_INSN_VAR_LOCATION && NOTE_KIND (next_note) != NOTE_INSN_BEGIN_STMT + && NOTE_KIND (next_note) != NOTE_INSN_INLINE_ENTRY && NOTE_KIND (next_note) != NOTE_INSN_CALL_ARG_LOCATION)) next_note = NULL; @@ -26889,6 +26972,113 @@ create_label: last_in_cold_section_p = in_cold_section_p; } +/* Check whether BLOCK, a lexical block, is nested within OUTER, or is + OUTER itself. If BOTHWAYS, check not only that BLOCK can reach + OUTER through BLOCK_SUPERCONTEXT links, but also that there is a + path from OUTER to BLOCK through BLOCK_SUBBLOCKs and + BLOCK_FRAGMENT_ORIGIN links. */ +static bool +block_within_block_p (tree block, tree outer, bool bothways) +{ + if (block == outer) + return true; + + /* Quickly check that OUTER is up BLOCK's supercontext chain. */ + for (tree context = BLOCK_SUPERCONTEXT (block); + context != outer; + context = BLOCK_SUPERCONTEXT (context)) + if (!context || TREE_CODE (context) != BLOCK) + return false; + + if (!bothways) + return true; + + /* Now check that each block is actually referenced by its + parent. */ + for (tree context = BLOCK_SUPERCONTEXT (block); ; + context = BLOCK_SUPERCONTEXT (context)) + { + if (BLOCK_FRAGMENT_ORIGIN (context)) + { + gcc_assert (!BLOCK_SUBBLOCKS (context)); + context = BLOCK_FRAGMENT_ORIGIN (context); + } + for (tree sub = BLOCK_SUBBLOCKS (context); + sub != block; + sub = BLOCK_CHAIN (sub)) + if (!sub) + return false; + if (context == outer) + return true; + else + block = context; + } +} + +/* Called during final while assembling the marker of the entry point + for an inlined function. */ + +static void +dwarf2out_inline_entry (tree block) +{ + gcc_assert (DECL_P (block_ultimate_origin (block))); + + /* Sanity check the block tree. This would catch a case in which + BLOCK got removed from the tree reachable from the outermost + lexical block, but got retained in markers. It would still link + back to its parents, but some ancestor would be missing a link + down the path to the sub BLOCK. If the block got removed, its + BLOCK_NUMBER will not be a usable value. */ + gcc_checking_assert (block_within_block_p (block, + DECL_INITIAL + (current_function_decl), + true)); + + gcc_assert (inlined_function_outer_scope_p (block)); + gcc_assert (!BLOCK_DIE (block)); + + /* If we can't represent it, don't bother. */ + if (!(dwarf_version >= 3 || !dwarf_strict)) + return; + + if (BLOCK_FRAGMENT_ORIGIN (block)) + block = BLOCK_FRAGMENT_ORIGIN (block); + /* Can the entry point ever not be at the beginning of an + unfragmented lexical block? */ + else if (!(BLOCK_FRAGMENT_CHAIN (block) + || (cur_line_info_table + && !ZERO_VIEW_P (cur_line_info_table->view)))) + return; + + if (!inline_entry_data_table) + inline_entry_data_table + = hash_table::create_ggc (10); + + + inline_entry_data **iedp + = inline_entry_data_table->find_slot_with_hash (block, + htab_hash_pointer (block), + INSERT); + if (*iedp) + /* ??? Ideally, we'd record all entry points for the same inlined + function (some may have been duplicated by e.g. unrolling), but + we have no way to represent that ATM. */ + return; + + inline_entry_data *ied = *iedp = ggc_cleared_alloc (); + ied->block = block; + ied->label_pfx = BLOCK_INLINE_ENTRY_LABEL; + ied->label_num = BLOCK_NUMBER (block); + if (cur_line_info_table) + ied->view = cur_line_info_table->view; + + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_INLINE_ENTRY_LABEL, + BLOCK_NUMBER (block)); + ASM_OUTPUT_LABEL (asm_out_file, label); +} + /* Called from finalize_size_functions for size functions so that their body can be encoded in the debug info to describe the layout of variable-length structures. */ @@ -30360,6 +30550,9 @@ dwarf2out_finish (const char *) /* Flush out any latecomers to the limbo party. */ flush_limbo_die_list (); + if (inline_entry_data_table) + gcc_assert (inline_entry_data_table->elements () == 0); + if (flag_checking) { verify_die (comp_unit_die ()); diff --git a/gcc/final.c b/gcc/final.c index c6a1d5b7e05a..afb2988f8207 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -1672,6 +1672,7 @@ reemit_insn_block_notes (void) break; case NOTE_INSN_BEGIN_STMT: + case NOTE_INSN_INLINE_ENTRY: this_block = LOCATION_BLOCK (NOTE_MARKER_LOCATION (insn)); goto set_cur_block_to_this_block; @@ -2531,6 +2532,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, if (!DECL_IGNORED_P (current_function_decl) && notice_source_line (insn, NULL)) { + output_source_line: (*debug_hooks->source_line) (last_linenum, last_columnnum, last_filename, last_discriminator, true); @@ -2538,6 +2540,18 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, } break; + case NOTE_INSN_INLINE_ENTRY: + gcc_checking_assert (cfun->debug_nonbind_markers); + if (!DECL_IGNORED_P (current_function_decl)) + { + if (!notice_source_line (insn, NULL)) + break; + (*debug_hooks->inline_entry) (LOCATION_BLOCK + (NOTE_MARKER_LOCATION (insn))); + goto output_source_line; + } + break; + default: gcc_unreachable (); break; @@ -3241,6 +3255,17 @@ notice_source_line (rtx_insn *insn, bool *is_stmt) if (NOTE_MARKER_P (insn)) { location_t loc = NOTE_MARKER_LOCATION (insn); + /* The inline entry markers (gimple, insn, note) carry the + location of the call, because that's what we want to carry + during compilation, but the location we want to output in + debug information for the inline entry point is the location + of the function itself. */ + if (NOTE_KIND (insn) == NOTE_INSN_INLINE_ENTRY) + { + tree block = LOCATION_BLOCK (loc); + tree fn = block_ultimate_origin (block); + loc = DECL_SOURCE_LOCATION (fn); + } expanded_location xloc = expand_location (loc); if (xloc.line == 0) { @@ -4839,6 +4864,7 @@ rest_of_clean_state (void) && (!NOTE_P (insn) || (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION && NOTE_KIND (insn) != NOTE_INSN_BEGIN_STMT + && NOTE_KIND (insn) != NOTE_INSN_INLINE_ENTRY && NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 61b1f2c89cbb..5e832a78475d 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1370,6 +1370,19 @@ dump_gimple_debug (pretty_printer *buffer, gdebug *gs, int spc, dump_gimple_fmt (buffer, spc, flags, "# DEBUG BEGIN_STMT"); break; + case GIMPLE_DEBUG_INLINE_ENTRY: + if (flags & TDF_RAW) + dump_gimple_fmt (buffer, spc, flags, "%G INLINE_ENTRY %T", gs, + gimple_block (gs) + ? block_ultimate_origin (gimple_block (gs)) + : NULL_TREE); + else + dump_gimple_fmt (buffer, spc, flags, "# DEBUG INLINE_ENTRY %T", + gimple_block (gs) + ? block_ultimate_origin (gimple_block (gs)) + : NULL_TREE); + break; + default: gcc_unreachable (); } diff --git a/gcc/gimple.c b/gcc/gimple.c index 66496d002a8d..da6df9898512 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -873,6 +873,27 @@ gimple_build_debug_begin_stmt (tree block, location_t location } +/* Build a new GIMPLE_DEBUG_INLINE_ENTRY statement in BLOCK at + LOCATION. The BLOCK links to the inlined function. */ + +gdebug * +gimple_build_debug_inline_entry (tree block, location_t location + MEM_STAT_DECL) +{ + gdebug *p + = as_a ( + gimple_build_with_ops_stat (GIMPLE_DEBUG, + (unsigned)GIMPLE_DEBUG_INLINE_ENTRY, 0 + PASS_MEM_STAT)); + + gimple_set_location (p, location); + gimple_set_block (p, block); + cfun->debug_marker_count++; + + return p; +} + + /* Build a GIMPLE_OMP_CRITICAL statement. BODY is the sequence of statements for which only one thread can execute. diff --git a/gcc/gimple.h b/gcc/gimple.h index f44887ad7a9b..e925c329a347 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -204,7 +204,8 @@ enum gf_mask { enum gimple_debug_subcode { GIMPLE_DEBUG_BIND = 0, GIMPLE_DEBUG_SOURCE_BIND = 1, - GIMPLE_DEBUG_BEGIN_STMT = 2 + GIMPLE_DEBUG_BEGIN_STMT = 2, + GIMPLE_DEBUG_INLINE_ENTRY = 3 }; /* Masks for selecting a pass local flag (PLF) to work on. These @@ -1456,6 +1457,7 @@ geh_dispatch *gimple_build_eh_dispatch (int); gdebug *gimple_build_debug_bind (tree, tree, gimple * CXX_MEM_STAT_INFO); gdebug *gimple_build_debug_source_bind (tree, tree, gimple * CXX_MEM_STAT_INFO); gdebug *gimple_build_debug_begin_stmt (tree, location_t CXX_MEM_STAT_INFO); +gdebug *gimple_build_debug_inline_entry (tree, location_t CXX_MEM_STAT_INFO); gomp_critical *gimple_build_omp_critical (gimple_seq, tree, tree); gomp_for *gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq); gomp_parallel *gimple_build_omp_parallel (gimple_seq, tree, tree, tree); @@ -4786,13 +4788,25 @@ gimple_debug_begin_stmt_p (const gimple *s) return false; } +/* Return true if S is a GIMPLE_DEBUG INLINE_ENTRY statement. */ + +static inline bool +gimple_debug_inline_entry_p (const gimple *s) +{ + if (is_gimple_debug (s)) + return s->subcode == GIMPLE_DEBUG_INLINE_ENTRY; + + return false; +} + /* Return true if S is a GIMPLE_DEBUG non-binding marker statement. */ static inline bool gimple_debug_nonbind_marker_p (const gimple *s) { if (is_gimple_debug (s)) - return s->subcode == GIMPLE_DEBUG_BEGIN_STMT; + return s->subcode == GIMPLE_DEBUG_BEGIN_STMT + || s->subcode == GIMPLE_DEBUG_INLINE_ENTRY; return false; } diff --git a/gcc/insn-notes.def b/gcc/insn-notes.def index 960487b31db1..252e95722447 100644 --- a/gcc/insn-notes.def +++ b/gcc/insn-notes.def @@ -71,6 +71,10 @@ INSN_NOTE (CALL_ARG_LOCATION) /* The beginning of a statement. */ INSN_NOTE (BEGIN_STMT) +/* The entry point for an inlined function. Its NOTE_BLOCK references + the lexical block whose abstract origin is the inlined function. */ +INSN_NOTE (INLINE_ENTRY) + /* Record the struct for the following basic block. Uses NOTE_BASIC_BLOCK. FIXME: Redundant with the basic block pointer now included in every insn. NOTE: If there's no CFG anymore, in other words, diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c index acbe2f37748a..277ef16c8499 100644 --- a/gcc/print-rtl.c +++ b/gcc/print-rtl.c @@ -259,6 +259,7 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED, break; case NOTE_INSN_BEGIN_STMT: + case NOTE_INSN_INLINE_ENTRY: #ifndef GENERATOR_FILE { expanded_location xloc @@ -1809,6 +1810,10 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose) pp_string (pp, "debug begin stmt marker"); break; + case NOTE_INSN_INLINE_ENTRY: + pp_string (pp, "debug inline entry marker"); + break; + default: gcc_unreachable (); } diff --git a/gcc/rtl.h b/gcc/rtl.h index 3ef687e5a371..63df02e0376a 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1625,7 +1625,8 @@ extern const char * const reg_note_name[]; for which NOTE_MARKER_LOCATION can be used. */ #define NOTE_MARKER_P(INSN) \ (NOTE_P (INSN) && \ - (NOTE_KIND (INSN) == NOTE_INSN_BEGIN_STMT)) + (NOTE_KIND (INSN) == NOTE_INSN_BEGIN_STMT \ + || NOTE_KIND (INSN) == NOTE_INSN_INLINE_ENTRY)) /* Variable declaration and the location of a variable. */ #define PAT_VAR_LOCATION_DECL(PAT) (XCTREE ((PAT), 0, VAR_LOCATION)) @@ -1663,6 +1664,8 @@ extern const char * const reg_note_name[]; (GET_CODE (PATTERN (INSN)) == DEBUG_MARKER \ ? (GET_MODE (PATTERN (INSN)) == VOIDmode \ ? NOTE_INSN_BEGIN_STMT \ + : GET_MODE (PATTERN (INSN)) == BLKmode \ + ? NOTE_INSN_INLINE_ENTRY \ : (enum insn_note)-1) \ : (enum insn_note)-1) /* Create patterns for debug markers. These and the above abstract @@ -1672,6 +1675,8 @@ extern const char * const reg_note_name[]; wouldn't be a problem. */ #define GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT() \ gen_rtx_DEBUG_MARKER (VOIDmode) +#define GEN_RTX_DEBUG_MARKER_INLINE_ENTRY_PAT() \ + gen_rtx_DEBUG_MARKER (BLKmode) /* The VAR_LOCATION rtx in a DEBUG_INSN. */ #define INSN_VAR_LOCATION(INSN) \ diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index f858d426a500..8fd757fd40e6 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -4631,6 +4631,13 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id) GSI_NEW_STMT); } initialize_inlined_parameters (id, stmt, fn, bb); + if (debug_nonbind_markers_p && id->block + && inlined_function_outer_scope_p (id->block)) + { + gimple_stmt_iterator si = gsi_last_bb (bb); + gsi_insert_after (&si, gimple_build_debug_inline_entry + (id->block, input_location), GSI_NEW_STMT); + } if (DECL_INITIAL (fn)) { diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c index 8738fe21a6e1..734d15df2c51 100644 --- a/gcc/tree-ssa-live.c +++ b/gcc/tree-ssa-live.c @@ -520,6 +520,11 @@ remove_unused_scope_block_p (tree scope, bool in_ctor_dtor_block) else if (!BLOCK_SUPERCONTEXT (scope) || TREE_CODE (BLOCK_SUPERCONTEXT (scope)) == FUNCTION_DECL) unused = false; + /* Preserve the block, it is referenced by at least the inline + entry point marker. */ + else if (debug_nonbind_markers_p + && inlined_function_outer_scope_p (scope)) + unused = false; /* Innermost blocks with no live variables nor statements can be always eliminated. */ else if (!nsubblocks) @@ -548,11 +553,13 @@ remove_unused_scope_block_p (tree scope, bool in_ctor_dtor_block) } else if (BLOCK_VARS (scope) || BLOCK_NUM_NONLOCALIZED_VARS (scope)) unused = false; - /* See if this block is important for representation of inlined function. - Inlined functions are always represented by block with - block_ultimate_origin being set to FUNCTION_DECL and DECL_SOURCE_LOCATION - set... */ - else if (inlined_function_outer_scope_p (scope)) + /* See if this block is important for representation of inlined + function. Inlined functions are always represented by block + with block_ultimate_origin being set to FUNCTION_DECL and + DECL_SOURCE_LOCATION set, unless they expand to nothing... But + see above for the case of statement frontiers. */ + else if (!debug_nonbind_markers_p + && inlined_function_outer_scope_p (scope)) unused = false; else /* Verfify that only blocks with source location set @@ -640,6 +647,16 @@ dump_scope_block (FILE *file, int indent, tree scope, dump_flags_t flags) fprintf (file, "#%i", BLOCK_NUMBER (origin)); } } + if (BLOCK_FRAGMENT_ORIGIN (scope)) + fprintf (file, " Fragment of : #%i", + BLOCK_NUMBER (BLOCK_FRAGMENT_ORIGIN (scope))); + else if (BLOCK_FRAGMENT_CHAIN (scope)) + { + fprintf (file, " Fragment chain :"); + for (t = BLOCK_FRAGMENT_CHAIN (scope); t ; + t = BLOCK_FRAGMENT_CHAIN (t)) + fprintf (file, " #%i", BLOCK_NUMBER (t)); + } fprintf (file, " \n"); for (var = BLOCK_VARS (scope); var; var = DECL_CHAIN (var)) { diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index 8e500b144712..4f8f9f182203 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -9938,6 +9938,7 @@ reemit_marker_as_note (rtx_insn *insn, basic_block *bb) switch (kind) { case NOTE_INSN_BEGIN_STMT: + case NOTE_INSN_INLINE_ENTRY: { rtx_insn *note = NULL; if (cfun->debug_nonbind_markers) diff --git a/include/dwarf2.def b/include/dwarf2.def index f3fa4009207b..8e731a3b87a6 100644 --- a/include/dwarf2.def +++ b/include/dwarf2.def @@ -444,6 +444,7 @@ DW_AT (DW_AT_GNU_pubtypes, 0x2135) See http://gcc.gnu.org/wiki/Discriminator */ DW_AT (DW_AT_GNU_discriminator, 0x2136) DW_AT (DW_AT_GNU_locviews, 0x2137) +DW_AT (DW_AT_GNU_entry_view, 0x2138) /* VMS extensions. */ DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201) /* GNAT extensions. */