From patchwork Thu Apr 28 16:30:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aldy Hernandez X-Patchwork-Id: 53322 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B2C0F3856DCA for ; Thu, 28 Apr 2022 16:32:01 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B2C0F3856DCA DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1651163521; bh=IoJezZw8MepuT4VesUnQpQE9cy9btJJJkX7Oxr/jMtA=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=VAu8gCagCBvLzE2FOz9Tza+/ubOrTf8MswJO9qKSgrIiyXiS26V9ZHx31IcxT8gKr +ZoKPFe9sjJx27/UX+zn7OT2fnhJkSkNf1YpPunZo0fsENOroYSHvyK1L92TgPmsg7 ksTAC6BAd2oaCPiw2B3Qo8Ap70sfAq8qY0jaLccs= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 7DA57385781D for ; Thu, 28 Apr 2022 16:31:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 7DA57385781D Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-460-ekDwil37PdOlz8OijQ5Ckw-1; Thu, 28 Apr 2022 12:31:25 -0400 X-MC-Unique: ekDwil37PdOlz8OijQ5Ckw-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 75DA386B8A0; Thu, 28 Apr 2022 16:31:25 +0000 (UTC) Received: from abulafia (unknown [10.39.195.120]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E8A7540D2971; Thu, 28 Apr 2022 16:31:24 +0000 (UTC) Received: from abulafia (localhost [127.0.0.1]) by abulafia (8.17.1/8.17.1) with ESMTPS id 23SGVMjW595336 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Thu, 28 Apr 2022 18:31:22 +0200 Received: (from aldyh@localhost) by abulafia (8.17.1/8.17.1/Submit) id 23SGVMj9595276; Thu, 28 Apr 2022 18:31:22 +0200 To: Jeff Law Subject: [PATCH] Replace EVRP in DOM with ranger. Date: Thu, 28 Apr 2022 18:30:15 +0200 Message-Id: <20220428163015.595263-1-aldyh@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.11.54.2 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Aldy Hernandez via Gcc-patches From: Aldy Hernandez Reply-To: Aldy Hernandez Cc: GCC patches Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" [Jeff, this is the same patch I sent you last week with minor tweaks to the commit message.] [Despite the verbosity of the message, this is actually a pretty straightforward patch. It should've gone in last cycle, but there was a nagging regression I couldn't get to until after stage1 had closed.] There are 3 uses of EVRP in DOM that must be converted. Unfortunately, they need to be converted in one go, so further splitting of this patch would be problematic. There's nothing here earth shattering. It's all pretty obvious in retrospect, but I've added a short description of each use to aid in reviewing: * Convert evrp use in cprop to ranger. This is easy, as cprop in DOM was converted to the ranger API last cycle, so this is just a matter of using a ranger instead of an evrp_range_analyzer. * Convert evrp use in threader to ranger. The idea here is to use the hybrid approach we used for the initial VRP threader conversion last cycle. The DOM threader will continue using the forward threader infrastructure while continuing to query DOM data structures, and only if the conditional does not relsolve, using the ranger. This gives us the best of both worlds, and is a proven approach. Furthermore, as frange and prange come live in the next cycle, we can move away from the forward threader altogether, and just add another backward threader. This will not only remove the last use of the forward threader, but will allow us to remove at least 1 or 2 threader instances. * Convert conditional folding to use the method used by the ranger and evrp. Previously DOM was calling into the guts of simplify_using_ranges::vrp_visit_cond_stmt. The blessed way now is using fold_cond() which rewrites the conditional and edges automatically. When legacy is removed, simplify_using_ranges will be further cleaned up, and there will only be one entry point into simplifying a statement. * DOM was setting global ranges determined from unreachable edges as a side-effect of using the evrp engine. We must handle these cases before nuking evrp, and DOM seems like a good fit. I've just moved the snippet to DOM, but it could live anywhere else we do a DOM walk. For the record, this is the case *vrp handled: : ... if (c_5(D) != 5) goto ; else goto ; : __builtin_unreachable (); : If M dominates all uses of c_5, we can set the global range of c_5 to [5,5]. I have tested on x86-64, pcc64le, and aarch64 Linux. I also ran threading benchmarks as well as performance benchmarks. DOM threads 1.56% more paths which ultimately yields a miniscule total increase of 0.03%. The conversion to ranger brings a 7.87% performance drop in DOM, which is a wash in overall compilation. This is in line with other replacements of legacy evrp with ranger. We handle a lot more cases. It's not free :). There is a a regression on Wstringop-overflow-4.C which I'm planning on XFAILing. It's another variant of the usual middle-end false positives: having no ranges produces no warnings, but slightly refined ranges, or worse-- isolating specific problematic cases in the threader causes flare-ups. As an aside, as Richi has suggested, I think we should discuss restricting the threader's ability to thread highly unlikely paths. These cause no end of pain for middle-end warnings. However, I don't know if this would conflict with path isolation for things like null dereferencing. ISTR you were interested in this. BTW, I think the Wstringop-overflow-4.C test is problematic and I've attached my analysis. Basically the regression is caused by a bad interaction with the rounding/alignment that placement new has inlined into the IL. This happens for int16_r[] which the test is testing. Ranger can glean some range info, which causes DOM threading to isolate a path which causes a warning. OK for trunk? gcc/ChangeLog: * tree-ssa-dom.cc (dom_jt_state): Pass ranger to constructor instead of evrp. (dom_jt_state::push): Remove m_evrp. (dom_jt_state::pop): Same. (dom_jt_state::record_ranges_from_stmt): Remove. (dom_jt_state::register_equiv): Remove updating of evrp ranges. (class dom_jt_simplifier): Pass ranger to constructor. Inherit from hybrid_jt_simplifier. (dom_jt_simplifier::simplify): Convert to ranger. (pass_dominator::execute): Same. (all_uses_feed_or_dominated_by_stmt): New. (dom_opt_dom_walker::set_global_ranges_from_unreachable_edges): New. (dom_opt_dom_walker::before_dom_children): Call set_global_ranges_from_unreachable_edges. Do not call record_ranges_from_stmt. (dom_opt_dom_walker::after_dom_children): Remove evrp use. (cprop_operand): Use int_range<> instead of value_range. (dom_opt_dom_walker::fold_cond): New. (dom_opt_dom_walker::optimize_stmt): Pass ranger to cprop_into_stmt. Use fold_cond() instead of vrp_visit_cond_stmt(). * tree-ssa-threadedge.cc (jt_state::register_equivs_stmt): Do not pass state to simplifier. * vr-values.h (class vr_values): Make fold_cond public. gcc/testsuite/ChangeLog: * gcc.dg/sancov/cmp0.c: Adjust for conversion to ranger. * gcc.dg/tree-ssa/ssa-dom-branch-1.c: Same. * gcc.dg/tree-ssa/ssa-dom-thread-7.c: Same. * gcc.dg/vect/bb-slp-pr81635-2.c: Same. * gcc.dg/vect/bb-slp-pr81635-4.c: Same. --- .../g++.dg/warn/Wstringop-overflow-4.C | 34 +++ gcc/testsuite/gcc.dg/sancov/cmp0.c | 2 +- .../gcc.dg/tree-ssa/ssa-dom-branch-1.c | 5 +- .../gcc.dg/tree-ssa/ssa-dom-thread-7.c | 2 +- gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-2.c | 2 +- gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-4.c | 6 +- gcc/tree-ssa-dom.cc | 223 ++++++++++-------- gcc/tree-ssa-threadedge.cc | 4 +- gcc/vr-values.h | 2 +- 9 files changed, 168 insertions(+), 112 deletions(-) diff --git a/gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C b/gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C index c80977d3043..eb4801918fc 100644 --- a/gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C +++ b/gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C @@ -161,6 +161,40 @@ void test_strcpy_new_int16_t (size_t n, const size_t vals[]) ptrdiff_t r_dmin_dmax = SR (DIFF_MIN, DIFF_MAX); T (S (1), new int16_t[r_dmin_dmax]); + /* ?? The above SR(DIFF_MIN, DIFF_MAX) implies r_dmin_dmax can be + the entire domain, including negative numbers because ptrdiff_t + is a signed entity. + + This causes a warning in the following line after the + DOM/threader changes for C++98. + + [local count: 1073741824]: + _26 ={v} signed_value_source; ;; could be -1 + r_dmin_dmax.1_8 = (sizetype) _26; + if (r_dmin_dmax.1_8 <= 4611686018427387900) ;; placement new rounding + goto ; [50.00%] + else + goto ; [50.00%] + + ... + ... + + [local count: 536870912]: + # iftmp.0_39 = PHI <18446744073709551615(2)> + _41 = operator new [] (iftmp.0_39); + __builtin_memcpy (_41, "z", 2); + sink (_41); + _44 = _26 + 1; ;; _44 = 0 + _45 = (sizetype) _44; ;; _45 = 0 + if (_45 <= 4611686018427387900) + goto ; [0.00%] + else + goto ; [100.00%] + + [local count: 0]: + iftmp.2_33 = _45 * 2; ;; iftmp.2_33 = 0 + _34 = operator new [] (iftmp.2_33); ;; new [] (0) + */ T (S (2), new int16_t[r_dmin_dmax + 1]); T (S (9), new int16_t[r_dmin_dmax * 2 + 1]); } diff --git a/gcc/testsuite/gcc.dg/sancov/cmp0.c b/gcc/testsuite/gcc.dg/sancov/cmp0.c index 8bbf06e9466..9fd7f5cccc8 100644 --- a/gcc/testsuite/gcc.dg/sancov/cmp0.c +++ b/gcc/testsuite/gcc.dg/sancov/cmp0.c @@ -1,6 +1,6 @@ /* Basic test on number of inserted callbacks. */ /* { dg-do compile } */ -/* { dg-options "-fsanitize-coverage=trace-cmp -fdump-tree-optimized" } */ +/* { dg-options "-fsanitize-coverage=trace-cmp -fdump-tree-optimized -fno-thread-jumps" } */ /* { dg-skip-if "different type layout" { avr-*-* } } */ #if __SIZEOF_INT__ < 4 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-branch-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-branch-1.c index fae5bdef818..ede3274f59d 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-branch-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-branch-1.c @@ -19,10 +19,9 @@ try_combine (rtx i1, rtx newpat) else if (i1 && foo ()); } -/* There should be four tests against i1. One from the hash table - dumps, one from the EVRP analyzer one from EVRP evaluation and one +/* There should be 3 tests against i1. Two from DOM machinery and one in the code itself. */ -/* { dg-final { scan-tree-dump-times "if .i1_" 4 "dom2"} } */ +/* { dg-final { scan-tree-dump-times "if .i1_" 3 "dom2"} } */ /* There should be no actual jump threads realized by DOM. The legitimize jump threads are handled in VRP and those discovered diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c index b64e71dae22..aa06db5e223 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c @@ -11,7 +11,7 @@ to change decisions in switch expansion which in turn can expose new jump threading opportunities. Skip the later tests on aarch64. */ /* { dg-final { scan-tree-dump-not "Jumps threaded" "dom3" { target { ! aarch64*-*-* } } } } */ -/* { dg-final { scan-tree-dump "Jumps threaded: 7" "thread2" { target { ! aarch64*-*-* } } } } */ +/* { dg-final { scan-tree-dump "Jumps threaded: 8" "thread2" { target { ! aarch64*-*-* } } } } */ /* { dg-final { scan-tree-dump "Jumps threaded: 18" "thread2" { target { aarch64*-*-* } } } } */ enum STATE { diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-2.c b/gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-2.c index 6b213d4da28..56c4bbf86d8 100644 --- a/gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-2.c +++ b/gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-additional-options "-fno-tree-loop-vectorize" } */ +/* { dg-additional-options "-fno-tree-loop-vectorize -fno-tree-dominator-opts" } */ /* { dg-require-effective-target lp64 } */ double p[1000]; diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-4.c b/gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-4.c index 599f718ecdc..67ee809826c 100644 --- a/gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-4.c +++ b/gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-4.c @@ -1,7 +1,11 @@ /* { dg-do compile } */ -/* { dg-additional-options "-fno-tree-loop-vectorize" } */ +/* { dg-additional-options "-fno-tree-loop-vectorize -fno-tree-dominator-opts" } */ /* { dg-require-effective-target lp64 } */ +/* A ranger based DOM causes many more SSA names to be exported, which + causes slp1 to vectorize more things. Disabling DOM to avoid + disturbing this test. */ + void f1 (double *p, double *q, unsigned int n) { diff --git a/gcc/tree-ssa-dom.cc b/gcc/tree-ssa-dom.cc index 21745bf31d3..74f4eec91be 100644 --- a/gcc/tree-ssa-dom.cc +++ b/gcc/tree-ssa-dom.cc @@ -48,7 +48,8 @@ along with GCC; see the file COPYING3. If not see #include "alloc-pool.h" #include "tree-vrp.h" #include "vr-values.h" -#include "gimple-ssa-evrp-analyze.h" +#include "gimple-range.h" +#include "gimple-range-path.h" #include "alias.h" /* This file implements optimizations on the dominator tree. */ @@ -589,132 +590,64 @@ class dom_jt_state : public jt_state { public: dom_jt_state (const_and_copies *copies, avail_exprs_stack *avails, - evrp_range_analyzer *evrp) - : m_copies (copies), m_avails (avails), m_evrp (evrp) + gimple_ranger *ranger) + : m_copies (copies), m_avails (avails), m_ranger (ranger) { } void push (edge e) override { m_copies->push_marker (); m_avails->push_marker (); - m_evrp->push_marker (); jt_state::push (e); } void pop () override { m_copies->pop_to_marker (); m_avails->pop_to_marker (); - m_evrp->pop_to_marker (); jt_state::pop (); } void register_equivs_edge (edge e) override { record_temporary_equivalences (e, m_copies, m_avails); } - void record_ranges_from_stmt (gimple *stmt, bool temporary) override - { - m_evrp->record_ranges_from_stmt (stmt, temporary); - } void register_equiv (tree dest, tree src, bool update) override; private: const_and_copies *m_copies; avail_exprs_stack *m_avails; - evrp_range_analyzer *m_evrp; + gimple_ranger *m_ranger; }; void -dom_jt_state::register_equiv (tree dest, tree src, bool update) +dom_jt_state::register_equiv (tree dest, tree src, bool) { m_copies->record_const_or_copy (dest, src); - - /* If requested, update the value range associated with DST, using - the range from SRC. */ - if (update) - { - /* Get new VR we can pass to push_value_range. */ - value_range_equiv *new_vr = m_evrp->allocate_value_range_equiv (); - new (new_vr) value_range_equiv (); - - /* There are three cases to consider: - - First if SRC is an SSA_NAME, then we can copy the value range - from SRC into NEW_VR. - - Second if SRC is an INTEGER_CST, then we can just set NEW_VR - to a singleton range. Note that even if SRC is a constant we - need to set a suitable output range so that VR_UNDEFINED - ranges do not leak through. - - Otherwise set NEW_VR to varying. This may be overly - conservative. */ - if (TREE_CODE (src) == SSA_NAME) - new_vr->deep_copy (m_evrp->get_value_range (src)); - else if (TREE_CODE (src) == INTEGER_CST) - new_vr->set (src); - else - new_vr->set_varying (TREE_TYPE (src)); - - /* This is a temporary range for DST, so push it. */ - m_evrp->push_value_range (dest, new_vr); - } } -class dom_jt_simplifier : public jt_simplifier +class dom_jt_simplifier : public hybrid_jt_simplifier { public: - dom_jt_simplifier (vr_values *v, avail_exprs_stack *avails) - : m_vr_values (v), m_avails (avails) { } + dom_jt_simplifier (avail_exprs_stack *avails, gimple_ranger *ranger, + path_range_query *query) + : hybrid_jt_simplifier (ranger, query), m_avails (avails) { } private: tree simplify (gimple *, gimple *, basic_block, jt_state *) override; - vr_values *m_vr_values; avail_exprs_stack *m_avails; }; tree dom_jt_simplifier::simplify (gimple *stmt, gimple *within_stmt, - basic_block, jt_state *) + basic_block bb, jt_state *state) { /* First see if the conditional is in the hash table. */ tree cached_lhs = m_avails->lookup_avail_expr (stmt, false, true); if (cached_lhs) return cached_lhs; - if (gcond *cond_stmt = dyn_cast (stmt)) - { - simplify_using_ranges simplifier (m_vr_values); - return simplifier.vrp_evaluate_conditional (gimple_cond_code (cond_stmt), - gimple_cond_lhs (cond_stmt), - gimple_cond_rhs (cond_stmt), - within_stmt); - } - if (gswitch *switch_stmt = dyn_cast (stmt)) - { - tree op = gimple_switch_index (switch_stmt); - if (TREE_CODE (op) != SSA_NAME) - return NULL_TREE; + /* Otherwise call the ranger if possible. */ + if (state) + return hybrid_jt_simplifier::simplify (stmt, within_stmt, bb, state); - const value_range_equiv *vr = m_vr_values->get_value_range (op); - return find_case_label_range (switch_stmt, vr); - } - if (gassign *assign_stmt = dyn_cast (stmt)) - { - tree lhs = gimple_assign_lhs (assign_stmt); - if (TREE_CODE (lhs) == SSA_NAME - && (INTEGRAL_TYPE_P (TREE_TYPE (lhs)) - || POINTER_TYPE_P (TREE_TYPE (lhs))) - && stmt_interesting_for_vrp (stmt)) - { - edge dummy_e; - tree dummy_tree; - value_range_equiv new_vr; - m_vr_values->extract_range_from_stmt (stmt, &dummy_e, &dummy_tree, - &new_vr); - tree singleton; - if (new_vr.singleton_p (&singleton)) - return singleton; - } - } return NULL; } @@ -724,12 +657,12 @@ public: dom_opt_dom_walker (cdi_direction direction, jump_threader *threader, jt_state *state, - evrp_range_analyzer *analyzer, + gimple_ranger *ranger, const_and_copies *const_and_copies, avail_exprs_stack *avail_exprs_stack) : dom_walker (direction, REACHABLE_BLOCKS) { - m_evrp_range_analyzer = analyzer; + m_ranger = ranger; m_state = state; m_dummy_cond = gimple_build_cond (NE_EXPR, integer_zero_node, integer_zero_node, NULL, NULL); @@ -756,11 +689,13 @@ private: value. */ edge optimize_stmt (basic_block, gimple_stmt_iterator *, bool *); + void set_global_ranges_from_unreachable_edges (basic_block); void test_for_singularity (gimple *, avail_exprs_stack *); + edge fold_cond (gcond *cond); jump_threader *m_threader; - evrp_range_analyzer *m_evrp_range_analyzer; + gimple_ranger *m_ranger; jt_state *m_state; }; @@ -857,18 +792,22 @@ pass_dominator::execute (function *fun) record_edge_info (bb); /* Recursively walk the dominator tree optimizing statements. */ - evrp_range_analyzer analyzer (true); - dom_jt_simplifier simplifier (&analyzer, avail_exprs_stack); - dom_jt_state state (const_and_copies, avail_exprs_stack, &analyzer); + gimple_ranger *ranger = enable_ranger (fun); + path_range_query path_query (/*resolve=*/true, ranger); + dom_jt_simplifier simplifier (avail_exprs_stack, ranger, &path_query); + dom_jt_state state (const_and_copies, avail_exprs_stack, ranger); jump_threader threader (&simplifier, &state); dom_opt_dom_walker walker (CDI_DOMINATORS, &threader, &state, - &analyzer, + ranger, const_and_copies, avail_exprs_stack); walker.walk (fun->cfg->x_entry_block_ptr); + ranger->export_global_ranges (); + disable_ranger (fun); + /* Look for blocks where we cleared EDGE_EXECUTABLE on an outgoing edge. When found, remove jump threads which contain any outgoing edge from the affected block. */ @@ -1253,6 +1192,77 @@ record_equivalences_from_phis (basic_block bb) } } +/* Return true if all uses of NAME are dominated by STMT or feed STMT + via a chain of single immediate uses. */ + +static bool +all_uses_feed_or_dominated_by_stmt (tree name, gimple *stmt) +{ + use_operand_p use_p, use2_p; + imm_use_iterator iter; + basic_block stmt_bb = gimple_bb (stmt); + + FOR_EACH_IMM_USE_FAST (use_p, iter, name) + { + gimple *use_stmt = USE_STMT (use_p), *use_stmt2; + if (use_stmt == stmt + || is_gimple_debug (use_stmt) + || (gimple_bb (use_stmt) != stmt_bb + && dominated_by_p (CDI_DOMINATORS, + gimple_bb (use_stmt), stmt_bb))) + continue; + while (use_stmt != stmt + && is_gimple_assign (use_stmt) + && TREE_CODE (gimple_assign_lhs (use_stmt)) == SSA_NAME + && single_imm_use (gimple_assign_lhs (use_stmt), + &use2_p, &use_stmt2)) + use_stmt = use_stmt2; + if (use_stmt != stmt) + return false; + } + return true; +} + +/* Set global ranges that can be determined from the C->M edge: + + : + ... + if (something) + goto ; + else + goto ; + : + __builtin_unreachable (); + : +*/ + +void +dom_opt_dom_walker::set_global_ranges_from_unreachable_edges (basic_block bb) +{ + edge pred_e = single_pred_edge_ignoring_loop_edges (bb, false); + + if (!pred_e) + return; + + gimple *stmt = last_stmt (pred_e->src); + tree name; + int_range_max r; + if (stmt + && gimple_code (stmt) == GIMPLE_COND + && (name = gimple_cond_lhs (stmt)) + && TREE_CODE (name) == SSA_NAME + && irange::supports_type_p (TREE_TYPE (name)) + && assert_unreachable_fallthru_edge_p (pred_e) + && all_uses_feed_or_dominated_by_stmt (name, stmt) + && m_ranger->range_on_edge (r, pred_e, name) + && !r.varying_p () + && !r.undefined_p ()) + { + update_global_range (r, name); + maybe_set_nonzero_bits (pred_e, name); + } +} + /* Record any equivalences created by the incoming edge to BB into CONST_AND_COPIES and AVAIL_EXPRS_STACK. If BB has more than one incoming edge, then no equivalence is created. */ @@ -1506,8 +1516,6 @@ dom_opt_dom_walker::before_dom_children (basic_block bb) if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "\n\nOptimizing block #%d\n\n", bb->index); - m_evrp_range_analyzer->enter (bb); - /* Push a marker on the stacks of local information so that we know how far to unwind when we finalize this block. */ m_avail_exprs_stack->push_marker (); @@ -1515,6 +1523,7 @@ dom_opt_dom_walker::before_dom_children (basic_block bb) record_equivalences_from_incoming_edge (bb, m_const_and_copies, m_avail_exprs_stack); + set_global_ranges_from_unreachable_edges (bb); /* PHI nodes can create equivalences too. */ record_equivalences_from_phis (bb); @@ -1543,7 +1552,6 @@ dom_opt_dom_walker::before_dom_children (basic_block bb) continue; } - m_state->record_ranges_from_stmt (gsi_stmt (gsi), false); bool removed_p = false; taken_edge = this->optimize_stmt (bb, &gsi, &removed_p); if (!removed_p) @@ -1591,7 +1599,6 @@ dom_opt_dom_walker::after_dom_children (basic_block bb) m_threader->thread_outgoing_edges (bb); m_avail_exprs_stack->pop_to_marker (); m_const_and_copies->pop_to_marker (); - m_evrp_range_analyzer->leave (bb); } /* Search for redundant computations in STMT. If any are found, then @@ -1833,7 +1840,7 @@ cprop_operand (gimple *stmt, use_operand_p op_p, range_query *query) val = SSA_NAME_VALUE (op); if (!val) { - value_range r; + int_range<2> r; tree single; if (query->range_of_expr (r, op, stmt) && r.singleton_p (&single)) val = single; @@ -2074,6 +2081,24 @@ reduce_vector_comparison_to_scalar_comparison (gimple *stmt) } } +/* If possible, rewrite the conditional as TRUE or FALSE, and return + the taken edge. Otherwise, return NULL. */ + +edge +dom_opt_dom_walker::fold_cond (gcond *cond) +{ + simplify_using_ranges simplify (m_ranger); + if (simplify.fold_cond (cond)) + { + basic_block bb = gimple_bb (cond); + if (gimple_cond_true_p (cond)) + return find_taken_edge (bb, boolean_true_node); + if (gimple_cond_false_p (cond)) + return find_taken_edge (bb, boolean_false_node); + } + return NULL; +} + /* Optimize the statement in block BB pointed to by iterator SI. We try to perform some simplistic global redundancy elimination and @@ -2122,7 +2147,7 @@ dom_opt_dom_walker::optimize_stmt (basic_block bb, gimple_stmt_iterator *si, opt_stats.num_stmts++; /* Const/copy propagate into USES, VUSES and the RHS of VDEFs. */ - cprop_into_stmt (stmt, m_evrp_range_analyzer); + cprop_into_stmt (stmt, m_ranger); /* If the statement has been modified with constant replacements, fold its RHS before checking for redundant computations. */ @@ -2219,17 +2244,9 @@ dom_opt_dom_walker::optimize_stmt (basic_block bb, gimple_stmt_iterator *si, IL because we've attached range information to new SSA_NAMES. */ update_stmt_if_modified (stmt); - edge taken_edge = NULL; - simplify_using_ranges simpl (m_evrp_range_analyzer); - simpl.vrp_visit_cond_stmt (as_a (stmt), &taken_edge); + edge taken_edge = fold_cond (as_a (stmt)); if (taken_edge) { - if (taken_edge->flags & EDGE_TRUE_VALUE) - gimple_cond_make_true (as_a (stmt)); - else if (taken_edge->flags & EDGE_FALSE_VALUE) - gimple_cond_make_false (as_a (stmt)); - else - gcc_unreachable (); gimple_set_modified (stmt, true); update_stmt (stmt); cfg_altered = true; diff --git a/gcc/tree-ssa-threadedge.cc b/gcc/tree-ssa-threadedge.cc index 4eb65ca7cac..50251af8fc0 100644 --- a/gcc/tree-ssa-threadedge.cc +++ b/gcc/tree-ssa-threadedge.cc @@ -1377,7 +1377,9 @@ jt_state::register_equivs_stmt (gimple *stmt, basic_block bb, SET_USE (use_p, tmp); } - cached_lhs = simplifier->simplify (stmt, stmt, bb, this); + /* Do not pass state to avoid calling the ranger with the + temporarily altered IL. */ + cached_lhs = simplifier->simplify (stmt, stmt, bb, /*state=*/NULL); /* Restore the statement's original uses/defs. */ i = 0; diff --git a/gcc/vr-values.h b/gcc/vr-values.h index f29441747e2..db0aa838bfe 100644 --- a/gcc/vr-values.h +++ b/gcc/vr-values.h @@ -41,6 +41,7 @@ public: // ?? These should be cleaned, merged, and made private. tree vrp_evaluate_conditional (tree_code, tree, tree, gimple *); void vrp_visit_cond_stmt (gcond *, edge *); + bool fold_cond (gcond *); tree vrp_evaluate_conditional_warnv_with_ops (gimple *stmt, enum tree_code, tree, tree, bool, bool *, bool *); @@ -53,7 +54,6 @@ private: bool simplify_bit_ops_using_ranges (gimple_stmt_iterator *, gimple *); bool simplify_min_or_max_using_ranges (gimple_stmt_iterator *, gimple *); bool simplify_cond_using_ranges_1 (gcond *); - bool fold_cond (gcond *); bool simplify_switch_using_ranges (gswitch *); bool simplify_float_conversion_using_ranges (gimple_stmt_iterator *, gimple *);