diff options
Diffstat (limited to 'gcc')
-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 *); |