summaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-phiopt.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-ssa-phiopt.c')
-rw-r--r--gcc/tree-ssa-phiopt.c463
1 files changed, 387 insertions, 76 deletions
diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c
index 6943c1732c1..3eedf9974e4 100644
--- a/gcc/tree-ssa-phiopt.c
+++ b/gcc/tree-ssa-phiopt.c
@@ -41,10 +41,13 @@ static bool conditional_replacement (basic_block, basic_block, basic_block,
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
@@ -102,6 +105,21 @@ static void replace_phi_edge_with_variable (basic_block, basic_block, edge,
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. */
@@ -110,15 +128,28 @@ static void
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;
- /* 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. */
@@ -174,25 +205,80 @@ tree_ssa_phiopt (void)
/* 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);
- /* We know something is wrong if we cannot find the edges in the PHI
- node. */
- gcc_assert (arg0 != NULL && arg1 != NULL);
+ /* 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))
- {
- }
+ /* 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;
+ sbitmap visited = sbitmap_alloc (last_basic_block + 2);
+
+#define MARK_VISITED(BB) (SET_BIT (visited, (BB)->index + 2))
+#define VISITED_P(BB) (TEST_BIT (visited, (BB)->index + 2))
+
+ 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
@@ -324,11 +410,11 @@ conditional_replacement (basic_block cond_bb, basic_block middle_bb,
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 (MODIFY_EXPR, TREE_TYPE (old_result), new_var, new1);
+ new1 = build2 (MODIFY_EXPR, TREE_TYPE (old_result), new_var, new1);
bsi_insert_after (&bsi, new1, BSI_NEW_STMT);
}
@@ -357,7 +443,7 @@ conditional_replacement (basic_block cond_bb, basic_block middle_bb,
|| (e1 == true_edge && integer_onep (arg1))
|| (e1 == false_edge && integer_zerop (arg1)))
{
- new = build (MODIFY_EXPR, TREE_TYPE (new_var1), new_var1, cond);
+ new = build2 (MODIFY_EXPR, TREE_TYPE (new_var1), new_var1, cond);
}
else
{
@@ -379,7 +465,7 @@ conditional_replacement (basic_block cond_bb, basic_block middle_bb,
{
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);
+ 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);
}
@@ -391,7 +477,7 @@ conditional_replacement (basic_block cond_bb, basic_block middle_bb,
return false;
}
- new = build (MODIFY_EXPR, TREE_TYPE (new_var1), new_var1, cond);
+ new = build2 (MODIFY_EXPR, TREE_TYPE (new_var1), new_var1, cond);
}
bsi_insert_after (&bsi, new, BSI_NEW_STMT);
@@ -482,6 +568,257 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
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.
@@ -497,9 +834,9 @@ abs_replacement (basic_block cond_bb, basic_block middle_bb,
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;
@@ -510,57 +847,31 @@ abs_replacement (basic_block cond_bb, basic_block middle_bb,
/* 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) != 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);
@@ -607,8 +918,8 @@ abs_replacement (basic_block cond_bb, basic_block middle_bb,
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 = 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);
@@ -618,8 +929,8 @@ abs_replacement (basic_block cond_bb, basic_block middle_bb,
/* 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 = build2 (MODIFY_EXPR, TREE_TYPE (result),
+ result, build1 (NEGATE_EXPR, TREE_TYPE (lhs), lhs));
bsi_insert_after (&bsi, new, BSI_NEW_STMT);
}