/* Optimization of PHI nodes by converting them into straightline code.
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GCC.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
-#include "errors.h"
#include "ggc.h"
#include "tree.h"
#include "rtl.h"
#include "tree-dump.h"
#include "langhooks.h"
-static void tree_ssa_phiopt (void);
-static bool conditional_replacement (basic_block, basic_block, basic_block,
+static unsigned int tree_ssa_phiopt (void);
+static bool conditional_replacement (basic_block, basic_block,
edge, edge, tree, tree, tree);
-static bool value_replacement (basic_block, basic_block, basic_block,
+static bool value_replacement (basic_block, basic_block,
edge, edge, tree, tree, tree);
-static bool abs_replacement (basic_block, basic_block, basic_block,
+static bool minmax_replacement (basic_block, basic_block,
+ edge, edge, tree, tree, tree);
+static bool abs_replacement (basic_block, basic_block,
edge, edge, tree, tree, tree);
-static void replace_phi_edge_with_variable (basic_block, basic_block, edge,
- tree, tree);
+static void replace_phi_edge_with_variable (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
- like:
+/* This pass tries to replaces an if-then-else block with an
+ assignment. We have four kinds of transformations. Some of these
+ transformations are also performed by the ifcvt RTL optimizer.
+
+ Conditional Replacement
+ -----------------------
+
+ This transformation, implemented in conditional_replacement,
+ replaces
bb0:
if (cond) goto bb2; else goto bb1;
bb1:
bb2:
- x = PHI (0 (bb1), 1 (bb0)
+ x = PHI <0 (bb1), 1 (bb0), ...>;
- We can rewrite that as:
+ with
bb0:
- bb1:
+ x' = cond;
+ goto bb2;
bb2:
- x = cond;
+ x = PHI <x' (bb0), ...>;
- bb1 will become unreachable and bb0 and bb2 will almost always
- be merged into a single block. This occurs often due to gimplification
- of conditionals.
+ We remove bb1 as it becomes unreachable. This occurs often due to
+ gimplification of conditionals.
- Also done is the following optimization:
+ Value Replacement
+ -----------------
+
+ This transformation, implemented in value_replacement, replaces
bb0:
- if (a != b) goto bb2; else goto bb1;
+ if (a != b) goto bb2; else goto bb1;
bb1:
bb2:
- x = PHI (a (bb1), b (bb0))
+ x = PHI <a (bb1), b (bb0), ...>;
- We can rewrite that as:
+ with
bb0:
- bb1:
bb2:
- x = b;
+ x = PHI <b (bb0), ...>;
+
+ This opportunity can sometimes occur as a result of other
+ optimizations.
- This can sometimes occur as a result of other optimizations. A
- similar transformation is done by the ifcvt RTL optimizer.
+ ABS Replacement
+ ---------------
- This pass also eliminates PHI nodes which are really absolute
- values. i.e. if we have something like:
+ This transformation, implemented in abs_replacement, replaces
bb0:
- if (a >= 0) goto bb2; else goto bb1;
+ if (a >= 0) goto bb2; else goto bb1;
bb1:
- x = -a;
+ x = -a;
bb2:
- x = PHI (x (bb1), a (bb0));
+ x = PHI <x (bb1), a (bb0), ...>;
- We can rewrite that as:
+ with
bb0:
+ x' = ABS_EXPR< a >;
+ bb2:
+ x = PHI <x' (bb0), ...>;
+
+ MIN/MAX Replacement
+ -------------------
+
+ This transformation, minmax_replacement replaces
+
+ bb0:
+ if (a <= b) goto bb2; else goto bb1;
bb1:
bb2:
- x = ABS_EXPR< a >;
+ x = PHI <b (bb1), a (bb0), ...>;
- 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. */
+ with
-static void
+ bb0:
+ x' = MIN_EXPR (a, b)
+ bb2:
+ x = PHI <x' (bb0), ...>;
+
+ A similar transformation is done for MAX_EXPR. */
+
+static unsigned int
tree_ssa_phiopt (void)
{
basic_block bb;
- bool removed_phis = false;
+ basic_block *bb_order;
+ unsigned n, i;
+ bool cfgchanged = false;
+
+ /* 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 - NUM_FIXED_BLOCKS;
- /* 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)
+ 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. */
continue;
/* If either bb1's succ or bb2 or bb2's succ is non NULL. */
- if (EDGE_COUNT (bb1->succs) < 1
+ if (EDGE_COUNT (bb1->succs) == 0
|| bb2 == NULL
- || EDGE_COUNT (bb2->succs) < 1)
+ || EDGE_COUNT (bb2->succs) == 0)
continue;
/* Find the bb which is the fall through to the other. */
e1 = EDGE_SUCC (bb1, 0);
/* Make sure that bb1 is just a fall through. */
- if (EDGE_COUNT (bb1->succs) > 1
+ if (!single_succ_p (bb1)
|| (e1->flags & EDGE_FALLTHRU) == 0)
continue;
- /* Also make that bb1 only have one pred and it is bb. */
- if (EDGE_COUNT (bb1->preds) > 1
- || EDGE_PRED (bb1, 0)->src != bb)
+ /* Also make sure that bb1 only have one predecessor and that it
+ is bb. */
+ if (!single_pred_p (bb1)
+ || single_pred (bb1) != bb)
continue;
phi = phi_nodes (bb2);
/* 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;
+ 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);
+ arg0 = PHI_ARG_DEF_TREE (phi, e1->dest_idx);
+ arg1 = PHI_ARG_DEF_TREE (phi, e2->dest_idx);
+
+ /* Something is wrong if we cannot find the arguments 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, e1, e2, phi, arg0, arg1))
+ cfgchanged = true;
+ else if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
+ cfgchanged = true;
+ else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
+ cfgchanged = true;
+ else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
+ cfgchanged = true;
+ }
- /* We know something is wrong if we cannot find the edges in the PHI
- node. */
- gcc_assert (arg0 != NULL && arg1 != NULL);
+ free (bb_order);
+
+ /* If the CFG has changed, we should cleanup the CFG. */
+ return cfgchanged ? TODO_cleanup_cfg : 0;
+}
- /* 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;
- }
+/* 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 = XNEWVEC (basic_block, n_basic_blocks);
+ unsigned n = n_basic_blocks - NUM_FIXED_BLOCKS;
+ unsigned np, i;
+ sbitmap visited = sbitmap_alloc (last_basic_block);
+
+#define MARK_VISITED(BB) (SET_BIT (visited, (BB)->index))
+#define VISITED_P(BB) (TEST_BIT (visited, (BB)->index))
+
+ sbitmap_zero (visited);
+
+ MARK_VISITED (ENTRY_BLOCK_PTR);
+ FOR_EACH_BB (x)
+ {
+ if (VISITED_P (x))
+ 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;
+ single_pred_p (y) && !VISITED_P (single_pred (y));
+ y = single_pred (y))
+ np++;
+ for (y = x, i = n - np;
+ single_pred_p (y) && !VISITED_P (single_pred (y));
+ y = single_pred (y), i++)
+ {
+ order[i] = y;
+ MARK_VISITED (y);
}
+ order[i] = y;
+ MARK_VISITED (y);
+
+ gcc_assert (i == n - 1);
+ n -= np;
}
+
+ sbitmap_free (visited);
+ gcc_assert (n == 0);
+ return order;
+
+#undef MARK_VISITED
+#undef VISITED_P
}
/* Return TRUE if block BB has no executable statements, otherwise return
return true;
}
-/* Replace PHI node element whoes edge is E in block BB with variable NEW.
+/* Replace PHI node element whose edge is E in block BB with variable NEW.
Remove the edge from COND_BLOCK which does not lead to BB (COND_BLOCK
is known to have two edges, one of which must reach BB). */
static void
-replace_phi_edge_with_variable (basic_block cond_block, basic_block bb,
+replace_phi_edge_with_variable (basic_block cond_block,
edge e, tree phi, tree new)
{
+ basic_block bb = bb_for_stmt (phi);
basic_block block_to_remove;
block_stmt_iterator bsi;
/* Change the PHI argument to new. */
- PHI_ARG_DEF_TREE (phi, e->dest_idx) = new;
+ SET_USE (PHI_ARG_DEF_PTR (phi, e->dest_idx), new);
/* Remove the empty basic block. */
if (EDGE_SUCC (cond_block, 0)->dest == bb)
{
EDGE_SUCC (cond_block, 0)->flags |= EDGE_FALLTHRU;
EDGE_SUCC (cond_block, 0)->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
+ EDGE_SUCC (cond_block, 0)->probability = REG_BR_PROB_BASE;
+ EDGE_SUCC (cond_block, 0)->count += EDGE_SUCC (cond_block, 1)->count;
block_to_remove = EDGE_SUCC (cond_block, 1)->dest;
}
EDGE_SUCC (cond_block, 1)->flags |= EDGE_FALLTHRU;
EDGE_SUCC (cond_block, 1)->flags
&= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
+ EDGE_SUCC (cond_block, 1)->probability = REG_BR_PROB_BASE;
+ EDGE_SUCC (cond_block, 1)->count += EDGE_SUCC (cond_block, 0)->count;
block_to_remove = EDGE_SUCC (cond_block, 0)->dest;
}
/* Eliminate the COND_EXPR at the end of COND_BLOCK. */
bsi = bsi_last (cond_block);
- bsi_remove (&bsi);
+ bsi_remove (&bsi, true);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
static bool
conditional_replacement (basic_block cond_bb, basic_block middle_bb,
- basic_block phi_bb, edge e0, edge e1, tree phi,
+ edge e0, edge e1, tree phi,
tree arg0, tree arg1)
{
tree result;
if (TREE_CODE (cond) != SSA_NAME
&& !lang_hooks.types_compatible_p (TREE_TYPE (cond), TREE_TYPE (result)))
{
- new_var = make_rename_temp (TREE_TYPE (cond), NULL);
+ tree tmp;
+
+ if (!COMPARISON_CLASS_P (cond))
+ return false;
+
+ tmp = create_tmp_var (TREE_TYPE (cond), NULL);
+ add_referenced_var (tmp);
+ new_var = make_ssa_name (tmp, NULL);
old_result = cond;
cond = new_var;
}
if (old_result)
{
tree new1;
- 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 = build2 (TREE_CODE (old_result), TREE_TYPE (old_result),
+ TREE_OPERAND (old_result, 0),
+ TREE_OPERAND (old_result, 1));
+
+ new1 = build_gimple_modify_stmt (new_var, new1);
+ SSA_NAME_DEF_STMT (new_var) = new1;
- new1 = build (MODIFY_EXPR, TREE_TYPE (old_result), new_var, new1);
bsi_insert_after (&bsi, new1, BSI_NEW_STMT);
}
|| (e1 == true_edge && integer_onep (arg1))
|| (e1 == false_edge && integer_zerop (arg1)))
{
- new = build (MODIFY_EXPR, TREE_TYPE (new_var1), new_var1, cond);
+ new = build_gimple_modify_stmt (new_var1, cond);
}
else
{
tree cond1 = invert_truthvalue (cond);
cond = cond1;
+
/* If what we get back is a conditional expression, there is no
way that it can be gimple. */
if (TREE_CODE (cond) == COND_EXPR)
return false;
}
+ /* If COND is not something we can expect to be reducible to a GIMPLE
+ condition, return early. */
+ if (is_gimple_cast (cond))
+ cond1 = TREE_OPERAND (cond, 0);
+ if (TREE_CODE (cond1) == TRUTH_NOT_EXPR
+ && !is_gimple_val (TREE_OPERAND (cond1, 0)))
+ {
+ release_ssa_name (new_var1);
+ return false;
+ }
+
/* If what we get back is not gimple try to create it as gimple by
using a temporary variable. */
if (is_gimple_cast (cond)
&& !is_gimple_val (TREE_OPERAND (cond, 0)))
{
- 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);
- }
+ tree op0, tmp, cond_tmp;
- if (TREE_CODE (cond) == TRUTH_NOT_EXPR
- && !is_gimple_val (TREE_OPERAND (cond, 0)))
- {
- release_ssa_name (new_var1);
- return false;
+ /* Only "real" casts are OK here, not everything that is
+ acceptable to is_gimple_cast. Make sure we don't do
+ anything stupid here. */
+ gcc_assert (TREE_CODE (cond) == NOP_EXPR
+ || TREE_CODE (cond) == CONVERT_EXPR);
+
+ op0 = TREE_OPERAND (cond, 0);
+ tmp = create_tmp_var (TREE_TYPE (op0), NULL);
+ add_referenced_var (tmp);
+ cond_tmp = make_ssa_name (tmp, NULL);
+ new = build_gimple_modify_stmt (cond_tmp, op0);
+ SSA_NAME_DEF_STMT (cond_tmp) = new;
+
+ bsi_insert_after (&bsi, new, BSI_NEW_STMT);
+ cond = fold_convert (TREE_TYPE (result), cond_tmp);
}
- new = build (MODIFY_EXPR, TREE_TYPE (new_var1), new_var1, cond);
+ new = build_gimple_modify_stmt (new_var1, cond);
}
bsi_insert_after (&bsi, new, BSI_NEW_STMT);
SSA_NAME_DEF_STMT (new_var1) = new;
- replace_phi_edge_with_variable (cond_bb, phi_bb, e1, phi, new_var1);
+ replace_phi_edge_with_variable (cond_bb, e1, phi, new_var1);
/* Note that we optimized this PHI. */
return true;
static bool
value_replacement (basic_block cond_bb, basic_block middle_bb,
- basic_block phi_bb, edge e0, edge e1, tree phi,
+ edge e0, edge e1, tree phi,
tree arg0, tree arg1)
{
- tree result;
tree cond;
edge true_edge, false_edge;
return false;
cond = COND_EXPR_COND (last_stmt (cond_bb));
- result = PHI_RESULT (phi);
/* This transformation is only valid for equality comparisons. */
if (TREE_CODE (cond) != NE_EXPR && TREE_CODE (cond) != EQ_EXPR)
edge from OTHER_BLOCK which reaches BB and represents the desired
path from COND_BLOCK. */
if (e->dest == middle_bb)
- e = EDGE_SUCC (e->dest, 0);
+ e = single_succ_edge (e->dest);
/* Now we know the incoming edge to BB that has the argument for the
RHS of our new assignment statement. */
else
arg = arg1;
- replace_phi_edge_with_variable (cond_bb, phi_bb, e1, phi, arg);
+ replace_phi_edge_with_variable (cond_bb, e1, phi, arg);
/* Note that we optimized this PHI. */
return true;
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,
+ 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) != GIMPLE_MODIFY_STMT)
+ return false;
+
+ lhs = GIMPLE_STMT_OPERAND (assign, 0);
+ rhs = GIMPLE_STMT_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 = build_gimple_modify_stmt (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, 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.
static bool
abs_replacement (basic_block cond_bb, basic_block middle_bb,
- basic_block phi_bb, edge e0 ATTRIBUTE_UNUSED, edge e1,
+ edge e0 ATTRIBUTE_UNUSED, edge e1,
tree phi, tree arg0, tree arg1)
{
tree result;
tree new, cond;
block_stmt_iterator bsi;
edge true_edge, false_edge;
- tree assign = NULL;
+ tree assign;
edge e;
- tree rhs = NULL, lhs = NULL;
+ tree rhs, lhs;
bool negate;
enum tree_code cond_code;
/* 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;
- }
+ 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) != GIMPLE_MODIFY_STMT)
+ return false;
+
+ lhs = GIMPLE_STMT_OPERAND (assign, 0);
+ rhs = GIMPLE_STMT_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);
result = duplicate_ssa_name (result, NULL);
if (negate)
- lhs = make_rename_temp (TREE_TYPE (result), NULL);
+ {
+ tree tmp = create_tmp_var (TREE_TYPE (result), NULL);
+ add_referenced_var (tmp);
+ lhs = make_ssa_name (tmp, NULL);
+ }
else
lhs = result;
/* Build the modify expression with abs expression. */
- new = build (MODIFY_EXPR, TREE_TYPE (lhs),
- lhs, build1 (ABS_EXPR, TREE_TYPE (lhs), rhs));
+ new = build_gimple_modify_stmt (lhs,
+ build1 (ABS_EXPR, TREE_TYPE (lhs), rhs));
+ SSA_NAME_DEF_STMT (lhs) = new;
bsi = bsi_last (cond_bb);
bsi_insert_before (&bsi, new, BSI_NEW_STMT);
/* 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));
+ new = build_gimple_modify_stmt (result,
+ build1 (NEGATE_EXPR, TREE_TYPE (lhs),
+ lhs));
+ SSA_NAME_DEF_STMT (result) = new;
bsi_insert_after (&bsi, new, BSI_NEW_STMT);
}
- SSA_NAME_DEF_STMT (result) = new;
- replace_phi_edge_with_variable (cond_bb, phi_bb, e1, phi, result);
+ replace_phi_edge_with_variable (cond_bb, e1, phi, result);
/* Note that we optimized this PHI. */
return true;
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_cleanup_cfg | TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */
- | TODO_verify_ssa | TODO_rename_vars
- | TODO_verify_flow | TODO_verify_stmts,
+ TODO_dump_func
+ | TODO_ggc_collect
+ | TODO_verify_ssa
+ | TODO_verify_flow
+ | TODO_verify_stmts, /* todo_flags_finish */
0 /* letter */
};