https://gcc.gnu.org/g:ea48f0c5493cb0829127ec12d7af2ba3c5c11c97
commit r17-4889-gea48f0c5493cb0829127ec12d7af2ba3c5c11c97 Author: Aldy Hernandez <[email protected]> Date: Sun Oct 4 06:21:07 2026 +0000 DOM: replace test_for_singularity with simplify_using_ranges We now have all the pieces to do what test_for_singularity does, but with ranges. Remove the function and use simplify_using_ranges instead. This makes DOM a tiny bit smarter, since simplify_using_ranges is far more capable than the ad-hoc stuff we did. As much as I hate making it smarter, it's all in the interest of nuking it :). Tested on ppc64le Linux. gcc/ChangeLog: * tree-ssa-dom.cc (dom_opt_dom_walker::m_dummy_cond): Remove. (dom_opt_dom_walker::test_for_singularity): Remove. (dom_opt_dom_walker::fold_cond): Remove. (dom_opt_dom_walker::simplify_stmt): New. (dom_opt_dom_walker::optimize_stmt): Call it in place of test_for_singularity and fold_cond. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/predcom-7.c: Add -fno-tree-dominator-opts. * gcc.dg/tree-ssa/ssa-dom-simplify-3.c: New test. Diff: --- gcc/testsuite/gcc.dg/tree-ssa/predcom-7.c | 5 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-simplify-3.c | 91 +++++++++++ gcc/tree-ssa-dom.cc | 169 ++++----------------- 3 files changed, 127 insertions(+), 138 deletions(-) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/predcom-7.c b/gcc/testsuite/gcc.dg/tree-ssa/predcom-7.c index 999397675622..0a1bc5b3a2b8 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/predcom-7.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/predcom-7.c @@ -1,5 +1,8 @@ /* { dg-do run } */ -/* { dg-options "-O3 -fdump-tree-pcom-details-blocks" } */ +/* { dg-options "-O3 -fdump-tree-pcom-details-blocks -fno-tree-dominator-opts" } */ +/* DOM folds the exit test to c + 1 == 1 from c's range, which leaves c a + two-valued PHI rather than an induction variable and predcom nothing to + do; keep it out of the way. */ int b, f, d[5][2]; unsigned int c; diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-simplify-3.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-simplify-3.c new file mode 100644 index 000000000000..89d545e621d3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-simplify-3.c @@ -0,0 +1,91 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fgimple -fno-tree-vrp -fdump-tree-dom2" } */ + +void frob (void); + +/* x <= 4 at the last test, so x > 3 holds for x == 4 only. */ + +void __GIMPLE (ssa,startwith("dom")) +by_range (int x) +{ + __BB(2): + if (x_1(D) > 5) + goto __BB6; + else + goto __BB3; + + __BB(3): + if (x_1(D) == 5) + goto __BB6; + else + goto __BB4; + + __BB(4): + if (x_1(D) > 3) + goto __BB5; + else + goto __BB6; + + __BB(5): + frob (); + goto __BB6; + + __BB(6): + return; +} + +/* i <= j at the second test, so i >= j holds for i == j only. */ + +void __GIMPLE (ssa,startwith("dom")) +by_relation (int i, int j) +{ + __BB(2): + if (i_1(D) <= j_2(D)) + goto __BB3; + else + goto __BB5; + + __BB(3): + if (i_1(D) >= j_2(D)) + goto __BB4; + else + goto __BB5; + + __BB(4): + frob (); + goto __BB5; + + __BB(5): + return; +} + +/* a <= 10 and b >= 20 where the MIN is computed, so it is a. */ + +int __GIMPLE (ssa,startwith("dom")) +by_range_min (int a, int b) +{ + int m; + + __BB(2): + if (a_1(D) > 10) + goto __BB5; + else + goto __BB3; + + __BB(3): + if (b_2(D) < 20) + goto __BB5; + else + goto __BB4; + + __BB(4): + m_3 = __MIN (a_1(D), b_2(D)); + return m_3; + + __BB(5): + return 0; +} + +/* { dg-final { scan-tree-dump "if \\(x_1\\(D\\) == 4\\)" "dom2" } } */ +/* { dg-final { scan-tree-dump "if \\(i_1\\(D\\) == j_2\\(D\\)\\)" "dom2" } } */ +/* { dg-final { scan-tree-dump-not "MIN_EXPR" "dom2" } } */ diff --git a/gcc/tree-ssa-dom.cc b/gcc/tree-ssa-dom.cc index 7fded792a3c0..490eddc37c38 100644 --- a/gcc/tree-ssa-dom.cc +++ b/gcc/tree-ssa-dom.cc @@ -805,8 +805,6 @@ public: { m_ranger = ranger; m_state = state; - m_dummy_cond = gimple_build_cond (NE_EXPR, integer_zero_node, - integer_zero_node, NULL, NULL); m_const_and_copies = const_and_copies; m_avail_exprs_stack = avail_exprs_stack; m_threader = threader; @@ -821,9 +819,6 @@ private: class const_and_copies *m_const_and_copies; class avail_exprs_stack *m_avail_exprs_stack; - /* Dummy condition to avoid creating lots of throw away statements. */ - gcond *m_dummy_cond; - /* Optimize a single statement within a basic block using the various tables maintained by DOM. Returns the taken edge if the statement is a conditional with a statically determined @@ -832,8 +827,7 @@ private: void set_global_ranges_from_unreachable_edges (basic_block); - void test_for_singularity (gimple *, avail_exprs_stack *); - edge fold_cond (gcond *cond); + void simplify_stmt (gimple_stmt_iterator *); jump_threader *m_threader; gimple_ranger *m_ranger; @@ -2097,6 +2091,34 @@ cprop_operand (gimple *stmt, use_operand_p op_p, range_query *query) } } +/* Attempt to simplify the statement in GSI with range info. */ + +void +dom_opt_dom_walker::simplify_stmt (gimple_stmt_iterator *gsi) +{ + gimple *stmt = gsi_stmt (*gsi); + + /* Avoid switches as touching those could remove edges mid-walk. */ + if (gimple_code (stmt) == GIMPLE_SWITCH) + return; + + gimple_stmt_iterator i = *gsi; + gsi_prev (&i); + gimple *before = gsi_end_p (i) ? NULL : gsi_stmt (i); + simplify_using_ranges simplify (m_ranger); + if (!simplify.simplify (gsi)) + return; + + stmt = gsi_stmt (*gsi); + gimple_set_modified (stmt, true); + + /* Our main loop will go back over the statements inserted in front of STMT, + so mark those as visited to avoid looking at them again. */ + i = *gsi; + for (gsi_prev (&i); !gsi_end_p (i) && gsi_stmt (i) != before; gsi_prev (&i)) + gimple_set_visited (gsi_stmt (i), true); +} + /* CONST_AND_COPIES is a table which maps an SSA_NAME to the current known value for that SSA_NAME (or NULL if no value is known). @@ -2130,99 +2152,6 @@ cprop_into_stmt (gimple *stmt, range_query *query) } } -/* If STMT contains a relational test, try to convert it into an - equality test if there is only a single value which can ever - make the test true. - - For example, if the expression hash table contains: - - TRUE = (i <= 1) - - And we have a test within statement of i >= 1, then we can safely - rewrite the test as i == 1 since there only a single value where - the test is true. - - This is similar to code in VRP. */ - -void -dom_opt_dom_walker::test_for_singularity (gimple *stmt, - avail_exprs_stack *avail_exprs_stack) -{ - /* We want to support gimple conditionals as well as assignments - where the RHS contains a conditional. */ - if (is_gimple_assign (stmt) || gimple_code (stmt) == GIMPLE_COND) - { - enum tree_code code = ERROR_MARK; - tree lhs, rhs; - - /* Extract the condition of interest from both forms we support. */ - if (is_gimple_assign (stmt)) - { - code = gimple_assign_rhs_code (stmt); - lhs = gimple_assign_rhs1 (stmt); - rhs = gimple_assign_rhs2 (stmt); - } - else if (gimple_code (stmt) == GIMPLE_COND) - { - code = gimple_cond_code (as_a <gcond *> (stmt)); - lhs = gimple_cond_lhs (as_a <gcond *> (stmt)); - rhs = gimple_cond_rhs (as_a <gcond *> (stmt)); - } - - /* We're looking for a relational test using LE/GE. Also note we can - canonicalize LT/GT tests against constants into LE/GT tests. */ - if (code == LE_EXPR || code == GE_EXPR - || ((code == LT_EXPR || code == GT_EXPR) - && TREE_CODE (rhs) == INTEGER_CST)) - { - /* For LT_EXPR and GT_EXPR, canonicalize to LE_EXPR and GE_EXPR. */ - if (code == LT_EXPR) - rhs = fold_build2 (MINUS_EXPR, TREE_TYPE (rhs), - rhs, build_int_cst (TREE_TYPE (rhs), 1)); - - if (code == GT_EXPR) - rhs = fold_build2 (PLUS_EXPR, TREE_TYPE (rhs), - rhs, build_int_cst (TREE_TYPE (rhs), 1)); - - /* Determine the code we want to check for in the hash table. */ - enum tree_code test_code; - if (code == GE_EXPR || code == GT_EXPR) - test_code = LE_EXPR; - else - test_code = GE_EXPR; - - /* Update the dummy statement so we can query the hash tables. */ - gimple_cond_set_code (m_dummy_cond, test_code); - gimple_cond_set_lhs (m_dummy_cond, lhs); - gimple_cond_set_rhs (m_dummy_cond, rhs); - tree cached_lhs - = avail_exprs_stack->lookup_avail_expr (m_dummy_cond, - false, false); - - /* If the lookup returned 1 (true), then the expression we - queried was in the hash table. As a result there is only - one value that makes the original conditional true. Update - STMT accordingly. */ - if (cached_lhs && integer_onep (cached_lhs)) - { - if (is_gimple_assign (stmt)) - { - gimple_assign_set_rhs_code (stmt, EQ_EXPR); - gimple_assign_set_rhs2 (stmt, rhs); - gimple_set_modified (stmt, true); - } - else - { - gimple_set_modified (stmt, true); - gimple_cond_set_code (as_a <gcond *> (stmt), EQ_EXPR); - gimple_cond_set_rhs (as_a <gcond *> (stmt), rhs); - gimple_set_modified (stmt, true); - } - } - } - } -} - /* If STMT is a comparison of two uniform vectors reduce it to a comparison of scalar objects, otherwise leave STMT unchanged. */ @@ -2283,24 +2212,6 @@ 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 @@ -2437,24 +2348,6 @@ dom_opt_dom_walker::optimize_stmt (basic_block bb, gimple_stmt_iterator *si, integer_zero_node)); gimple_set_modified (stmt, true); } - else if (TREE_CODE (lhs) == SSA_NAME) - { - /* Exploiting EVRP data is not yet fully integrated into DOM - but we need to do something for this case to avoid regressing - udr4.f90 and new1.C which have unexecutable blocks with - undefined behavior that get diagnosed if they're left in the - IL because we've attached range information to new - SSA_NAMES. */ - update_stmt_if_modified (stmt); - edge taken_edge = fold_cond (as_a <gcond *> (stmt)); - if (taken_edge) - { - gimple_set_modified (stmt, true); - update_stmt (stmt); - cfg_altered = true; - return taken_edge; - } - } } update_stmt_if_modified (stmt); @@ -2509,7 +2402,9 @@ dom_opt_dom_walker::optimize_stmt (basic_block bb, gimple_stmt_iterator *si, /* If this statement was not redundant, we may still be able to simplify it, which may in turn allow other part of DOM or other passes to do a better job. */ - test_for_singularity (stmt, m_avail_exprs_stack); + if (!gimple_modified_p (stmt)) + simplify_stmt (si); + stmt = gsi_stmt (*si); } /* Record any additional equivalences created by this statement. */
