https://gcc.gnu.org/g:58294ebfb40b05e1e4624006a8c5479293d398ec
commit r17-4892-g58294ebfb40b05e1e4624006a8c5479293d398ec Author: Aldy Hernandez <[email protected]> Date: Sun Oct 4 06:21:05 2026 +0000 DOM: replace simplify_binary_operation with the ranger DOM is using its simplify_binary_operation method to derive things that ranger can do better. Remove the function and let ranger do its thing. I added some functionality tests to make sure we don't mysteriously stop handling cases simplify_binary_operation did. Although that's unlikely as ranger is pretty mature by now, and surely a regression would pop up ;-). Tested on ppc64le Linux. gcc/ChangeLog: * tree-ssa-dom.cc (dom_opt_dom_walker::const_or_copy_of_stmt): New. (dom_opt_dom_walker::eliminate_redundant_computations): Ask it on a lookup miss. * tree-ssa-scopedtables.cc (simplify_binary_operation): Remove. (lookup_avail_expr): Do not call it. * tree-ssa-scopedtables.h (simplify_binary_operation): Remove. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/ssa-dom-simplify-2.c: New test. Diff: --- gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-simplify-2.c | 100 +++++++++++++ gcc/tree-ssa-dom.cc | 32 +++++ gcc/tree-ssa-scopedtables.cc | 154 +-------------------- gcc/tree-ssa-scopedtables.h | 5 - 4 files changed, 133 insertions(+), 158 deletions(-) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-simplify-2.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-simplify-2.c new file mode 100644 index 000000000000..b0985de9d568 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-simplify-2.c @@ -0,0 +1,100 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fgimple -fno-tree-vrp -fdump-tree-dom2" } */ + +/* x <= 5 and y >= 10 where x < y is computed, so it is 1. */ + +int __GIMPLE (ssa,startwith("dom")) +by_range_cmp (int x, int y) +{ + _Bool b; + int r; + + __BB(2): + if (x_1(D) > 5) + goto __BB5; + else + goto __BB3; + + __BB(3): + if (y_2(D) < 10) + goto __BB5; + else + goto __BB4; + + __BB(4): + b_3 = x_1(D) < y_2(D); + r_4 = (int) b_3; + return r_4; + + __BB(5): + return 0; +} + +/* 1 <= x <= 3 and 4 <= y <= 8 where x / y is computed, so it is 0. */ + +int __GIMPLE (ssa,startwith("dom")) +by_range_div (int x, int y) +{ + int q; + + __BB(2): + if (x_1(D) > 3) + goto __BB7; + else + goto __BB3; + + __BB(3): + if (x_1(D) < 1) + goto __BB7; + else + goto __BB4; + + __BB(4): + if (y_2(D) > 8) + goto __BB7; + else + goto __BB5; + + __BB(5): + if (y_2(D) < 4) + goto __BB7; + else + goto __BB6; + + __BB(6): + q_3 = x_1(D) / y_2(D); + return q_3; + + __BB(7): + return 7; +} + +/* x == y where x & y and x - y are computed, so they are x and 0. */ + +int __GIMPLE (ssa,startwith("dom")) +by_relation (int x, int y) +{ + int t; + int d; + int r; + + __BB(2): + if (x_1(D) == y_2(D)) + goto __BB3; + else + goto __BB4; + + __BB(3): + t_3 = x_1(D) & y_2(D); + d_4 = x_1(D) - y_2(D); + r_5 = t_3 + d_4; + return r_5; + + __BB(4): + return 0; +} + +/* { dg-final { scan-tree-dump-not "x_1\\(D\\) < y_2\\(D\\)" "dom2" } } */ +/* { dg-final { scan-tree-dump-not "x_1\\(D\\) / y_2\\(D\\)" "dom2" } } */ +/* { dg-final { scan-tree-dump-not "x_1\\(D\\) & y_2\\(D\\)" "dom2" } } */ +/* { dg-final { scan-tree-dump-not "x_1\\(D\\) - y_2\\(D\\)" "dom2" } } */ diff --git a/gcc/tree-ssa-dom.cc b/gcc/tree-ssa-dom.cc index 7ff6b912be6a..519661973ecf 100644 --- a/gcc/tree-ssa-dom.cc +++ b/gcc/tree-ssa-dom.cc @@ -822,6 +822,7 @@ private: void record_equivalences_from_incoming_edge (basic_block); void eliminate_redundant_computations (gimple_stmt_iterator *); void record_equivalences_from_stmt (gimple *, int); + tree const_or_copy_of_stmt (gimple *); jump_threader *m_threader; gimple_ranger *m_ranger; @@ -1789,6 +1790,33 @@ dom_opt_dom_walker::after_dom_children (basic_block bb) m_const_and_copies->pop_to_marker (); } +/* Return the constant STMT computes, and barring that, an operand its + result is equivalent to. NULL if neither. */ + +tree +dom_opt_dom_walker::const_or_copy_of_stmt (gimple *stmt) +{ + if (tree val = m_ranger->value_of_stmt (stmt)) + return val; + + /* We could remove this gate, but we'd end up with tons of useless + replacements (casts, copies, etc). Best to keep it to binops, which is + what the original code did. */ + if (!is_gimple_assign (stmt) + || gimple_assign_rhs_class (stmt) != GIMPLE_BINARY_RHS) + return NULL_TREE; + + tree lhs = gimple_assign_lhs (stmt); + tree rhs1 = gimple_assign_rhs1 (stmt); + tree rhs2 = gimple_assign_rhs2 (stmt); + if (m_ranger->relation ().query (stmt, lhs, rhs1) == VREL_EQ) + return rhs1; + if (m_ranger->relation ().query (stmt, lhs, rhs2) == VREL_EQ) + return rhs2; + + return NULL_TREE; +} + /* Search for redundant computations in STMT. If any are found, then replace them with the variable holding the result of the computation. @@ -1824,6 +1852,10 @@ dom_opt_dom_walker::eliminate_redundant_computations (gimple_stmt_iterator *gsi) /* Check if the expression has been computed before. */ cached_lhs = m_avail_exprs_stack->lookup_avail_expr (stmt, insert, true); + /* Otherwise, ask the ranger. */ + if (!cached_lhs) + cached_lhs = const_or_copy_of_stmt (stmt); + opt_stats.num_exprs_considered++; /* Get the type of the expression we are trying to optimize. */ diff --git a/gcc/tree-ssa-scopedtables.cc b/gcc/tree-ssa-scopedtables.cc index 242d3f0e7cc0..35ce7586d8bc 100644 --- a/gcc/tree-ssa-scopedtables.cc +++ b/gcc/tree-ssa-scopedtables.cc @@ -108,153 +108,6 @@ vuse_eq (ao_ref *, tree vuse1, void *data) return NULL; } -/* We looked for STMT in the hash table, but did not find it. - - If STMT is an assignment from a binary operator, we may know something - about the operands relationship to each other which would allow - us to derive a constant value for the RHS of STMT. */ - -tree -avail_exprs_stack::simplify_binary_operation (gimple *stmt, - class expr_hash_elt element) -{ - if (is_gimple_assign (stmt)) - { - struct hashable_expr *expr = element.expr (); - if (expr->kind == EXPR_BINARY) - { - enum tree_code code = expr->ops.binary.op; - - switch (code) - { - /* For these cases, if we know some relationships - between the operands, then we can simplify. */ - case MIN_EXPR: - case MAX_EXPR: - { - /* Build a simple equality expr and query the hash table - for it. */ - struct hashable_expr expr; - expr.type = boolean_type_node; - expr.kind = EXPR_BINARY; - expr.ops.binary.op = LE_EXPR; - tree rhs1 = gimple_assign_rhs1 (stmt); - tree rhs2 = gimple_assign_rhs2 (stmt); - if (tree_swap_operands_p (rhs1, rhs2)) - std::swap (rhs1, rhs2); - expr.ops.binary.opnd0 = rhs1; - expr.ops.binary.opnd1 = rhs2; - class expr_hash_elt element2 (&expr, NULL_TREE); - expr_hash_elt **slot - = m_avail_exprs->find_slot (&element2, NO_INSERT); - - /* If the query was successful and returned a nonzero - result, then we know the result of the MIN/MAX, even - though it is not a constant value. */ - if (slot && *slot && integer_onep ((*slot)->lhs ())) - return code == MIN_EXPR ? rhs1 : rhs2; - - /* Try again, this time with GE_EXPR. */ - expr.ops.binary.op = GE_EXPR; - class expr_hash_elt element3 (&expr, NULL_TREE); - slot = m_avail_exprs->find_slot (&element3, NO_INSERT); - - /* If the query was successful and returned a nonzero - result, then we know the result of the MIN/MAX, even - though it is not a constant value. */ - if (slot && *slot && integer_onep ((*slot)->lhs ())) - return code == MIN_EXPR ? rhs2 : rhs1; - - break; - } - - /* For these cases, if we know the operands - are equal, then we know the result. */ - case BIT_IOR_EXPR: - case BIT_AND_EXPR: - case BIT_XOR_EXPR: - case MINUS_EXPR: - case TRUNC_DIV_EXPR: - case CEIL_DIV_EXPR: - case FLOOR_DIV_EXPR: - case ROUND_DIV_EXPR: - case EXACT_DIV_EXPR: - case TRUNC_MOD_EXPR: - case CEIL_MOD_EXPR: - case FLOOR_MOD_EXPR: - case ROUND_MOD_EXPR: - { - /* Build a simple equality expr and query the hash table - for it. */ - struct hashable_expr expr; - expr.type = boolean_type_node; - expr.kind = EXPR_BINARY; - expr.ops.binary.op = EQ_EXPR; - tree rhs1 = gimple_assign_rhs1 (stmt); - tree rhs2 = gimple_assign_rhs2 (stmt); - if (tree_swap_operands_p (rhs1, rhs2)) - std::swap (rhs1, rhs2); - expr.ops.binary.opnd0 = rhs1; - expr.ops.binary.opnd1 = rhs2; - class expr_hash_elt element2 (&expr, NULL_TREE); - expr_hash_elt **slot - = m_avail_exprs->find_slot (&element2, NO_INSERT); - tree result_type = TREE_TYPE (gimple_assign_lhs (stmt)); - - /* If the query was successful and returned a nonzero - result, then we know that the operands of the binary - expression are the same. In many cases this allows - us to compute a constant result of the expression - at compile time, even if we do not know the exact - values of the operands. */ - if (slot && *slot && integer_onep ((*slot)->lhs ())) - { - switch (code) - { - case BIT_IOR_EXPR: - case BIT_AND_EXPR: - return gimple_assign_rhs1 (stmt); - - case MINUS_EXPR: - /* This is unsafe for certain floats even in non-IEEE - formats. In IEEE, it is unsafe because it does - wrong for NaNs. */ - if (FLOAT_TYPE_P (result_type) - && HONOR_NANS (result_type)) - break; - /* FALLTHRU */ - case BIT_XOR_EXPR: - case TRUNC_MOD_EXPR: - case CEIL_MOD_EXPR: - case FLOOR_MOD_EXPR: - case ROUND_MOD_EXPR: - return build_zero_cst (result_type); - - case TRUNC_DIV_EXPR: - case CEIL_DIV_EXPR: - case FLOOR_DIV_EXPR: - case ROUND_DIV_EXPR: - case EXACT_DIV_EXPR: - /* Avoid _Fract types where we can't build 1. */ - if (ALL_FRACT_MODE_P (TYPE_MODE (result_type))) - break; - return build_one_cst (result_type); - - default: - gcc_unreachable (); - } - } - break; - } - - default: - break; - } - } - } - return NULL_TREE; -} - /* Search for an existing instance of STMT in the AVAIL_EXPRS_STACK table. If found, return its LHS. Otherwise insert STMT in the table and return NULL_TREE. @@ -313,13 +166,8 @@ avail_exprs_stack::lookup_avail_expr (gimple *stmt, bool insert, bool tbaa_p, class expr_hash_elt *element2 = new expr_hash_elt (element); *slot = element2; - /* If we did not find the expression in the hash table, we may still - be able to produce a result for some expressions. */ - tree retval = avail_exprs_stack::simplify_binary_operation (stmt, - element); - record_expr (element2, NULL, '2'); - return retval; + return NULL_TREE; } /* If we found a redundant memory operation do an alias walk to diff --git a/gcc/tree-ssa-scopedtables.h b/gcc/tree-ssa-scopedtables.h index 0028b705145b..c7989b2c88e8 100644 --- a/gcc/tree-ssa-scopedtables.h +++ b/gcc/tree-ssa-scopedtables.h @@ -156,11 +156,6 @@ class avail_exprs_stack vec<std::pair<expr_hash_elt_t, expr_hash_elt_t> > m_stack; hash_table<expr_elt_hasher> *m_avail_exprs; - /* For some assignments where the RHS is a binary operator, if we know - a equality relationship between the operands, we may be able to compute - a result, even if we don't know the exact value of the operands. */ - tree simplify_binary_operation (gimple *, class expr_hash_elt); - /* We do not allow copying this object or initializing one from another. */ avail_exprs_stack& operator= (const avail_exprs_stack&);
