Commit 7b1737d0 by Richard Guenther Committed by Richard Biener

re PR tree-optimization/31146 (forwprop does not look through casts)

2007-03-16  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/31146
	* tree-ssa-forwprop.c (forward_propagate_addr_expr_1): Restructure
	to allow recursion of forward_propagate_addr_expr.
	(forward_propagate_addr_into_variable_array_index): Likewise.
	(forward_propagate_addr_expr): Likewise.
	(tree_ssa_forward_propagate_single_use_vars): Likewise.
	(forward_propagate_addr_expr_1): Recurse on simple copies
	instead of propagating into them.  Do so for useless conversions
	as well.
	(forward_propagate_addr_expr): Clean up unused statements after
	recursion.

	* g++.dg/tree-ssa/pr31146.C: New testcase.

From-SVN: r122985
parent 3811dfcd
2007-03-16 Richard Guenther <rguenther@suse.de> 2007-03-16 Richard Guenther <rguenther@suse.de>
PR tree-optimization/31146
* tree-ssa-forwprop.c (forward_propagate_addr_expr_1): Restructure
to allow recursion of forward_propagate_addr_expr.
(forward_propagate_addr_into_variable_array_index): Likewise.
(forward_propagate_addr_expr): Likewise.
(tree_ssa_forward_propagate_single_use_vars): Likewise.
(forward_propagate_addr_expr_1): Recurse on simple copies
instead of propagating into them. Do so for useless conversions
as well.
(forward_propagate_addr_expr): Clean up unused statements after
recursion.
2007-03-16 Richard Guenther <rguenther@suse.de>
* builtins.c (expand_builtin_cexpi): Use the right argument * builtins.c (expand_builtin_cexpi): Use the right argument
for the expansion via cexp. for the expansion via cexp.
......
2007-03-16 Richard Guenther <rguenther@suse.de>
PR tree-optimization/31146
* g++.dg/tree-ssa/pr31146.C: New testcase.
2007-03-16 Richard Sandiford <richard@codesourcery.com> 2007-03-16 Richard Sandiford <richard@codesourcery.com>
* lib/target-supports.exp (check_missing_uclibc_feature): Don't * lib/target-supports.exp (check_missing_uclibc_feature): Don't
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-forwprop1" } */
/* We should be able to optimize this to i[j] = 1 during
early optimizations. */
int i[5];
void foo (int j)
{
void *p = &i[j];
int *q = (int *)p;
*q = 1;
}
/* { dg-final { scan-tree-dump "i\\\[j.*\\\] = 1;" "forwprop1" } } */
/* { dg-final { cleanup-tree-dump "forwprop1" } } */
...@@ -149,6 +149,7 @@ Boston, MA 02110-1301, USA. */ ...@@ -149,6 +149,7 @@ Boston, MA 02110-1301, USA. */
This will (of course) be extended as other needs arise. */ This will (of course) be extended as other needs arise. */
static bool forward_propagate_addr_expr (tree name, tree rhs);
/* Set to true if we delete EH edges during the optimization. */ /* Set to true if we delete EH edges during the optimization. */
static bool cfg_changed; static bool cfg_changed;
...@@ -591,7 +592,7 @@ tidy_after_forward_propagate_addr (tree stmt) ...@@ -591,7 +592,7 @@ tidy_after_forward_propagate_addr (tree stmt)
mark_symbols_for_renaming (stmt); mark_symbols_for_renaming (stmt);
} }
/* STMT defines LHS which is contains the address of the 0th element /* DEF_RHS defines LHS which is contains the address of the 0th element
in an array. USE_STMT uses LHS to compute the address of an in an array. USE_STMT uses LHS to compute the address of an
arbitrary element within the array. The (variable) byte offset arbitrary element within the array. The (variable) byte offset
of the element is contained in OFFSET. of the element is contained in OFFSET.
...@@ -608,7 +609,7 @@ tidy_after_forward_propagate_addr (tree stmt) ...@@ -608,7 +609,7 @@ tidy_after_forward_propagate_addr (tree stmt)
static bool static bool
forward_propagate_addr_into_variable_array_index (tree offset, tree lhs, forward_propagate_addr_into_variable_array_index (tree offset, tree lhs,
tree stmt, tree use_stmt) tree def_rhs, tree use_stmt)
{ {
tree index; tree index;
...@@ -650,8 +651,7 @@ forward_propagate_addr_into_variable_array_index (tree offset, tree lhs, ...@@ -650,8 +651,7 @@ forward_propagate_addr_into_variable_array_index (tree offset, tree lhs,
index = TREE_OPERAND (offset, 0); index = TREE_OPERAND (offset, 0);
/* Replace the pointer addition with array indexing. */ /* Replace the pointer addition with array indexing. */
GIMPLE_STMT_OPERAND (use_stmt, 1) GIMPLE_STMT_OPERAND (use_stmt, 1) = unshare_expr (def_rhs);
= unshare_expr (GIMPLE_STMT_OPERAND (stmt, 1));
TREE_OPERAND (TREE_OPERAND (GIMPLE_STMT_OPERAND (use_stmt, 1), 0), 1) TREE_OPERAND (TREE_OPERAND (GIMPLE_STMT_OPERAND (use_stmt, 1), 0), 1)
= index; = index;
...@@ -662,7 +662,8 @@ forward_propagate_addr_into_variable_array_index (tree offset, tree lhs, ...@@ -662,7 +662,8 @@ forward_propagate_addr_into_variable_array_index (tree offset, tree lhs,
return true; return true;
} }
/* STMT is a statement of the form SSA_NAME = ADDR_EXPR <whatever>. /* NAME is a SSA_NAME representing DEF_RHS which is of the form
ADDR_EXPR <whatever>.
Try to forward propagate the ADDR_EXPR into the use USE_STMT. Try to forward propagate the ADDR_EXPR into the use USE_STMT.
Often this will allow for removal of an ADDR_EXPR and INDIRECT_REF Often this will allow for removal of an ADDR_EXPR and INDIRECT_REF
...@@ -672,9 +673,8 @@ forward_propagate_addr_into_variable_array_index (tree offset, tree lhs, ...@@ -672,9 +673,8 @@ forward_propagate_addr_into_variable_array_index (tree offset, tree lhs,
be not totally successful, yet things may have been changed). */ be not totally successful, yet things may have been changed). */
static bool static bool
forward_propagate_addr_expr_1 (tree stmt, tree use_stmt) forward_propagate_addr_expr_1 (tree name, tree def_rhs, tree use_stmt)
{ {
tree name = GIMPLE_STMT_OPERAND (stmt, 0);
tree lhs, rhs, array_ref; tree lhs, rhs, array_ref;
/* Strip away any outer COMPONENT_REF/ARRAY_REF nodes from the LHS. /* Strip away any outer COMPONENT_REF/ARRAY_REF nodes from the LHS.
...@@ -683,36 +683,37 @@ forward_propagate_addr_expr_1 (tree stmt, tree use_stmt) ...@@ -683,36 +683,37 @@ forward_propagate_addr_expr_1 (tree stmt, tree use_stmt)
while (TREE_CODE (lhs) == COMPONENT_REF || TREE_CODE (lhs) == ARRAY_REF) while (TREE_CODE (lhs) == COMPONENT_REF || TREE_CODE (lhs) == ARRAY_REF)
lhs = TREE_OPERAND (lhs, 0); lhs = TREE_OPERAND (lhs, 0);
rhs = GIMPLE_STMT_OPERAND (use_stmt, 1);
/* Now see if the LHS node is an INDIRECT_REF using NAME. If so, /* Now see if the LHS node is an INDIRECT_REF using NAME. If so,
propagate the ADDR_EXPR into the use of NAME and fold the result. */ propagate the ADDR_EXPR into the use of NAME and fold the result. */
if (TREE_CODE (lhs) == INDIRECT_REF && TREE_OPERAND (lhs, 0) == name) if (TREE_CODE (lhs) == INDIRECT_REF && TREE_OPERAND (lhs, 0) == name)
{ {
/* This should always succeed in creating gimple, so there is /* This should always succeed in creating gimple, so there is
no need to save enough state to undo this propagation. */ no need to save enough state to undo this propagation. */
TREE_OPERAND (lhs, 0) = unshare_expr (GIMPLE_STMT_OPERAND (stmt, 1)); TREE_OPERAND (lhs, 0) = unshare_expr (def_rhs);
fold_stmt_inplace (use_stmt); fold_stmt_inplace (use_stmt);
tidy_after_forward_propagate_addr (use_stmt); tidy_after_forward_propagate_addr (use_stmt);
}
/* Trivial case. The use statement could be a trivial copy. We /* The only case we did not replace all uses this way is if the
go ahead and handle that case here since it's trivial and use statement is of the form *name = name. */
removes the need to run copy-prop before this pass to get return rhs != name;
the best results. Also note that by handling this case here
we can catch some cascading effects, ie the single use is
in a copy, and the copy is used later by a single INDIRECT_REF
for example. */
else if (TREE_CODE (lhs) == SSA_NAME
&& GIMPLE_STMT_OPERAND (use_stmt, 1) == name)
{
GIMPLE_STMT_OPERAND (use_stmt, 1)
= unshare_expr (GIMPLE_STMT_OPERAND (stmt, 1));
tidy_after_forward_propagate_addr (use_stmt);
return true;
} }
/* Trivial case. The use statement could be a trivial copy or a
useless conversion. Recurse to the uses of the lhs as copyprop does
not copy through differen variant pointers and FRE does not catch
all useless conversions. */
else if ((TREE_CODE (lhs) == SSA_NAME
&& rhs == name)
|| ((TREE_CODE (rhs) == NOP_EXPR
|| TREE_CODE (rhs) == CONVERT_EXPR)
&& tree_ssa_useless_type_conversion_1 (TREE_TYPE (rhs),
TREE_TYPE (def_rhs))))
return forward_propagate_addr_expr (lhs, def_rhs);
/* Strip away any outer COMPONENT_REF, ARRAY_REF or ADDR_EXPR /* Strip away any outer COMPONENT_REF, ARRAY_REF or ADDR_EXPR
nodes from the RHS. */ nodes from the RHS. */
rhs = GIMPLE_STMT_OPERAND (use_stmt, 1);
while (TREE_CODE (rhs) == COMPONENT_REF while (TREE_CODE (rhs) == COMPONENT_REF
|| TREE_CODE (rhs) == ARRAY_REF || TREE_CODE (rhs) == ARRAY_REF
|| TREE_CODE (rhs) == ADDR_EXPR) || TREE_CODE (rhs) == ADDR_EXPR)
...@@ -724,7 +725,7 @@ forward_propagate_addr_expr_1 (tree stmt, tree use_stmt) ...@@ -724,7 +725,7 @@ forward_propagate_addr_expr_1 (tree stmt, tree use_stmt)
{ {
/* This should always succeed in creating gimple, so there is /* This should always succeed in creating gimple, so there is
no need to save enough state to undo this propagation. */ no need to save enough state to undo this propagation. */
TREE_OPERAND (rhs, 0) = unshare_expr (GIMPLE_STMT_OPERAND (stmt, 1)); TREE_OPERAND (rhs, 0) = unshare_expr (def_rhs);
fold_stmt_inplace (use_stmt); fold_stmt_inplace (use_stmt);
tidy_after_forward_propagate_addr (use_stmt); tidy_after_forward_propagate_addr (use_stmt);
return true; return true;
...@@ -734,7 +735,7 @@ forward_propagate_addr_expr_1 (tree stmt, tree use_stmt) ...@@ -734,7 +735,7 @@ forward_propagate_addr_expr_1 (tree stmt, tree use_stmt)
array indexing. They only apply when we have the address of array indexing. They only apply when we have the address of
element zero in an array. If that is not the case then there element zero in an array. If that is not the case then there
is nothing to do. */ is nothing to do. */
array_ref = TREE_OPERAND (GIMPLE_STMT_OPERAND (stmt, 1), 0); array_ref = TREE_OPERAND (def_rhs, 0);
if (TREE_CODE (array_ref) != ARRAY_REF if (TREE_CODE (array_ref) != ARRAY_REF
|| TREE_CODE (TREE_TYPE (TREE_OPERAND (array_ref, 0))) != ARRAY_TYPE || TREE_CODE (TREE_TYPE (TREE_OPERAND (array_ref, 0))) != ARRAY_TYPE
|| !integer_zerop (TREE_OPERAND (array_ref, 1))) || !integer_zerop (TREE_OPERAND (array_ref, 1)))
...@@ -751,7 +752,7 @@ forward_propagate_addr_expr_1 (tree stmt, tree use_stmt) ...@@ -751,7 +752,7 @@ forward_propagate_addr_expr_1 (tree stmt, tree use_stmt)
&& TREE_CODE (TREE_OPERAND (rhs, 1)) == INTEGER_CST) && TREE_CODE (TREE_OPERAND (rhs, 1)) == INTEGER_CST)
{ {
tree orig = unshare_expr (rhs); tree orig = unshare_expr (rhs);
TREE_OPERAND (rhs, 0) = unshare_expr (GIMPLE_STMT_OPERAND (stmt, 1)); TREE_OPERAND (rhs, 0) = unshare_expr (def_rhs);
/* If folding succeeds, then we have just exposed new variables /* If folding succeeds, then we have just exposed new variables
in USE_STMT which will need to be renamed. If folding fails, in USE_STMT which will need to be renamed. If folding fails,
...@@ -783,7 +784,7 @@ forward_propagate_addr_expr_1 (tree stmt, tree use_stmt) ...@@ -783,7 +784,7 @@ forward_propagate_addr_expr_1 (tree stmt, tree use_stmt)
tree offset_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 1)); tree offset_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 1));
res = forward_propagate_addr_into_variable_array_index (offset_stmt, lhs, res = forward_propagate_addr_into_variable_array_index (offset_stmt, lhs,
stmt, use_stmt); def_rhs, use_stmt);
return res; return res;
} }
...@@ -798,7 +799,7 @@ forward_propagate_addr_expr_1 (tree stmt, tree use_stmt) ...@@ -798,7 +799,7 @@ forward_propagate_addr_expr_1 (tree stmt, tree use_stmt)
bool res; bool res;
tree offset_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0)); tree offset_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0));
res = forward_propagate_addr_into_variable_array_index (offset_stmt, lhs, res = forward_propagate_addr_into_variable_array_index (offset_stmt, lhs,
stmt, use_stmt); def_rhs, use_stmt);
return res; return res;
} }
return false; return false;
...@@ -812,10 +813,9 @@ forward_propagate_addr_expr_1 (tree stmt, tree use_stmt) ...@@ -812,10 +813,9 @@ forward_propagate_addr_expr_1 (tree stmt, tree use_stmt)
Returns true, if all uses have been propagated into. */ Returns true, if all uses have been propagated into. */
static bool static bool
forward_propagate_addr_expr (tree stmt) forward_propagate_addr_expr (tree name, tree rhs)
{ {
int stmt_loop_depth = bb_for_stmt (stmt)->loop_depth; int stmt_loop_depth = bb_for_stmt (SSA_NAME_DEF_STMT (name))->loop_depth;
tree name = GIMPLE_STMT_OPERAND (stmt, 0);
imm_use_iterator iter; imm_use_iterator iter;
tree use_stmt; tree use_stmt;
bool all = true; bool all = true;
...@@ -843,10 +843,22 @@ forward_propagate_addr_expr (tree stmt) ...@@ -843,10 +843,22 @@ forward_propagate_addr_expr (tree stmt)
push_stmt_changes (&use_stmt); push_stmt_changes (&use_stmt);
result = forward_propagate_addr_expr_1 (stmt, use_stmt); result = forward_propagate_addr_expr_1 (name, rhs, use_stmt);
all &= result; all &= result;
pop_stmt_changes (&use_stmt); pop_stmt_changes (&use_stmt);
/* Remove intermediate now unused copy and conversion chains. */
if (result
&& TREE_CODE (GIMPLE_STMT_OPERAND (use_stmt, 0)) == SSA_NAME
&& (TREE_CODE (GIMPLE_STMT_OPERAND (use_stmt, 1)) == SSA_NAME
|| TREE_CODE (GIMPLE_STMT_OPERAND (use_stmt, 1)) == NOP_EXPR
|| TREE_CODE (GIMPLE_STMT_OPERAND (use_stmt, 1)) == CONVERT_EXPR))
{
block_stmt_iterator bsi = bsi_for_stmt (use_stmt);
release_defs (use_stmt);
bsi_remove (&bsi, true);
}
} }
return all; return all;
...@@ -981,7 +993,7 @@ tree_ssa_forward_propagate_single_use_vars (void) ...@@ -981,7 +993,7 @@ tree_ssa_forward_propagate_single_use_vars (void)
if (TREE_CODE (rhs) == ADDR_EXPR) if (TREE_CODE (rhs) == ADDR_EXPR)
{ {
if (forward_propagate_addr_expr (stmt)) if (forward_propagate_addr_expr (lhs, rhs))
{ {
release_defs (stmt); release_defs (stmt);
todoflags |= TODO_remove_unused_locals; todoflags |= TODO_remove_unused_locals;
......
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