diff options
author | Aldy Hernandez <aldyh@redhat.com> | 2022-06-25 18:58:02 -0400 |
---|---|---|
committer | Jeff Law <jeffreyalaw@gmail.com> | 2022-06-25 19:04:01 -0400 |
commit | 8c99e307b20c502e55c425897fb3884ba8f05882 (patch) | |
tree | 4a4b7b02f25107e40541b75c213c8808035fa4c2 | |
parent | fc259b522c0f8b7bbca8e7adcd3da63330094a34 (diff) | |
download | gcc-8c99e307b20c502e55c425897fb3884ba8f05882.zip gcc-8c99e307b20c502e55c425897fb3884ba8f05882.tar.gz gcc-8c99e307b20c502e55c425897fb3884ba8f05882.tar.bz2 |
Convert DOM to use Ranger rather than EVRP
[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:
<bb C>:
...
if (c_5(D) != 5)
goto <bb N>;
else
goto <bb M>;
<bb N>:
__builtin_unreachable ();
<bb M>:
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: Likewise.
* gcc.target/mips/data-sym-multi-pool.c: Likewise.
* gcc.target/mips/mips.exp: Likewise.
-rw-r--r-- | gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C | 34 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/sancov/cmp0.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-branch-1.c | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-2.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-4.c | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/mips/data-sym-multi-pool.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/mips/mips.exp | 1 | ||||
-rw-r--r-- | gcc/tree-ssa-dom.cc | 223 | ||||
-rw-r--r-- | gcc/tree-ssa-threadedge.cc | 4 | ||||
-rw-r--r-- | gcc/vr-values.h | 2 |
11 files changed, 170 insertions, 113 deletions
diff --git a/gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C b/gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C index c80977d..eb48019 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. + + <bb 2> [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 <bb 3>; [50.00%] + else + goto <bb 9>; [50.00%] + + ... + ... + + <bb 9> [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 <bb 8>; [0.00%] + else + goto <bb 7>; [100.00%] + + <bb 8> [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 8bbf06e..9fd7f5c 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 fae5bde..ede3274 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 b64e71d..aa06db5 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 6b213d4..56c4bbf 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 599f718..67ee809 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/testsuite/gcc.target/mips/data-sym-multi-pool.c b/gcc/testsuite/gcc.target/mips/data-sym-multi-pool.c index 26a622a..3cf2d4f 100644 --- a/gcc/testsuite/gcc.target/mips/data-sym-multi-pool.c +++ b/gcc/testsuite/gcc.target/mips/data-sym-multi-pool.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-mips16 -mcode-readable=yes -fno-tree-vrp" } */ +/* { dg-options "-mips16 -mcode-readable=yes -fno-tree-vrp -fno-tree-dominator-opts" } */ /* { dg-skip-if "per-function expected output" { *-*-* } { "-flto" } { "" } } */ /* This testcase generates multiple constant pools within a function body. */ diff --git a/gcc/testsuite/gcc.target/mips/mips.exp b/gcc/testsuite/gcc.target/mips/mips.exp index 8a62267..42a0dbb 100644 --- a/gcc/testsuite/gcc.target/mips/mips.exp +++ b/gcc/testsuite/gcc.target/mips/mips.exp @@ -335,6 +335,7 @@ foreach option { split-wide-types tree-vectorize tree-vrp + tree-dominator-opts unroll-all-loops unroll-loops ipa-ra diff --git a/gcc/tree-ssa-dom.cc b/gcc/tree-ssa-dom.cc index 9a84321..208b0a0 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. */ @@ -588,132 +589,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 <gcond *> (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 <gswitch *> (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 *vr = m_vr_values->get_value_range (op); - return find_case_label_range (switch_stmt, vr); - } - if (gassign *assign_stmt = dyn_cast <gassign *> (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; } @@ -723,12 +656,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); @@ -755,11 +688,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; }; @@ -856,18 +791,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. */ @@ -1252,6 +1191,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: + + <bb C>: + ... + if (something) + goto <bb N>; + else + goto <bb M>; + <bb N>: + __builtin_unreachable (); + <bb M>: +*/ + +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 + && r.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. */ @@ -1505,8 +1515,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 (); @@ -1514,6 +1522,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); @@ -1542,7 +1551,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) @@ -1590,7 +1598,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 @@ -1832,7 +1839,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; @@ -2073,6 +2080,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 @@ -2121,7 +2146,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. */ @@ -2218,17 +2243,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 <gcond *> (stmt), &taken_edge); + edge taken_edge = fold_cond (as_a <gcond *> (stmt)); if (taken_edge) { - if (taken_edge->flags & EDGE_TRUE_VALUE) - gimple_cond_make_true (as_a <gcond *> (stmt)); - else if (taken_edge->flags & EDGE_FALSE_VALUE) - gimple_cond_make_false (as_a <gcond *> (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 a70aebd..e64e4f2 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 f018d0d..8c8f031 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 *); |