This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch] MIN/MAX_EXPR transform in phiopts
- From: Zdenek Dvorak <rakdver at atrey dot karlin dot mff dot cuni dot cz>
- To: gcc-patches at gcc dot gnu dot org
- Cc: stevenb at suse dot de
- Date: Fri, 11 Mar 2005 09:52:13 +0100
- Subject: [patch] MIN/MAX_EXPR transform in phiopts
Hello,
this patch makes ivopts turn
if (a < b)
a = b;
into
a = MAX_EXPR (a, b)
and
if (a < 0)
a = 0;
else if (a > 10)
a = 10;
into
a = MAX_EXPR (0, MIN_EXPR (a, 10))
It also makes several related cleanups to phiopts:
1) To handle nested conditionals (like in the later transforms), phiopts
pass the blocks using FOR_EACH_BB_REVERSE, so that the inner
conditions are tested and collapsed first. This is not reliable,
since the order of the blocks in the list may be arbitrary.
The patch forces a correct ordering -- the one in that a basic
block with a single predecessor is guaranteed to be processed
before the predecessor.
2) abs_replacement is made to use last_and_only_stmt instead of
nontrivially looking loop to pass over the statements of the
middle block.
3) On a few places, build is replaced with build1/build2.
Bootstrapped & regtested on i686 and ppc.
Btw.: yesterday I noticed Steven mentioning in a mailing list that he has
a similar patch; sorry for the work duplication, I had already the patch
in testing at the moment :-(
Zdenek
* tree-ssa-phiopt.c (minmax_replacement, blocks_in_phiopt_order):
New functions.
(tree_ssa_phiopt): Use blocks_in_phiopt_order and minmax_replacement.
Remove unused removed_phis variable.
(conditional_replacement): Use build1/build2.
(abs_replacement): Use last_and_only_stmt and build1/build2.
* gcc.dg/tree-ssa/phi-opt-5.c: New test.
Index: tree-ssa-phiopt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-phiopt.c,v
retrieving revision 2.25
diff -c -3 -p -r2.25 tree-ssa-phiopt.c
*** tree-ssa-phiopt.c 8 Mar 2005 13:56:58 -0000 2.25
--- tree-ssa-phiopt.c 10 Mar 2005 23:48:04 -0000
*************** static bool conditional_replacement (bas
*** 41,50 ****
--- 41,53 ----
edge, edge, tree, tree, tree);
static bool value_replacement (basic_block, basic_block, basic_block,
edge, edge, tree, tree, tree);
+ static bool minmax_replacement (basic_block, basic_block, basic_block,
+ edge, edge, tree, tree, tree);
static bool abs_replacement (basic_block, basic_block, basic_block,
edge, edge, tree, tree, tree);
static void replace_phi_edge_with_variable (basic_block, basic_block, edge,
tree, tree);
+ static basic_block *blocks_in_phiopt_order (void);
/* This pass eliminates PHI nodes which can be trivially implemented as
an assignment from a conditional expression. i.e. if we have something
*************** static void replace_phi_edge_with_variab
*** 102,107 ****
--- 105,125 ----
bb2:
x = ABS_EXPR< a >;
+ Similarly,
+
+ bb0:
+ if (a <= b) goto bb2; else goto bb1;
+ bb1:
+ goto bb2;
+ bb2:
+ x = PHI (b (bb1), a (bb0));
+
+ Becomes
+
+ x = MIN_EXPR (a, b)
+
+ And the same transformation for MAX_EXPR.
+
bb1 will become unreachable and bb0 and bb2 will almost always be merged
into a single block. Similar transformations are done by the ifcvt
RTL optimizer. */
*************** static void
*** 110,125 ****
tree_ssa_phiopt (void)
{
basic_block bb;
! bool removed_phis = false;
! /* Search every basic block for COND_EXPR we may be able to optimize
! in reverse order so we can find more. */
! FOR_EACH_BB_REVERSE (bb)
{
tree cond_expr;
tree phi;
basic_block bb1, bb2;
edge e1, e2;
cond_expr = last_stmt (bb);
/* Check to see if the last statement is a COND_EXPR. */
--- 128,155 ----
tree_ssa_phiopt (void)
{
basic_block bb;
! basic_block *bb_order;
! unsigned n, i;
!
! /* Search every basic block for COND_EXPR we may be able to optimize.
! We walk the blocks in order that guarantees that a block with
! a single predecessor is processed before the predecessor.
! This ensures that we collapse inner ifs before visiting the
! outer ones, and also that we do not try to visit a removed
! block. */
! bb_order = blocks_in_phiopt_order ();
! n = n_basic_blocks;
!
! for (i = 0; i < n; i++)
{
tree cond_expr;
tree phi;
basic_block bb1, bb2;
edge e1, e2;
+ tree arg0, arg1;
+
+ bb = bb_order[i];
cond_expr = last_stmt (bb);
/* Check to see if the last statement is a COND_EXPR. */
*************** tree_ssa_phiopt (void)
*** 175,202 ****
/* Check to make sure that there is only one PHI node.
TODO: we could do it with more than one iff the other PHI nodes
have the same elements for these two edges. */
! if (phi && PHI_CHAIN (phi) == NULL)
! {
! tree arg0 = NULL, arg1 = NULL;
! arg0 = PHI_ARG_DEF_TREE (phi, e1->dest_idx);
! arg1 = PHI_ARG_DEF_TREE (phi, e2->dest_idx);
! /* We know something is wrong if we cannot find the edges in the PHI
! node. */
! gcc_assert (arg0 != NULL && arg1 != NULL);
!
! /* Do the replacement of conditional if it can be done. */
! if (conditional_replacement (bb, bb1, bb2, e1, e2, phi, arg0, arg1)
! || value_replacement (bb, bb1, bb2, e1, e2, phi, arg0, arg1)
! || abs_replacement (bb, bb1, bb2, e1, e2, phi, arg0, arg1))
! {
! /* We have done the replacement so we need to rebuild the
! cfg when this pass is complete. */
! removed_phis = true;
! }
}
}
}
/* Return TRUE if block BB has no executable statements, otherwise return
--- 205,281 ----
/* Check to make sure that there is only one PHI node.
TODO: we could do it with more than one iff the other PHI nodes
have the same elements for these two edges. */
! if (!phi || PHI_CHAIN (phi) != NULL)
! continue;
! arg0 = PHI_ARG_DEF_TREE (phi, e1->dest_idx);
! arg1 = PHI_ARG_DEF_TREE (phi, e2->dest_idx);
! /* We know something is wrong if we cannot find the edges in the PHI
! node. */
! gcc_assert (arg0 != NULL && arg1 != NULL);
!
! /* Do the replacement of conditional if it can be done. */
! if (conditional_replacement (bb, bb1, bb2, e1, e2, phi, arg0, arg1))
! ;
! else if (value_replacement (bb, bb1, bb2, e1, e2, phi, arg0, arg1))
! ;
! else if (abs_replacement (bb, bb1, bb2, e1, e2, phi, arg0, arg1))
! ;
! else
! minmax_replacement (bb, bb1, bb2, e1, e2, phi, arg0, arg1);
! }
!
! free (bb_order);
! }
!
! /* Returns the list of basic blocks in the function in an order that guarantees
! that if a block X has just a single predecessor Y, then Y is after X in the
! ordering. */
!
! static basic_block *
! blocks_in_phiopt_order (void)
! {
! basic_block x, y;
! basic_block *order = xmalloc (sizeof (basic_block) * n_basic_blocks);
! unsigned n = n_basic_blocks, np, i;
!
! ENTRY_BLOCK_PTR->flags |= BB_VISITED;
! FOR_EACH_BB (x)
! {
! if (x->flags & BB_VISITED)
! continue;
!
! /* Walk the predecessors of x as long as they have precisely one
! predecessor and add them to the list, so that they get stored
! after x. */
! for (y = x, np = 1;
! EDGE_COUNT (y->preds) == 1
! && !(EDGE_PRED (y, 0)->src->flags & BB_VISITED);
! y = EDGE_PRED (y, 0)->src)
! np++;
! for (y = x, i = n - np;
! EDGE_COUNT (y->preds) == 1
! && !(EDGE_PRED (y, 0)->src->flags & BB_VISITED);
! y = EDGE_PRED (y, 0)->src, i++)
! {
! order[i] = y;
! y->flags |= BB_VISITED;
}
+ order[i] = y;
+ y->flags |= BB_VISITED;
+
+ gcc_assert (i == n - 1);
+ n -= np;
+ }
+
+ ENTRY_BLOCK_PTR->flags &= ~BB_VISITED;
+ FOR_EACH_BB (x)
+ {
+ x->flags &= ~BB_VISITED;
}
+ gcc_assert (n == 0);
+ return order;
}
/* Return TRUE if block BB has no executable statements, otherwise return
*************** conditional_replacement (basic_block con
*** 328,338 ****
if (!COMPARISON_CLASS_P (old_result))
return false;
! new1 = build (TREE_CODE (old_result), TREE_TYPE (old_result),
! TREE_OPERAND (old_result, 0),
! TREE_OPERAND (old_result, 1));
! new1 = build (MODIFY_EXPR, TREE_TYPE (old_result), new_var, new1);
bsi_insert_after (&bsi, new1, BSI_NEW_STMT);
}
--- 407,417 ----
if (!COMPARISON_CLASS_P (old_result))
return false;
! new1 = build2 (TREE_CODE (old_result), TREE_TYPE (old_result),
! TREE_OPERAND (old_result, 0),
! TREE_OPERAND (old_result, 1));
! new1 = build2 (MODIFY_EXPR, TREE_TYPE (old_result), new_var, new1);
bsi_insert_after (&bsi, new1, BSI_NEW_STMT);
}
*************** conditional_replacement (basic_block con
*** 361,367 ****
|| (e1 == true_edge && integer_onep (arg1))
|| (e1 == false_edge && integer_zerop (arg1)))
{
! new = build (MODIFY_EXPR, TREE_TYPE (new_var1), new_var1, cond);
}
else
{
--- 440,446 ----
|| (e1 == true_edge && integer_onep (arg1))
|| (e1 == false_edge && integer_zerop (arg1)))
{
! new = build2 (MODIFY_EXPR, TREE_TYPE (new_var1), new_var1, cond);
}
else
{
*************** conditional_replacement (basic_block con
*** 383,389 ****
{
tree temp = TREE_OPERAND (cond, 0);
tree new_var_1 = make_rename_temp (TREE_TYPE (temp), NULL);
! new = build (MODIFY_EXPR, TREE_TYPE (new_var_1), new_var_1, temp);
bsi_insert_after (&bsi, new, BSI_NEW_STMT);
cond = fold_convert (TREE_TYPE (result), new_var_1);
}
--- 462,468 ----
{
tree temp = TREE_OPERAND (cond, 0);
tree new_var_1 = make_rename_temp (TREE_TYPE (temp), NULL);
! new = build2 (MODIFY_EXPR, TREE_TYPE (new_var_1), new_var_1, temp);
bsi_insert_after (&bsi, new, BSI_NEW_STMT);
cond = fold_convert (TREE_TYPE (result), new_var_1);
}
*************** conditional_replacement (basic_block con
*** 395,401 ****
return false;
}
! new = build (MODIFY_EXPR, TREE_TYPE (new_var1), new_var1, cond);
}
bsi_insert_after (&bsi, new, BSI_NEW_STMT);
--- 474,480 ----
return false;
}
! new = build2 (MODIFY_EXPR, TREE_TYPE (new_var1), new_var1, cond);
}
bsi_insert_after (&bsi, new, BSI_NEW_STMT);
*************** value_replacement (basic_block cond_bb,
*** 488,493 ****
--- 567,823 ----
return false;
}
+ /* 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. */
+
+ static bool
+ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
+ basic_block phi_bb, edge e0, edge e1, tree phi,
+ tree arg0, tree arg1)
+ {
+ tree result, type;
+ tree cond, new;
+ edge true_edge, false_edge;
+ enum tree_code cmp, minmax, ass_code;
+ tree smaller, larger, arg_true, arg_false;
+ block_stmt_iterator bsi, bsi_from;
+
+ type = TREE_TYPE (PHI_RESULT (phi));
+
+ /* The optimization may be unsafe due to NaNs. */
+ if (HONOR_NANS (TYPE_MODE (type)))
+ return false;
+
+ cond = COND_EXPR_COND (last_stmt (cond_bb));
+ cmp = TREE_CODE (cond);
+ result = PHI_RESULT (phi);
+
+ /* This transformation is only valid for order comparisons. Record which
+ operand is smaller/larger if the result of the comparison is true. */
+ if (cmp == LT_EXPR || cmp == LE_EXPR)
+ {
+ smaller = TREE_OPERAND (cond, 0);
+ larger = TREE_OPERAND (cond, 1);
+ }
+ else if (cmp == GT_EXPR || cmp == GE_EXPR)
+ {
+ smaller = TREE_OPERAND (cond, 1);
+ larger = TREE_OPERAND (cond, 0);
+ }
+ else
+ return false;
+
+ /* 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);
+
+ if (true_edge == e0)
+ {
+ gcc_assert (false_edge == e1);
+ arg_true = arg0;
+ arg_false = arg1;
+ }
+ else
+ {
+ gcc_assert (false_edge == e0);
+ gcc_assert (true_edge == e1);
+ arg_true = arg1;
+ arg_false = arg0;
+ }
+
+ if (empty_block_p (middle_bb))
+ {
+ if (operand_equal_for_phi_arg_p (arg_true, smaller)
+ && operand_equal_for_phi_arg_p (arg_false, larger))
+ {
+ /* Case
+
+ if (smaller < larger)
+ rslt = smaller;
+ else
+ rslt = larger; */
+ minmax = MIN_EXPR;
+ }
+ else if (operand_equal_for_phi_arg_p (arg_false, smaller)
+ && operand_equal_for_phi_arg_p (arg_true, larger))
+ minmax = MAX_EXPR;
+ else
+ return false;
+ }
+ else
+ {
+ /* 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); */
+
+ tree assign = last_and_only_stmt (middle_bb);
+ tree lhs, rhs, op0, op1, bound;
+
+ if (!assign
+ || TREE_CODE (assign) != MODIFY_EXPR)
+ return false;
+
+ lhs = TREE_OPERAND (assign, 0);
+ rhs = TREE_OPERAND (assign, 1);
+ ass_code = TREE_CODE (rhs);
+ if (ass_code != MAX_EXPR && ass_code != MIN_EXPR)
+ return false;
+ op0 = TREE_OPERAND (rhs, 0);
+ op1 = TREE_OPERAND (rhs, 1);
+
+ 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))
+ {
+ /* 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))
+ bound = op1;
+ else if (operand_equal_for_phi_arg_p (op1, smaller))
+ bound = op0;
+ else
+ return false;
+
+ /* We need BOUND <= LARGER. */
+ if (!integer_nonzerop (fold (build2 (LE_EXPR, boolean_type_node,
+ bound, larger))))
+ return false;
+ }
+ else if (operand_equal_for_phi_arg_p (arg_false, 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))
+ 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 (GE_EXPR, boolean_type_node,
+ bound, smaller))))
+ 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))
+ {
+ /* 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))
+ bound = op1;
+ else if (operand_equal_for_phi_arg_p (op1, smaller))
+ bound = op0;
+ else
+ return false;
+
+ /* We need BOUND >= LARGER. */
+ if (!integer_nonzerop (fold (build2 (GE_EXPR, boolean_type_node,
+ bound, larger))))
+ return false;
+ }
+ else if (operand_equal_for_phi_arg_p (arg_true, 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, smaller))))
+ return false;
+ }
+ else
+ return false;
+ }
+
+ /* Move the statement from the middle block. */
+ bsi = bsi_last (cond_bb);
+ bsi_from = bsi_last (middle_bb);
+ bsi_move_before (&bsi_from, &bsi);
+ }
+
+ /* Emit the statement to compute min/max. */
+ result = duplicate_ssa_name (PHI_RESULT (phi), NULL);
+ new = build2 (MODIFY_EXPR, type, result,
+ build2 (minmax, type, arg0, arg1));
+ SSA_NAME_DEF_STMT (result) = new;
+ bsi = bsi_last (cond_bb);
+ bsi_insert_before (&bsi, new, BSI_NEW_STMT);
+
+ replace_phi_edge_with_variable (cond_bb, phi_bb, e1, phi, result);
+ return true;
+ }
+
/* The function absolute_replacement does the main work of doing the absolute
replacement. Return true if the replacement is done. Otherwise return
false.
*************** abs_replacement (basic_block cond_bb, ba
*** 503,511 ****
tree new, cond;
block_stmt_iterator bsi;
edge true_edge, false_edge;
! tree assign = NULL;
edge e;
! tree rhs = NULL, lhs = NULL;
bool negate;
enum tree_code cond_code;
--- 833,841 ----
tree new, cond;
block_stmt_iterator bsi;
edge true_edge, false_edge;
! tree assign;
edge e;
! tree rhs, lhs;
bool negate;
enum tree_code cond_code;
*************** abs_replacement (basic_block cond_bb, ba
*** 516,572 ****
/* OTHER_BLOCK must have only one executable statement which must have the
form arg0 = -arg1 or arg1 = -arg0. */
- bsi = bsi_start (middle_bb);
- while (!bsi_end_p (bsi))
- {
- tree stmt = bsi_stmt (bsi);
-
- /* Empty statements and labels are uninteresting. */
- if (TREE_CODE (stmt) == LABEL_EXPR
- || IS_EMPTY_STMT (stmt))
- {
- bsi_next (&bsi);
- continue;
- }
-
- /* If we found the assignment, but it was not the only executable
- statement in OTHER_BLOCK, then we can not optimize. */
- if (assign)
- return false;
-
- /* If we got here, then we have found the first executable statement
- in OTHER_BLOCK. If it is anything other than arg = -arg1 or
- arg1 = -arg0, then we can not optimize. */
- if (TREE_CODE (stmt) == MODIFY_EXPR)
- {
- lhs = TREE_OPERAND (stmt, 0);
- rhs = TREE_OPERAND (stmt, 1);
-
- if (TREE_CODE (rhs) == NEGATE_EXPR)
- {
- rhs = TREE_OPERAND (rhs, 0);
-
- /* The assignment has to be arg0 = -arg1 or arg1 = -arg0. */
- if ((lhs == arg0 && rhs == arg1)
- || (lhs == arg1 && rhs == arg0))
- {
- assign = stmt;
- bsi_next (&bsi);
- }
- else
- return false;
- }
- else
- return false;
- }
- else
- return false;
- }
/* If we did not find the proper negation assignment, then we can not
optimize. */
if (assign == NULL)
return false;
cond = COND_EXPR_COND (last_stmt (cond_bb));
result = PHI_RESULT (phi);
--- 846,876 ----
/* OTHER_BLOCK must have only one executable statement which must have the
form arg0 = -arg1 or arg1 = -arg0. */
+ assign = last_and_only_stmt (middle_bb);
/* If we did not find the proper negation assignment, then we can not
optimize. */
if (assign == NULL)
return false;
+
+ /* If we got here, then we have found the only executable statement
+ in OTHER_BLOCK. If it is anything other than arg = -arg1 or
+ arg1 = -arg0, then we can not optimize. */
+ if (TREE_CODE (assign) != MODIFY_EXPR)
+ return false;
+
+ lhs = TREE_OPERAND (assign, 0);
+ rhs = TREE_OPERAND (assign, 1);
+
+ if (TREE_CODE (rhs) != NEGATE_EXPR)
+ return false;
+
+ rhs = TREE_OPERAND (rhs, 0);
+
+ /* The assignment has to be arg0 = -arg1 or arg1 = -arg0. */
+ if (!(lhs == arg0 && rhs == arg1)
+ && !(lhs == arg1 && rhs == arg0))
+ return false;
cond = COND_EXPR_COND (last_stmt (cond_bb));
result = PHI_RESULT (phi);
*************** abs_replacement (basic_block cond_bb, ba
*** 613,620 ****
lhs = result;
/* Build the modify expression with abs expression. */
! new = build (MODIFY_EXPR, TREE_TYPE (lhs),
! lhs, build1 (ABS_EXPR, TREE_TYPE (lhs), rhs));
bsi = bsi_last (cond_bb);
bsi_insert_before (&bsi, new, BSI_NEW_STMT);
--- 917,924 ----
lhs = result;
/* Build the modify expression with abs expression. */
! new = build2 (MODIFY_EXPR, TREE_TYPE (lhs),
! lhs, build1 (ABS_EXPR, TREE_TYPE (lhs), rhs));
bsi = bsi_last (cond_bb);
bsi_insert_before (&bsi, new, BSI_NEW_STMT);
*************** abs_replacement (basic_block cond_bb, ba
*** 624,631 ****
/* Get the right BSI. We want to insert after the recently
added ABS_EXPR statement (which we know is the first statement
in the block. */
! new = build (MODIFY_EXPR, TREE_TYPE (result),
! result, build1 (NEGATE_EXPR, TREE_TYPE (lhs), lhs));
bsi_insert_after (&bsi, new, BSI_NEW_STMT);
}
--- 928,935 ----
/* Get the right BSI. We want to insert after the recently
added ABS_EXPR statement (which we know is the first statement
in the block. */
! new = build2 (MODIFY_EXPR, TREE_TYPE (result),
! result, build1 (NEGATE_EXPR, TREE_TYPE (lhs), lhs));
bsi_insert_after (&bsi, new, BSI_NEW_STMT);
}
Index: testsuite/gcc.dg/tree-ssa/phi-opt-5.c
===================================================================
RCS file: testsuite/gcc.dg/tree-ssa/phi-opt-5.c
diff -N testsuite/gcc.dg/tree-ssa/phi-opt-5.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gcc.dg/tree-ssa/phi-opt-5.c 10 Mar 2005 23:48:05 -0000
***************
*** 0 ****
--- 1,58 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O1 -ffinite-math-only -fdump-tree-phiopt1" } */
+
+ float repl1 (float varx)
+ {
+ if (varx < 0.0)
+ return 0.0;
+ else if (varx > 1.0)
+ return 1.0;
+ else
+ return varx;
+ }
+
+ /* Should be turned to
+
+ varx_4 = MIN_EXPR <1.0e+0, varx_2>;
+ varx_5 = MAX_EXPR <varx_4, 0.0>; */
+
+ /* { dg-final { scan-tree-dump "varx.*MIN_EXPR.*1\\.0" "phiopt1"} } */
+ /* { dg-final { scan-tree-dump "varx.*MAX_EXPR.*0\\.0" "phiopt1"} } */
+
+ float repl2 (float vary)
+ {
+ if (vary > 1.0)
+ return 1.0;
+ else if (vary < 0.0)
+ return 0.0;
+ else
+ return vary;
+ }
+
+ /* Should be turned to
+
+ vary_4 = MAX_EXPR <0.0, vary_2>;
+ vary_5 = MIN_EXPR <vary_4, 1.0e+0>; */
+
+ /* { dg-final { scan-tree-dump "vary.*MAX_EXPR.*0\\.0" "phiopt1"} } */
+ /* { dg-final { scan-tree-dump "vary.*MIN_EXPR.*1\\.0" "phiopt1"} } */
+
+ float repl3 (float varz, float vara, float varb)
+ {
+ if (varz > vara)
+ return vara;
+ else if (varz < varb)
+ return varb;
+ else
+ return varz;
+ }
+
+ /* Should be turned to
+
+ if (varz_2 > vara_3) goto <L4>; else goto <L1>;
+
+ <L1>:;
+ vara_6 = MAX_EXPR <varb_5, varz_2>; */
+
+ /* { dg-final { scan-tree-dump "if .*varz" "phiopt1"} } */
+ /* { dg-final { scan-tree-dump "vara.*MAX_EXPR" "phiopt1"} } */