phiopt: Remove minmax_replacement [PR101024]

Now all of the optimizations are done in match from
minmax_replacement. We can now remove minmax_replacement. :)
This keeps around the special case for fp `a CMP b ? a : b` that was
added with r14-2699-g9f8f37f5490076 (PR 88540) and moves it to
match_simplify_replacement.

Bootsrapped and tested on x86_64-linux-gnu.

Note bool-12.c needed to be updated since phiopt1 rejecting the
BIT_AND/BIT_IOR with a cast and not getting MIN/MAX any more.

gcc/ChangeLog:

	PR tree-optimization/101024
	* tree-ssa-phiopt.cc (match_simplify_replacement): Special
	case fp `a CMP b ? a : b` when not creating a min/max.
	(strip_bit_not): Remove.
	(invert_minmax_code): Remove.
	(minmax_replacement): Remove.
	(pass_phiopt::execute): Update pass comment.
	Don't call minmax_replacement.

gcc/testsuite/ChangeLog:

	* gcc.dg/tree-ssa/bool-12.c: Update based on when BIT_AND/BIT_IOR
	is created and no longer MIN/MAX.

Signed-off-by: Andrew Pinski <andrew.pinski@oss.qualcomm.com>
This commit is contained in:
Andrew Pinski
2025-10-20 22:59:51 -07:00
parent 22448c7f64
commit f345fc997d
2 changed files with 36 additions and 652 deletions

View File

@@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-optimized -fdump-tree-original -fdump-tree-phiopt1 -fdump-tree-forwprop2" } */
/* { dg-options "-O1 -fdump-tree-optimized -fdump-tree-original -fdump-tree-phiopt2-raw" } */
#define bool _Bool
int maxbool(bool ab, bool bb)
{
@@ -28,15 +28,12 @@ int minbool(bool ab, bool bb)
/* { dg-final { scan-tree-dump-times "MIN_EXPR" 0 "original" } } */
/* { dg-final { scan-tree-dump-times "if " 2 "original" } } */
/* PHI-OPT1 should have converted it into min/max */
/* { dg-final { scan-tree-dump-times "MAX_EXPR" 1 "phiopt1" } } */
/* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "phiopt1" } } */
/* { dg-final { scan-tree-dump-times "if " 0 "phiopt1" } } */
/* Forwprop2 (after ccp) will convert it into &\| */
/* { dg-final { scan-tree-dump-times "MAX_EXPR" 0 "forwprop2" } } */
/* { dg-final { scan-tree-dump-times "MIN_EXPR" 0 "forwprop2" } } */
/* { dg-final { scan-tree-dump-times "if " 0 "forwprop2" } } */
/* PHI-OPT2 should have converted it into &\| */
/* { dg-final { scan-tree-dump-not "min_expr, " "phiopt2" } } */
/* { dg-final { scan-tree-dump-not "max_expr, " "phiopt2" } } */
/* { dg-final { scan-tree-dump-times "bit_ior_expr, " 1 "phiopt2" } } */
/* { dg-final { scan-tree-dump-times "bit_and_expr, " 1 "phiopt2" } } */
/* { dg-final { scan-tree-dump-times "gimple_cond " 0 "phiopt2" } } */
/* By optimize there should be no min/max nor if */
/* { dg-final { scan-tree-dump-times "MAX_EXPR" 0 "optimized" } } */

View File

@@ -1007,7 +1007,34 @@ match_simplify_replacement (basic_block cond_bb, basic_block middle_bb,
}
if (!result)
return false;
{
/* If we don't get back a MIN/MAX_EXPR still make sure the expression
stays in a form to be recognized by ISA that map to IEEE x > y ? x : y
semantics (that's not IEEE max semantics). */
if (!HONOR_NANS (type) && !HONOR_SIGNED_ZEROS (type))
return false;
if (stmt_to_move || stmt_to_move_alt)
return false;
tree_code cmp = gimple_cond_code (stmt);
if (cmp != LT_EXPR && cmp != LE_EXPR
&& cmp != GT_EXPR && cmp != GE_EXPR)
return false;
tree lhs = gimple_cond_lhs (stmt);
tree rhs = gimple_cond_rhs (stmt);
/* `lhs CMP rhs ? lhs : rhs` or `lhs CMP rhs ? rhs : lhs`
are only acceptable case here. */
if ((!operand_equal_for_phi_arg_p (lhs, arg_false)
|| !operand_equal_for_phi_arg_p (rhs, arg_true))
&& (!operand_equal_for_phi_arg_p (rhs, arg_false)
|| !operand_equal_for_phi_arg_p (lhs, arg_true)))
return false;
seq = nullptr;
result = gimple_build (&seq, cmp, boolean_type_node, lhs, rhs);
result = gimple_build (&seq, COND_EXPR, type, result,
arg_true, arg_false);
statistics_counter_event (cfun, "Non-IEEE FP MIN/MAX PHI replacement",
1);
}
if (dump_file && (dump_flags & TDF_FOLDING))
fprintf (dump_file, "accepted the phiopt match-simplify.\n");
@@ -1767,622 +1794,6 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
return 0;
}
/* If VAR is an SSA_NAME that points to a BIT_NOT_EXPR then return the TREE for
the value being inverted. */
static tree
strip_bit_not (tree var)
{
if (TREE_CODE (var) != SSA_NAME)
return NULL_TREE;
gimple *assign = SSA_NAME_DEF_STMT (var);
if (gimple_code (assign) != GIMPLE_ASSIGN)
return NULL_TREE;
if (gimple_assign_rhs_code (assign) != BIT_NOT_EXPR)
return NULL_TREE;
return gimple_assign_rhs1 (assign);
}
/* Invert a MIN to a MAX or a MAX to a MIN expression CODE. */
enum tree_code
invert_minmax_code (enum tree_code code)
{
switch (code) {
case MIN_EXPR:
return MAX_EXPR;
case MAX_EXPR:
return MIN_EXPR;
default:
gcc_unreachable ();
}
}
/* The function minmax_replacement does the main work of doing the minmax
replacement. Return true if the replacement is done. Otherwise return
false.
BB is the basic block where the replacement is going to be done on. ARG0
is argument 0 from the PHI. Likewise for ARG1.
If THREEWAY_P then expect the BB to be laid out in diamond shape with each
BB containing only a MIN or MAX expression. */
static bool
minmax_replacement (basic_block cond_bb, basic_block middle_bb, basic_block alt_middle_bb,
edge e0, edge e1, gphi *phi, tree arg0, tree arg1, bool threeway_p)
{
tree result;
edge true_edge, false_edge;
enum tree_code minmax, ass_code;
tree smaller, larger, arg_true, arg_false;
gimple_stmt_iterator gsi, gsi_from;
tree type = TREE_TYPE (gimple_phi_result (phi));
gcond *cond = as_a <gcond *> (*gsi_last_bb (cond_bb));
enum tree_code cmp = gimple_cond_code (cond);
tree rhs = gimple_cond_rhs (cond);
/* Turn EQ/NE of extreme values to order comparisons. */
if ((cmp == NE_EXPR || cmp == EQ_EXPR)
&& TREE_CODE (rhs) == INTEGER_CST
&& INTEGRAL_TYPE_P (TREE_TYPE (rhs)))
{
if (wi::eq_p (wi::to_wide (rhs), wi::min_value (TREE_TYPE (rhs))))
{
cmp = (cmp == EQ_EXPR) ? LT_EXPR : GE_EXPR;
rhs = wide_int_to_tree (TREE_TYPE (rhs),
wi::min_value (TREE_TYPE (rhs)) + 1);
}
else if (wi::eq_p (wi::to_wide (rhs), wi::max_value (TREE_TYPE (rhs))))
{
cmp = (cmp == EQ_EXPR) ? GT_EXPR : LE_EXPR;
rhs = wide_int_to_tree (TREE_TYPE (rhs),
wi::max_value (TREE_TYPE (rhs)) - 1);
}
}
/* This transformation is only valid for order comparisons. Record which
operand is smaller/larger if the result of the comparison is true. */
tree alt_smaller = NULL_TREE;
tree alt_larger = NULL_TREE;
if (cmp == LT_EXPR || cmp == LE_EXPR)
{
smaller = gimple_cond_lhs (cond);
larger = rhs;
/* If we have smaller < CST it is equivalent to smaller <= CST-1.
Likewise smaller <= CST is equivalent to smaller < CST+1. */
if (TREE_CODE (larger) == INTEGER_CST
&& INTEGRAL_TYPE_P (TREE_TYPE (larger)))
{
if (cmp == LT_EXPR)
{
wi::overflow_type overflow;
wide_int alt = wi::sub (wi::to_wide (larger), 1,
TYPE_SIGN (TREE_TYPE (larger)),
&overflow);
if (! overflow)
alt_larger = wide_int_to_tree (TREE_TYPE (larger), alt);
}
else
{
wi::overflow_type overflow;
wide_int alt = wi::add (wi::to_wide (larger), 1,
TYPE_SIGN (TREE_TYPE (larger)),
&overflow);
if (! overflow)
alt_larger = wide_int_to_tree (TREE_TYPE (larger), alt);
}
}
}
else if (cmp == GT_EXPR || cmp == GE_EXPR)
{
smaller = rhs;
larger = gimple_cond_lhs (cond);
/* If we have larger > CST it is equivalent to larger >= CST+1.
Likewise larger >= CST is equivalent to larger > CST-1. */
if (TREE_CODE (smaller) == INTEGER_CST
&& INTEGRAL_TYPE_P (TREE_TYPE (smaller)))
{
wi::overflow_type overflow;
if (cmp == GT_EXPR)
{
wide_int alt = wi::add (wi::to_wide (smaller), 1,
TYPE_SIGN (TREE_TYPE (smaller)),
&overflow);
if (! overflow)
alt_smaller = wide_int_to_tree (TREE_TYPE (smaller), alt);
}
else
{
wide_int alt = wi::sub (wi::to_wide (smaller), 1,
TYPE_SIGN (TREE_TYPE (smaller)),
&overflow);
if (! overflow)
alt_smaller = wide_int_to_tree (TREE_TYPE (smaller), alt);
}
}
}
else
return false;
/* Handle the special case of (signed_type)x < 0 being equivalent
to x > MAX_VAL(signed_type) and (signed_type)x >= 0 equivalent
to x <= MAX_VAL(signed_type). */
if ((cmp == GE_EXPR || cmp == LT_EXPR)
&& INTEGRAL_TYPE_P (type)
&& TYPE_UNSIGNED (type)
&& integer_zerop (rhs))
{
tree op = gimple_cond_lhs (cond);
if (TREE_CODE (op) == SSA_NAME
&& INTEGRAL_TYPE_P (TREE_TYPE (op))
&& !TYPE_UNSIGNED (TREE_TYPE (op)))
{
gimple *def_stmt = SSA_NAME_DEF_STMT (op);
if (gimple_assign_cast_p (def_stmt))
{
tree op1 = gimple_assign_rhs1 (def_stmt);
if (INTEGRAL_TYPE_P (TREE_TYPE (op1))
&& TYPE_UNSIGNED (TREE_TYPE (op1))
&& (TYPE_PRECISION (TREE_TYPE (op))
== TYPE_PRECISION (TREE_TYPE (op1)))
&& useless_type_conversion_p (type, TREE_TYPE (op1)))
{
wide_int w1 = wi::max_value (TREE_TYPE (op));
wide_int w2 = wi::add (w1, 1);
if (cmp == LT_EXPR)
{
larger = op1;
smaller = wide_int_to_tree (TREE_TYPE (op1), w1);
alt_smaller = wide_int_to_tree (TREE_TYPE (op1), w2);
alt_larger = NULL_TREE;
}
else
{
smaller = op1;
larger = wide_int_to_tree (TREE_TYPE (op1), w1);
alt_larger = wide_int_to_tree (TREE_TYPE (op1), w2);
alt_smaller = NULL_TREE;
}
}
}
}
}
/* We need to know which is the true edge and which is the false
edge so that we know if have abs or negative abs. */
extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);
/* Forward the edges over the middle basic block. */
if (true_edge->dest == middle_bb)
true_edge = EDGE_SUCC (true_edge->dest, 0);
if (false_edge->dest == middle_bb)
false_edge = EDGE_SUCC (false_edge->dest, 0);
/* When THREEWAY_P then e1 will point to the edge of the final transition
from middle-bb to end. */
if (true_edge == e0)
{
if (!threeway_p)
gcc_assert (false_edge == e1);
arg_true = arg0;
arg_false = arg1;
}
else
{
gcc_assert (false_edge == e0);
if (!threeway_p)
gcc_assert (true_edge == e1);
arg_true = arg1;
arg_false = arg0;
}
if (empty_block_p (middle_bb)
&& (!threeway_p
|| empty_block_p (alt_middle_bb)))
{
if ((operand_equal_for_phi_arg_p (arg_true, smaller)
|| (alt_smaller
&& operand_equal_for_phi_arg_p (arg_true, alt_smaller)))
&& (operand_equal_for_phi_arg_p (arg_false, larger)
|| (alt_larger
&& operand_equal_for_phi_arg_p (arg_true, alt_larger))))
{
/* Case
if (smaller < larger)
rslt = smaller;
else
rslt = larger; */
minmax = MIN_EXPR;
}
else if ((operand_equal_for_phi_arg_p (arg_false, smaller)
|| (alt_smaller
&& operand_equal_for_phi_arg_p (arg_false, alt_smaller)))
&& (operand_equal_for_phi_arg_p (arg_true, larger)
|| (alt_larger
&& operand_equal_for_phi_arg_p (arg_true, alt_larger))))
minmax = MAX_EXPR;
else
return false;
}
else if (HONOR_NANS (type) || HONOR_SIGNED_ZEROS (type))
/* The optimization may be unsafe due to NaNs. */
return false;
else if (middle_bb != alt_middle_bb && threeway_p)
{
/* Recognize the following case:
if (smaller < larger)
a = MIN (smaller, c);
else
b = MIN (larger, c);
x = PHI <a, b>
This is equivalent to
a = MIN (smaller, c);
x = MIN (larger, a); */
gimple *assign = last_and_only_stmt (middle_bb);
tree lhs, op0, op1, bound;
tree alt_lhs, alt_op0, alt_op1;
bool invert = false;
/* When THREEWAY_P then e1 will point to the edge of the final transition
from middle-bb to end. */
if (true_edge == e0)
gcc_assert (false_edge == EDGE_PRED (e1->src, 0));
else
gcc_assert (true_edge == EDGE_PRED (e1->src, 0));
bool valid_minmax_p = false;
gimple_stmt_iterator it1
= gsi_start_nondebug_after_labels_bb (middle_bb);
gimple_stmt_iterator it2
= gsi_start_nondebug_after_labels_bb (alt_middle_bb);
if (gsi_one_nondebug_before_end_p (it1)
&& gsi_one_nondebug_before_end_p (it2))
{
gimple *stmt1 = gsi_stmt (it1);
gimple *stmt2 = gsi_stmt (it2);
if (is_gimple_assign (stmt1) && is_gimple_assign (stmt2))
{
enum tree_code code1 = gimple_assign_rhs_code (stmt1);
enum tree_code code2 = gimple_assign_rhs_code (stmt2);
valid_minmax_p = (code1 == MIN_EXPR || code1 == MAX_EXPR)
&& (code2 == MIN_EXPR || code2 == MAX_EXPR);
}
}
if (!valid_minmax_p)
return false;
if (!assign
|| gimple_code (assign) != GIMPLE_ASSIGN)
return false;
/* There cannot be any phi nodes in the middle bb. */
if (!gimple_seq_empty_p (phi_nodes (middle_bb)))
return false;
lhs = gimple_assign_lhs (assign);
ass_code = gimple_assign_rhs_code (assign);
if (ass_code != MAX_EXPR && ass_code != MIN_EXPR)
return false;
op0 = gimple_assign_rhs1 (assign);
op1 = gimple_assign_rhs2 (assign);
assign = last_and_only_stmt (alt_middle_bb);
if (!assign
|| gimple_code (assign) != GIMPLE_ASSIGN)
return false;
/* There cannot be any phi nodes in the alt middle bb. */
if (!gimple_seq_empty_p (phi_nodes (alt_middle_bb)))
return false;
alt_lhs = gimple_assign_lhs (assign);
if (ass_code != gimple_assign_rhs_code (assign))
return false;
if (!operand_equal_for_phi_arg_p (lhs, arg_true)
|| !operand_equal_for_phi_arg_p (alt_lhs, arg_false))
return false;
alt_op0 = gimple_assign_rhs1 (assign);
alt_op1 = gimple_assign_rhs2 (assign);
if ((operand_equal_for_phi_arg_p (op0, smaller)
|| (alt_smaller
&& operand_equal_for_phi_arg_p (op0, alt_smaller)))
&& (operand_equal_for_phi_arg_p (alt_op0, larger)
|| (alt_larger
&& operand_equal_for_phi_arg_p (alt_op0, alt_larger))))
{
/* We got here if the condition is true, i.e., SMALLER < LARGER. */
if (!operand_equal_for_phi_arg_p (op1, alt_op1))
return false;
if ((arg0 = strip_bit_not (op0)) != NULL
&& (arg1 = strip_bit_not (alt_op0)) != NULL
&& (bound = strip_bit_not (op1)) != NULL)
{
minmax = MAX_EXPR;
ass_code = invert_minmax_code (ass_code);
invert = true;
}
else
{
bound = op1;
minmax = MIN_EXPR;
arg0 = op0;
arg1 = alt_op0;
}
}
else if ((operand_equal_for_phi_arg_p (op0, larger)
|| (alt_larger
&& operand_equal_for_phi_arg_p (op0, alt_larger)))
&& (operand_equal_for_phi_arg_p (alt_op0, smaller)
|| (alt_smaller
&& operand_equal_for_phi_arg_p (alt_op0, alt_smaller))))
{
/* We got here if the condition is true, i.e., SMALLER > LARGER. */
if (!operand_equal_for_phi_arg_p (op1, alt_op1))
return false;
if ((arg0 = strip_bit_not (op0)) != NULL
&& (arg1 = strip_bit_not (alt_op0)) != NULL
&& (bound = strip_bit_not (op1)) != NULL)
{
minmax = MIN_EXPR;
ass_code = invert_minmax_code (ass_code);
invert = true;
}
else
{
bound = op1;
minmax = MAX_EXPR;
arg0 = op0;
arg1 = alt_op0;
}
}
else
return false;
/* Emit the statement to compute min/max. */
location_t locus = gimple_location (last_nondebug_stmt (cond_bb));
gimple_seq stmts = NULL;
tree phi_result = gimple_phi_result (phi);
result = gimple_build (&stmts, locus, minmax, TREE_TYPE (phi_result),
arg0, arg1);
result = gimple_build (&stmts, locus, ass_code, TREE_TYPE (phi_result),
result, bound);
if (invert)
result = gimple_build (&stmts, locus, BIT_NOT_EXPR, TREE_TYPE (phi_result),
result);
gsi = gsi_last_bb (cond_bb);
gsi_insert_seq_before (&gsi, stmts, GSI_NEW_STMT);
replace_phi_edge_with_variable (cond_bb, e1, phi, result);
return true;
}
else if (!threeway_p
|| empty_block_p (alt_middle_bb))
{
/* Recognize the following case, assuming d <= u:
if (a <= u)
b = MAX (a, d);
x = PHI <b, u>
This is equivalent to
b = MAX (a, d);
x = MIN (b, u); */
gimple *assign = last_and_only_stmt (middle_bb);
tree lhs, op0, op1, bound;
if (!single_pred_p (middle_bb))
return false;
if (!assign
|| gimple_code (assign) != GIMPLE_ASSIGN)
return false;
/* There cannot be any phi nodes in the middle bb. */
if (!gimple_seq_empty_p (phi_nodes (middle_bb)))
return false;
lhs = gimple_assign_lhs (assign);
ass_code = gimple_assign_rhs_code (assign);
if (ass_code != MAX_EXPR && ass_code != MIN_EXPR)
return false;
op0 = gimple_assign_rhs1 (assign);
op1 = gimple_assign_rhs2 (assign);
if (true_edge->src == middle_bb)
{
/* We got here if the condition is true, i.e., SMALLER < LARGER. */
if (!operand_equal_for_phi_arg_p (lhs, arg_true))
return false;
if (operand_equal_for_phi_arg_p (arg_false, larger)
|| (alt_larger
&& operand_equal_for_phi_arg_p (arg_false, alt_larger)))
{
/* Case
if (smaller < larger)
{
r' = MAX_EXPR (smaller, bound)
}
r = PHI <r', larger> --> to be turned to MIN_EXPR. */
if (ass_code != MAX_EXPR)
return false;
minmax = MIN_EXPR;
if (operand_equal_for_phi_arg_p (op0, smaller)
|| (alt_smaller
&& operand_equal_for_phi_arg_p (op0, alt_smaller)))
bound = op1;
else if (operand_equal_for_phi_arg_p (op1, smaller)
|| (alt_smaller
&& operand_equal_for_phi_arg_p (op1, alt_smaller)))
bound = op0;
else
return false;
/* We need BOUND <= LARGER. */
if (!integer_nonzerop (fold_build2 (LE_EXPR, boolean_type_node,
bound, arg_false)))
return false;
}
else if (operand_equal_for_phi_arg_p (arg_false, smaller)
|| (alt_smaller
&& operand_equal_for_phi_arg_p (arg_false, alt_smaller)))
{
/* Case
if (smaller < larger)
{
r' = MIN_EXPR (larger, bound)
}
r = PHI <r', smaller> --> to be turned to MAX_EXPR. */
if (ass_code != MIN_EXPR)
return false;
minmax = MAX_EXPR;
if (operand_equal_for_phi_arg_p (op0, larger)
|| (alt_larger
&& operand_equal_for_phi_arg_p (op0, alt_larger)))
bound = op1;
else if (operand_equal_for_phi_arg_p (op1, larger)
|| (alt_larger
&& operand_equal_for_phi_arg_p (op1, alt_larger)))
bound = op0;
else
return false;
/* We need BOUND >= SMALLER. */
if (!integer_nonzerop (fold_build2 (GE_EXPR, boolean_type_node,
bound, arg_false)))
return false;
}
else
return false;
}
else
{
/* We got here if the condition is false, i.e., SMALLER > LARGER. */
if (!operand_equal_for_phi_arg_p (lhs, arg_false))
return false;
if (operand_equal_for_phi_arg_p (arg_true, larger)
|| (alt_larger
&& operand_equal_for_phi_arg_p (arg_true, alt_larger)))
{
/* Case
if (smaller > larger)
{
r' = MIN_EXPR (smaller, bound)
}
r = PHI <r', larger> --> to be turned to MAX_EXPR. */
if (ass_code != MIN_EXPR)
return false;
minmax = MAX_EXPR;
if (operand_equal_for_phi_arg_p (op0, smaller)
|| (alt_smaller
&& operand_equal_for_phi_arg_p (op0, alt_smaller)))
bound = op1;
else if (operand_equal_for_phi_arg_p (op1, smaller)
|| (alt_smaller
&& operand_equal_for_phi_arg_p (op1, alt_smaller)))
bound = op0;
else
return false;
/* We need BOUND >= LARGER. */
if (!integer_nonzerop (fold_build2 (GE_EXPR, boolean_type_node,
bound, arg_true)))
return false;
}
else if (operand_equal_for_phi_arg_p (arg_true, smaller)
|| (alt_smaller
&& operand_equal_for_phi_arg_p (arg_true, alt_smaller)))
{
/* Case
if (smaller > larger)
{
r' = MAX_EXPR (larger, bound)
}
r = PHI <r', smaller> --> to be turned to MIN_EXPR. */
if (ass_code != MAX_EXPR)
return false;
minmax = MIN_EXPR;
if (operand_equal_for_phi_arg_p (op0, larger))
bound = op1;
else if (operand_equal_for_phi_arg_p (op1, larger))
bound = op0;
else
return false;
/* We need BOUND <= SMALLER. */
if (!integer_nonzerop (fold_build2 (LE_EXPR, boolean_type_node,
bound, arg_true)))
return false;
}
else
return false;
}
/* Move the statement from the middle block. */
gsi = gsi_last_bb (cond_bb);
gsi_from = gsi_last_nondebug_bb (middle_bb);
reset_flow_sensitive_info (SINGLE_SSA_TREE_OPERAND (gsi_stmt (gsi_from),
SSA_OP_DEF));
gsi_move_before (&gsi_from, &gsi);
}
else
return false;
/* Emit the statement to compute min/max. */
gimple_seq stmts = NULL;
tree phi_result = gimple_phi_result (phi);
/* When we can't use a MIN/MAX_EXPR still make sure the expression
stays in a form to be recognized by ISA that map to IEEE x > y ? x : y
semantics (that's not IEEE max semantics). */
if (HONOR_NANS (type) || HONOR_SIGNED_ZEROS (type))
{
result = gimple_build (&stmts, cmp, boolean_type_node,
gimple_cond_lhs (cond), rhs);
result = gimple_build (&stmts, COND_EXPR, TREE_TYPE (phi_result),
result, arg_true, arg_false);
}
else
result = gimple_build (&stmts, minmax, TREE_TYPE (phi_result), arg0, arg1);
gsi = gsi_last_bb (cond_bb);
gsi_insert_seq_before (&gsi, stmts, GSI_NEW_STMT);
replace_phi_edge_with_variable (cond_bb, e1, phi, result);
return true;
}
/* Attempt to optimize (x <=> y) cmp 0 and similar comparisons.
For strong ordering <=> try to match something like:
<bb 2> : // cond3_bb (== cond2_bb)
@@ -4365,9 +3776,8 @@ execute_over_cond_phis (func_type func)
But in this case bb1/bb2 can only be forwarding basic blocks.
This fully replaces the old "Conditional Replacement",
"ABS Replacement" transformations as they are now
"ABS Replacement" and "MIN/MAX Replacement" transformations as they are now
implmeneted in match.pd.
Some parts of the "MIN/MAX Replacement" are re-implemented in match.pd.
Value Replacement
-----------------
@@ -4409,26 +3819,6 @@ execute_over_cond_phis (func_type func)
t3 = t1 & t2;
x = a;
MIN/MAX Replacement
-------------------
This transformation, minmax_replacement replaces
bb0:
if (a <= b) goto bb2; else goto bb1;
bb1:
bb2:
x = PHI <b (bb1), a (bb0), ...>;
with
bb0:
x' = MIN_EXPR (a, b)
bb2:
x = PHI <x' (bb0), ...>;
A similar transformation is done for MAX_EXPR.
This pass also performs a fifth transformation of a slightly different
flavor.
@@ -4642,9 +4032,6 @@ pass_phiopt::execute (function *)
&& cond_removal_in_builtin_zero_pattern (bb, bb1, e1, e2,
phi, arg0, arg1))
cfgchanged = true;
else if (minmax_replacement (bb, bb1, bb2, e1, e2, phi, arg0, arg1,
diamond_p))
cfgchanged = true;
else if (single_pred_p (bb1)
&& !diamond_p
&& spaceship_replacement (bb, bb1, e1, e2, phi, arg0, arg1))