Commit bec44647 by Kazu Hirata Committed by Kazu Hirata

tree-ssa-forwprop.c (vars, [...]): Remove.

	* tree-ssa-forwprop.c (vars,
	record_single_argument_cond_exprs,
	substitute_single_use_vars): Remove.
	(forward_propagate_into_cond_1, forward_propagate_into_cond):
	New.
	(tree_ssa_forward_propagate_single_use_vars): Call
	forward_propagate_into_cond for each COND_EXPR.

From-SVN: r98072
parent 8450a170
...@@ -4,6 +4,14 @@ ...@@ -4,6 +4,14 @@
* cgraphunit.c (INSNS_PER_CALL): Remove. * cgraphunit.c (INSNS_PER_CALL): Remove.
* tree-ssa-forwprop.c (vars,
record_single_argument_cond_exprs,
substitute_single_use_vars): Remove.
(forward_propagate_into_cond_1, forward_propagate_into_cond):
New.
(tree_ssa_forward_propagate_single_use_vars): Call
forward_propagate_into_cond for each COND_EXPR.
2005-04-12 Richard Henderson <rth@redhat.com> 2005-04-12 Richard Henderson <rth@redhat.com>
* config/i386/i386.c (ix86_prepare_sse_fp_compare_args): Split ... * config/i386/i386.c (ix86_prepare_sse_fp_compare_args): Split ...
......
...@@ -109,64 +109,30 @@ Boston, MA 02111-1307, USA. */ ...@@ -109,64 +109,30 @@ Boston, MA 02111-1307, USA. */
This will (of course) be extended as other needs arise. */ This will (of course) be extended as other needs arise. */
/* Bitmap of variables for which we want immediate uses. This is set /* Forward propagate a single-use variable into COND once. Return a
by record_single_argument_cond_exprs and tested in need_imm_uses_for. */ new condition if successful. Return NULL_TREE otherwise. */
static bitmap vars;
static void tree_ssa_forward_propagate_single_use_vars (void);
static void record_single_argument_cond_exprs (varray_type,
varray_type *,
bitmap);
static void substitute_single_use_vars (varray_type *, varray_type);
/* Find all COND_EXPRs with a condition that is a naked SSA_NAME or
an equality comparison against a constant.
Record the identified COND_EXPRs and the SSA_NAME used in the COND_EXPR
into a virtual array, which is returned to the caller. Also record
into VARS that we will need immediate uses for the identified SSA_NAME.
The more uninteresting COND_EXPRs and associated SSA_NAMEs we can
filter out here, the faster this pass will run since its runtime is
dominated by the time to build immediate uses. */
static void
record_single_argument_cond_exprs (varray_type cond_worklist,
varray_type *vars_worklist,
bitmap vars)
static tree
forward_propagate_into_cond_1 (tree cond, tree *test_var_p)
{ {
/* The first pass over the blocks gathers the set of variables we need tree new_cond = NULL_TREE;
immediate uses for as well as the set of interesting COND_EXPRs.
A simpler implementation may be appropriate if/when we have a lower
overhead means of getting immediate use information. */
while (VARRAY_ACTIVE_SIZE (cond_worklist) > 0)
{
tree last = VARRAY_TOP_TREE (cond_worklist);
VARRAY_POP (cond_worklist);
/* See if this block ends in a COND_EXPR. */
if (last && TREE_CODE (last) == COND_EXPR)
{
tree cond = COND_EXPR_COND (last);
enum tree_code cond_code = TREE_CODE (cond); enum tree_code cond_code = TREE_CODE (cond);
tree test_var = NULL_TREE;
tree def;
tree def_rhs;
/* If the condition is a lone variable or an equality test of /* If the condition is not a lone variable or an equality test of an
an SSA_NAME against an integral constant, then we may have an SSA_NAME against an integral constant, then we do not have an
optimizable case. optimizable case.
Note these conditions also ensure the COND_EXPR has no Note these conditions also ensure the COND_EXPR has no
virtual operands or other side effects. */ virtual operands or other side effects. */
if (cond_code == SSA_NAME if (cond_code != SSA_NAME
|| ((cond_code == EQ_EXPR || cond_code == NE_EXPR) && !((cond_code == EQ_EXPR || cond_code == NE_EXPR)
&& TREE_CODE (TREE_OPERAND (cond, 0)) == SSA_NAME && TREE_CODE (TREE_OPERAND (cond, 0)) == SSA_NAME
&& CONSTANT_CLASS_P (TREE_OPERAND (cond, 1)) && CONSTANT_CLASS_P (TREE_OPERAND (cond, 1))
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (cond, 1))))) && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (cond, 1)))))
{ return NULL_TREE;
tree def;
tree test_var;
/* Extract the single variable used in the test into TEST_VAR. */ /* Extract the single variable used in the test into TEST_VAR. */
if (cond_code == SSA_NAME) if (cond_code == SSA_NAME)
...@@ -174,17 +140,13 @@ record_single_argument_cond_exprs (varray_type cond_worklist, ...@@ -174,17 +140,13 @@ record_single_argument_cond_exprs (varray_type cond_worklist,
else else
test_var = TREE_OPERAND (cond, 0); test_var = TREE_OPERAND (cond, 0);
/* If we have already recorded this SSA_NAME as interesting, /* Now get the defining statement for TEST_VAR. Skip this case if
do not do so again. */ it's not defined by some MODIFY_EXPR. */
if (bitmap_bit_p (vars, SSA_NAME_VERSION (test_var)))
continue;
/* Now get the defining statement for TEST_VAR and see if it
something we are interested in. */
def = SSA_NAME_DEF_STMT (test_var); def = SSA_NAME_DEF_STMT (test_var);
if (TREE_CODE (def) == MODIFY_EXPR) if (TREE_CODE (def) != MODIFY_EXPR)
{ return NULL_TREE;
tree def_rhs = TREE_OPERAND (def, 1);
def_rhs = TREE_OPERAND (def, 1);
/* If TEST_VAR is set by adding or subtracting a constant /* If TEST_VAR is set by adding or subtracting a constant
from an SSA_NAME, then it is interesting to us as we from an SSA_NAME, then it is interesting to us as we
...@@ -201,12 +163,33 @@ record_single_argument_cond_exprs (varray_type cond_worklist, ...@@ -201,12 +163,33 @@ record_single_argument_cond_exprs (varray_type cond_worklist,
if (TREE_CODE (op0) != SSA_NAME if (TREE_CODE (op0) != SSA_NAME
|| !CONSTANT_CLASS_P (op1) || !CONSTANT_CLASS_P (op1)
|| !INTEGRAL_TYPE_P (TREE_TYPE (op1))) || !INTEGRAL_TYPE_P (TREE_TYPE (op1)))
continue; return NULL_TREE;
/* Don't propagate if the first operand occurs in /* Don't propagate if the first operand occurs in
an abnormal PHI. */ an abnormal PHI. */
if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op0)) if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op0))
continue; return NULL_TREE;
if (has_single_use (test_var))
{
tree op0 = TREE_OPERAND (def_rhs, 0);
tree op1 = TREE_OPERAND (def_rhs, 1);
enum tree_code new_code;
tree t;
/* If the variable was defined via X + C, then we must
subtract C from the constant in the conditional.
Otherwise we add C to the constant in the
conditional. The result must fold into a valid
gimple operand to be optimizable. */
new_code = (TREE_CODE (def_rhs) == PLUS_EXPR
? MINUS_EXPR : PLUS_EXPR);
t = int_const_binop (new_code, TREE_OPERAND (cond, 1), op1, 0);
if (!is_gimple_val (t))
return NULL_TREE;
new_cond = build (cond_code, boolean_type_node, op0, t);
}
} }
/* These cases require comparisons of a naked SSA_NAME or /* These cases require comparisons of a naked SSA_NAME or
...@@ -229,37 +212,78 @@ record_single_argument_cond_exprs (varray_type cond_worklist, ...@@ -229,37 +212,78 @@ record_single_argument_cond_exprs (varray_type cond_worklist,
&& !is_gimple_min_invariant (op0)) && !is_gimple_min_invariant (op0))
|| (TREE_CODE (op1) != SSA_NAME || (TREE_CODE (op1) != SSA_NAME
&& !is_gimple_min_invariant (op1))) && !is_gimple_min_invariant (op1)))
continue; return NULL_TREE;
/* Don't propagate if the first operand occurs in /* Don't propagate if the first operand occurs in
an abnormal PHI. */ an abnormal PHI. */
if (TREE_CODE (op0) == SSA_NAME if (TREE_CODE (op0) == SSA_NAME
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op0)) && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op0))
continue; return NULL_TREE;
/* Don't propagate if the second operand occurs in /* Don't propagate if the second operand occurs in
an abnormal PHI. */ an abnormal PHI. */
if (TREE_CODE (op1) == SSA_NAME if (TREE_CODE (op1) == SSA_NAME
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op1)) && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op1))
continue; return NULL_TREE;
if (has_single_use (test_var))
{
/* TEST_VAR was set from a relational operator. */
tree op0 = TREE_OPERAND (def_rhs, 0);
tree op1 = TREE_OPERAND (def_rhs, 1);
new_cond = build (TREE_CODE (def_rhs),
boolean_type_node, op0, op1);
/* Invert the conditional if necessary. */
if ((cond_code == EQ_EXPR
&& integer_zerop (TREE_OPERAND (cond, 1)))
|| (cond_code == NE_EXPR
&& integer_onep (TREE_OPERAND (cond, 1))))
{
new_cond = invert_truthvalue (new_cond);
/* If we did not get a simple relational
expression or bare SSA_NAME, then we can
not optimize this case. */
if (!COMPARISON_CLASS_P (new_cond)
&& TREE_CODE (new_cond) != SSA_NAME)
new_cond = NULL_TREE;
}
}
} }
/* If TEST_VAR is set from a TRUTH_NOT_EXPR, then it /* If TEST_VAR is set from a TRUTH_NOT_EXPR, then it
is interesting. */ is interesting. */
else if (TREE_CODE (def_rhs) == TRUTH_NOT_EXPR) else if (TREE_CODE (def_rhs) == TRUTH_NOT_EXPR)
{ {
enum tree_code new_code;
def_rhs = TREE_OPERAND (def_rhs, 0); def_rhs = TREE_OPERAND (def_rhs, 0);
/* DEF_RHS must be an SSA_NAME or constant. */ /* DEF_RHS must be an SSA_NAME or constant. */
if (TREE_CODE (def_rhs) != SSA_NAME if (TREE_CODE (def_rhs) != SSA_NAME
&& !is_gimple_min_invariant (def_rhs)) && !is_gimple_min_invariant (def_rhs))
continue; return NULL_TREE;
/* Don't propagate if the operand occurs in /* Don't propagate if the operand occurs in
an abnormal PHI. */ an abnormal PHI. */
if (TREE_CODE (def_rhs) == SSA_NAME if (TREE_CODE (def_rhs) == SSA_NAME
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def_rhs)) && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def_rhs))
continue; return NULL_TREE;
if (cond_code == SSA_NAME
|| (cond_code == NE_EXPR
&& integer_zerop (TREE_OPERAND (cond, 1)))
|| (cond_code == EQ_EXPR
&& integer_onep (TREE_OPERAND (cond, 1))))
new_code = EQ_EXPR;
else
new_code = NE_EXPR;
new_cond = build2 (new_code, boolean_type_node, def_rhs,
fold_convert (TREE_TYPE (def_rhs),
integer_zero_node));
} }
/* If TEST_VAR was set from a cast of an integer type /* If TEST_VAR was set from a cast of an integer type
...@@ -280,148 +304,20 @@ record_single_argument_cond_exprs (varray_type cond_worklist, ...@@ -280,148 +304,20 @@ record_single_argument_cond_exprs (varray_type cond_worklist,
&& INTEGRAL_TYPE_P (outer_type))) && INTEGRAL_TYPE_P (outer_type)))
; ;
else else
continue; return NULL_TREE;
/* Don't propagate if the operand occurs in /* Don't propagate if the operand occurs in
an abnormal PHI. */ an abnormal PHI. */
if (TREE_CODE (TREE_OPERAND (def_rhs, 0)) == SSA_NAME if (TREE_CODE (TREE_OPERAND (def_rhs, 0)) == SSA_NAME
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND
(def_rhs, 0))) (def_rhs, 0)))
continue; return NULL_TREE;
}
else
continue;
}
else
continue;
/* All the tests passed, record TEST_VAR as interesting. */
VARRAY_PUSH_TREE (*vars_worklist, test_var);
bitmap_set_bit (vars, SSA_NAME_VERSION (test_var));
}
}
}
}
}
/* Given FORWPROP_DATA containing SSA_NAMEs which are used in COND_EXPRs
that we may be able to optimize, attempt to rewrite the condition
in each COND_EXPR to use the RHS of the statement which defines the
SSA_NAME used in the COND_EXPR. */
static void if (has_single_use (test_var))
substitute_single_use_vars (varray_type *cond_worklist,
varray_type vars_worklist)
{
use_operand_p use_p;
while (VARRAY_ACTIVE_SIZE (vars_worklist) > 0)
{ {
tree test_var = VARRAY_TOP_TREE (vars_worklist);
tree def_stmt = SSA_NAME_DEF_STMT (test_var);
tree def;
int num_uses, propagated_uses;
imm_use_iterator imm_iter;
VARRAY_POP (vars_worklist);
propagated_uses = 0;
num_uses = 0;
if (NUM_DEFS (STMT_DEF_OPS (def_stmt)) != 1)
continue;
def = DEF_OP (STMT_DEF_OPS (def_stmt), 0);
/* If TEST_VAR is used more than once and is not a boolean set
via TRUTH_NOT_EXPR with another SSA_NAME as its argument, then
we can not optimize. */
if (has_single_use (def)
|| (TREE_CODE (TREE_TYPE (test_var)) == BOOLEAN_TYPE
&& TREE_CODE (TREE_OPERAND (def_stmt, 1)) == TRUTH_NOT_EXPR
&& (TREE_CODE (TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0))
== SSA_NAME)))
;
else
continue;
/* Walk over each use and try to forward propagate the RHS of
DEF into the use. */
FOR_EACH_IMM_USE_SAFE (use_p, imm_iter, def)
{
tree cond_stmt;
tree cond;
enum tree_code cond_code;
tree def_rhs;
enum tree_code def_rhs_code;
tree new_cond;
cond_stmt = USE_STMT (use_p);
num_uses++;
/* For now we can only propagate into COND_EXPRs. */
if (TREE_CODE (cond_stmt) != COND_EXPR)
continue;
cond = COND_EXPR_COND (cond_stmt);
cond_code = TREE_CODE (cond);
def_rhs = TREE_OPERAND (def_stmt, 1);
def_rhs_code = TREE_CODE (def_rhs);
/* If the definition of the single use variable was from an
arithmetic operation, then we just need to adjust the
constant in the COND_EXPR_COND and update the variable tested. */
if (def_rhs_code == PLUS_EXPR || def_rhs_code == MINUS_EXPR)
{
tree op0 = TREE_OPERAND (def_rhs, 0);
tree op1 = TREE_OPERAND (def_rhs, 1);
enum tree_code new_code;
tree t;
/* If the variable was defined via X + C, then we must subtract
C from the constant in the conditional. Otherwise we add
C to the constant in the conditional. The result must fold
into a valid gimple operand to be optimizable. */
new_code = def_rhs_code == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR;
t = int_const_binop (new_code, TREE_OPERAND (cond, 1), op1, 0);
if (!is_gimple_val (t))
continue;
new_cond = build (cond_code, boolean_type_node, op0, t);
}
/* If the variable is defined by a conditional expression... */
else if (TREE_CODE_CLASS (def_rhs_code) == tcc_comparison)
{
/* TEST_VAR was set from a relational operator. */
tree op0 = TREE_OPERAND (def_rhs, 0);
tree op1 = TREE_OPERAND (def_rhs, 1);
new_cond = build (def_rhs_code, boolean_type_node, op0, op1);
/* Invert the conditional if necessary. */
if ((cond_code == EQ_EXPR
&& integer_zerop (TREE_OPERAND (cond, 1)))
|| (cond_code == NE_EXPR
&& integer_onep (TREE_OPERAND (cond, 1))))
{
new_cond = invert_truthvalue (new_cond);
/* If we did not get a simple relational expression or
bare SSA_NAME, then we can not optimize this case. */
if (!COMPARISON_CLASS_P (new_cond)
&& TREE_CODE (new_cond) != SSA_NAME)
continue;
}
}
else
{
bool invert = false;
enum tree_code new_code; enum tree_code new_code;
tree new_arg; tree new_arg;
/* TEST_VAR was set from a TRUTH_NOT_EXPR or a NOP_EXPR. */
if (def_rhs_code == TRUTH_NOT_EXPR)
invert = true;
if (cond_code == SSA_NAME if (cond_code == SSA_NAME
|| (cond_code == NE_EXPR || (cond_code == NE_EXPR
&& integer_zerop (TREE_OPERAND (cond, 1))) && integer_zerop (TREE_OPERAND (cond, 1)))
...@@ -431,14 +327,35 @@ substitute_single_use_vars (varray_type *cond_worklist, ...@@ -431,14 +327,35 @@ substitute_single_use_vars (varray_type *cond_worklist,
else else
new_code = EQ_EXPR; new_code = EQ_EXPR;
if (invert)
new_code = (new_code == EQ_EXPR ? NE_EXPR : EQ_EXPR);
new_arg = TREE_OPERAND (def_rhs, 0); new_arg = TREE_OPERAND (def_rhs, 0);
new_cond = build2 (new_code, boolean_type_node, new_arg, new_cond = build2 (new_code, boolean_type_node, new_arg,
fold_convert (TREE_TYPE (new_arg), fold_convert (TREE_TYPE (new_arg),
integer_zero_node)); integer_zero_node));
} }
}
}
*test_var_p = test_var;
return new_cond;
}
/* Forward propagate a single-use variable into COND_EXPR as many
times as possible. */
static void
forward_propagate_into_cond (tree cond_expr)
{
gcc_assert (TREE_CODE (cond_expr) == COND_EXPR);
while (1)
{
tree test_var = NULL_TREE;
tree cond = COND_EXPR_COND (cond_expr);
tree new_cond = forward_propagate_into_cond_1 (cond, &test_var);
/* Return if unsuccessful. */
if (new_cond == NULL_TREE)
break;
/* Dump details. */ /* Dump details. */
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
...@@ -450,19 +367,13 @@ substitute_single_use_vars (varray_type *cond_worklist, ...@@ -450,19 +367,13 @@ substitute_single_use_vars (varray_type *cond_worklist,
fprintf (dump_file, "'\n"); fprintf (dump_file, "'\n");
} }
/* Replace the condition. */ COND_EXPR_COND (cond_expr) = new_cond;
COND_EXPR_COND (cond_stmt) = new_cond; update_stmt (cond_expr);
update_stmt (cond_stmt);
propagated_uses++;
VARRAY_PUSH_TREE (*cond_worklist, cond_stmt);
}
/* If we propagated into all the uses, then we can delete DEF. if (has_zero_uses (test_var))
Unfortunately, we have to find the defining statement in
whatever block it might be in. */
if (num_uses && num_uses == propagated_uses)
{ {
block_stmt_iterator bsi = bsi_for_stmt (def_stmt); tree def = SSA_NAME_DEF_STMT (test_var);
block_stmt_iterator bsi = bsi_for_stmt (def);
bsi_remove (&bsi); bsi_remove (&bsi);
} }
} }
...@@ -474,42 +385,13 @@ static void ...@@ -474,42 +385,13 @@ static void
tree_ssa_forward_propagate_single_use_vars (void) tree_ssa_forward_propagate_single_use_vars (void)
{ {
basic_block bb; basic_block bb;
varray_type vars_worklist, cond_worklist;
vars = BITMAP_ALLOC (NULL);
VARRAY_TREE_INIT (vars_worklist, 10, "VARS worklist");
VARRAY_TREE_INIT (cond_worklist, 10, "COND worklist");
/* Prime the COND_EXPR worklist by placing all the COND_EXPRs on the
worklist. */
FOR_EACH_BB (bb) FOR_EACH_BB (bb)
{ {
tree last = last_stmt (bb); tree last = last_stmt (bb);
if (last && TREE_CODE (last) == COND_EXPR) if (last && TREE_CODE (last) == COND_EXPR)
VARRAY_PUSH_TREE (cond_worklist, last); forward_propagate_into_cond (last);
} }
while (VARRAY_ACTIVE_SIZE (cond_worklist) > 0)
{
/* First get a list of all the interesting COND_EXPRs and potential
single use variables which feed those COND_EXPRs. This will drain
COND_WORKLIST and initialize VARS_WORKLIST. */
record_single_argument_cond_exprs (cond_worklist, &vars_worklist, vars);
if (VARRAY_ACTIVE_SIZE (vars_worklist) > 0)
{
/* We've computed immediate uses, so we can/must clear the VARS
bitmap for the next iteration. */
bitmap_clear (vars);
/* And optimize. This will drain VARS_WORKLIST and initialize
COND_WORKLIST for the next iteration. */
substitute_single_use_vars (&cond_worklist, vars_worklist);
}
}
/* All done. Clean up. */
BITMAP_FREE (vars);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment