re PR tree-optimization/36945 (PRE/SCCVN do not handle aggregate function arguments correctly)

2008-07-29  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/36945
	* tree-ssa-sccvn.h (copy_reference_ops_from_ref): Declare.
	* tree-ssa-sccvn.c (copy_reference_ops_from_ref): Export.
	Record invariant addresses un-decomposed.
	(copy_reference_ops_from_call): Record reference call
	arguments properly.  Simplify.
	* tree-ssa-pre.c (create_component_ref_by_pieces_1): New
	helper split out from ...
	(create_component_ref_by_pieces): ... here.  Simplify.
	Prepare for recursive invocation for call arguments.
	(create_expression_by_pieces): Adjust call to
	create_component_ref_by_pieces.
	(compute_avail): Process operand 2 of reference ops.

	* gcc.dg/tree-ssa/ssa-pre-18.c: New testcase.

From-SVN: r138257
This commit is contained in:
Richard Guenther 2008-07-29 17:09:26 +00:00 committed by Richard Biener
parent 0f3a057aa9
commit ce94d3547f
6 changed files with 127 additions and 109 deletions

View File

@ -1,3 +1,19 @@
2008-07-29 Richard Guenther <rguenther@suse.de>
PR tree-optimization/36945
* tree-ssa-sccvn.h (copy_reference_ops_from_ref): Declare.
* tree-ssa-sccvn.c (copy_reference_ops_from_ref): Export.
Record invariant addresses un-decomposed.
(copy_reference_ops_from_call): Record reference call
arguments properly. Simplify.
* tree-ssa-pre.c (create_component_ref_by_pieces_1): New
helper split out from ...
(create_component_ref_by_pieces): ... here. Simplify.
Prepare for recursive invocation for call arguments.
(create_expression_by_pieces): Adjust call to
create_component_ref_by_pieces.
(compute_avail): Process operand 2 of reference ops.
2008-07-29 Richard Guenther <rguenther@suse.de>
* gimplify.c (gimplify_expr): Clear TREE_SIDE_EFFECTS for

View File

@ -1,3 +1,8 @@
2008-07-29 Richard Guenther <rguenther@suse.de>
PR tree-optimization/36945
* gcc.dg/tree-ssa/ssa-pre-18.c: New testcase.
2008-07-29 Jakub Jelinek <jakub@redhat.com>
PR c++/36852

View File

@ -0,0 +1,21 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-pre-details" } */
struct Bar { int a; int b; };
struct Foo { int x; struct Bar y; };
int __attribute__((const)) foo (struct Bar);
int bar (int b)
{
struct Foo f;
int c;
while (b--)
{
c = foo(f.y);
}
return c;
}
/* { dg-final { scan-tree-dump "Replaced foo \\(f.y\\)" "pre" } } */
/* { dg-final { cleanup-tree-dump "pre" } } */

View File

@ -2421,64 +2421,56 @@ static VEC(gimple,heap) *inserted_exprs;
to see which expressions need to be put into GC'able memory */
static VEC(gimple, heap) *need_creation;
/* For COMPONENT_REF's and ARRAY_REF's, we can't have any intermediates for the
COMPONENT_REF or INDIRECT_REF or ARRAY_REF portion, because we'd end up with
trying to rename aggregates into ssa form directly, which is a no
no.
/* The actual worker for create_component_ref_by_pieces. */
Thus, this routine doesn't create temporaries, it just builds a
single access expression for the array, calling
find_or_generate_expression to build the innermost pieces.
This function is a subroutine of create_expression_by_pieces, and
should not be called on it's own unless you really know what you
are doing.
*/
static tree
create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
unsigned int operand,
gimple_seq *stmts,
gimple domstmt,
bool in_call)
create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
unsigned int *operand, gimple_seq *stmts,
gimple domstmt)
{
vn_reference_op_t currop = VEC_index (vn_reference_op_s, ref->operands,
operand);
*operand);
tree genop;
++*operand;
switch (currop->opcode)
{
case CALL_EXPR:
{
tree folded;
unsigned int i;
vn_reference_op_t declop = VEC_index (vn_reference_op_s,
ref->operands, 1);
unsigned int nargs = VEC_length (vn_reference_op_s, ref->operands) - 2;
tree *args = XNEWVEC (tree, nargs);
for (i = 0; i < nargs; i++)
unsigned int nargs = 0;
tree *args = XNEWVEC (tree, VEC_length (vn_reference_op_s,
ref->operands) - 1);
while (*operand < VEC_length (vn_reference_op_s, ref->operands))
{
args[i] = create_component_ref_by_pieces (block, ref,
operand + 2 + i, stmts,
domstmt, true);
args[nargs] = create_component_ref_by_pieces_1 (block, ref,
operand, stmts,
domstmt);
nargs++;
}
folded = build_call_array (currop->type,
TREE_CODE (declop->op0) == FUNCTION_DECL
? build_fold_addr_expr (declop->op0)
: declop->op0,
TREE_CODE (currop->op0) == FUNCTION_DECL
? build_fold_addr_expr (currop->op0)
: currop->op0,
nargs, args);
free (args);
return folded;
}
break;
case ADDR_EXPR:
if (currop->op0)
{
gcc_assert (is_gimple_min_invariant (currop->op0));
return currop->op0;
}
/* Fallthrough. */
case REALPART_EXPR:
case IMAGPART_EXPR:
case VIEW_CONVERT_EXPR:
{
tree folded;
tree genop0 = create_component_ref_by_pieces (block, ref,
operand + 1,
stmts, domstmt,
in_call);
tree genop0 = create_component_ref_by_pieces_1 (block, ref,
operand,
stmts, domstmt);
if (!genop0)
return NULL_TREE;
folded = fold_build1 (currop->opcode, currop->type,
@ -2490,45 +2482,25 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
case MISALIGNED_INDIRECT_REF:
case INDIRECT_REF:
{
/* Inside a CALL_EXPR op0 is the actual indirect_ref. */
if (in_call)
{
tree folded;
tree op0 = TREE_OPERAND (currop->op0, 0);
pre_expr op0expr = get_or_alloc_expr_for (op0);
tree genop0 = find_or_generate_expression (block, op0expr, stmts,
domstmt);
if (!genop0)
return NULL_TREE;
folded = fold_build1 (currop->opcode, currop->type,
genop0);
return folded;
}
else
{
tree folded;
tree genop1 = create_component_ref_by_pieces_1 (block, ref,
operand,
stmts, domstmt);
if (!genop1)
return NULL_TREE;
genop1 = fold_convert (build_pointer_type (currop->type),
genop1);
tree folded;
tree genop1 = create_component_ref_by_pieces (block, ref,
operand + 1,
stmts, domstmt,
in_call);
if (!genop1)
return NULL_TREE;
genop1 = fold_convert (build_pointer_type (currop->type),
genop1);
folded = fold_build1 (currop->opcode, currop->type,
genop1);
return folded;
}
folded = fold_build1 (currop->opcode, currop->type,
genop1);
return folded;
}
break;
case BIT_FIELD_REF:
{
tree folded;
tree genop0 = create_component_ref_by_pieces (block, ref, operand + 1,
stmts, domstmt,
in_call);
tree genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
stmts, domstmt);
pre_expr op1expr = get_or_alloc_expr_for (currop->op0);
pre_expr op2expr = get_or_alloc_expr_for (currop->op1);
tree genop1;
@ -2553,17 +2525,14 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
case ARRAY_RANGE_REF:
case ARRAY_REF:
{
vn_reference_op_t op0expr;
tree genop0;
tree genop1 = currop->op0;
pre_expr op1expr;
tree genop2 = currop->op1;
pre_expr op2expr;
tree genop3;
op0expr = VEC_index (vn_reference_op_s, ref->operands, operand + 1);
genop0 = create_component_ref_by_pieces (block, ref, operand + 1,
stmts, domstmt,
in_call);
genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
stmts, domstmt);
if (!genop0)
return NULL_TREE;
op1expr = get_or_alloc_expr_for (genop1);
@ -2589,8 +2558,8 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
tree op1;
tree genop2 = currop->op1;
pre_expr op2expr;
op0 = create_component_ref_by_pieces (block, ref, operand + 1,
stmts, domstmt, in_call);
op0 = create_component_ref_by_pieces_1 (block, ref, operand,
stmts, domstmt);
if (!op0)
return NULL_TREE;
/* op1 should be a FIELD_DECL, which are represented by
@ -2626,11 +2595,6 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
case CONST_DECL:
case RESULT_DECL:
case FUNCTION_DECL:
/* For ADDR_EXPR in a CALL_EXPR, op0 is actually the entire
ADDR_EXPR, not just it's operand. */
case ADDR_EXPR:
if (currop->opcode == ADDR_EXPR)
gcc_assert (currop->op0 != NULL);
return currop->op0;
default:
@ -2638,6 +2602,26 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
}
}
/* For COMPONENT_REF's and ARRAY_REF's, we can't have any intermediates for the
COMPONENT_REF or INDIRECT_REF or ARRAY_REF portion, because we'd end up with
trying to rename aggregates into ssa form directly, which is a no no.
Thus, this routine doesn't create temporaries, it just builds a
single access expression for the array, calling
find_or_generate_expression to build the innermost pieces.
This function is a subroutine of create_expression_by_pieces, and
should not be called on it's own unless you really know what you
are doing. */
static tree
create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
gimple_seq *stmts, gimple domstmt)
{
unsigned int op = 0;
return create_component_ref_by_pieces_1 (block, ref, &op, stmts, domstmt);
}
/* Find a leader for an expression, or generate one using
create_expression_by_pieces if it's ANTIC but
complex.
@ -2743,8 +2727,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
case REFERENCE:
{
vn_reference_t ref = PRE_EXPR_REFERENCE (expr);
folded = create_component_ref_by_pieces (block, ref, 0, stmts,
domstmt, false);
folded = create_component_ref_by_pieces (block, ref, stmts, domstmt);
}
break;
case NARY:
@ -3616,6 +3599,8 @@ compute_avail (void)
add_to_exp_gen (block, vro->op0);
if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME)
add_to_exp_gen (block, vro->op1);
if (vro->op2 && TREE_CODE (vro->op2) == SSA_NAME)
add_to_exp_gen (block, vro->op2);
}
result = (pre_expr) pool_alloc (pre_expr_pool);
result->kind = REFERENCE;
@ -3688,6 +3673,8 @@ compute_avail (void)
add_to_exp_gen (block, vro->op0);
if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME)
add_to_exp_gen (block, vro->op1);
if (vro->op2 && TREE_CODE (vro->op2) == SSA_NAME)
add_to_exp_gen (block, vro->op2);
}
result = (pre_expr) pool_alloc (pre_expr_pool);
result->kind = REFERENCE;

View File

@ -557,7 +557,7 @@ shared_vuses_from_stmt (gimple stmt)
/* Copy the operations present in load/store REF into RESULT, a vector of
vn_reference_op_s's. */
static void
void
copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
{
if (TREE_CODE (ref) == TARGET_MEM_REF)
@ -646,6 +646,13 @@ copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
case SSA_NAME:
temp.op0 = ref;
break;
case ADDR_EXPR:
if (is_gimple_min_invariant (ref))
{
temp.op0 = ref;
break;
}
/* Fallthrough. */
/* These are only interesting for their operands, their
existence, and their type. They will never be the last
ref in the chain of references (IE they require an
@ -654,15 +661,15 @@ copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
case IMAGPART_EXPR:
case REALPART_EXPR:
case VIEW_CONVERT_EXPR:
case ADDR_EXPR:
break;
default:
gcc_unreachable ();
}
VEC_safe_push (vn_reference_op_s, heap, *result, &temp);
if (REFERENCE_CLASS_P (ref) || TREE_CODE (ref) == ADDR_EXPR)
if (REFERENCE_CLASS_P (ref)
|| (TREE_CODE (ref) == ADDR_EXPR
&& !is_gimple_min_invariant (ref)))
ref = TREE_OPERAND (ref, 0);
else
ref = NULL_TREE;
@ -677,7 +684,6 @@ copy_reference_ops_from_call (gimple call,
VEC(vn_reference_op_s, heap) **result)
{
vn_reference_op_s temp;
tree callfn;
unsigned i;
/* Copy the call_expr opcode, type, function being called, and
@ -685,33 +691,15 @@ copy_reference_ops_from_call (gimple call,
memset (&temp, 0, sizeof (temp));
temp.type = gimple_call_return_type (call);
temp.opcode = CALL_EXPR;
temp.op0 = gimple_call_fn (call);
VEC_safe_push (vn_reference_op_s, heap, *result, &temp);
/* FIXME tuples
We make no attempt to simplify the called function because
the typical &FUNCTION_DECL form is also used in function pointer
cases that become constant. If we simplify the original to
FUNCTION_DECL but not the function pointer case (which can
happen because we have no fold functions that operate on
vn_reference_t), we will claim they are not equivalent.
An example of this behavior can be see if CALL_EXPR_FN below is
replaced with get_callee_fndecl and gcc.dg/tree-ssa/ssa-pre-13.c
is compiled. */
callfn = gimple_call_fn (call);
temp.type = TREE_TYPE (callfn);
temp.opcode = TREE_CODE (callfn);
temp.op0 = callfn;
VEC_safe_push (vn_reference_op_s, heap, *result, &temp);
/* Copy the call arguments. As they can be references as well,
just chain them together. */
for (i = 0; i < gimple_call_num_args (call); ++i)
{
tree callarg = gimple_call_arg (call, i);
memset (&temp, 0, sizeof (temp));
temp.type = TREE_TYPE (callarg);
temp.opcode = TREE_CODE (callarg);
temp.op0 = callarg;
VEC_safe_push (vn_reference_op_s, heap, *result, &temp);
copy_reference_ops_from_ref (callarg, result);
}
return;
}

View File

@ -174,6 +174,7 @@ vn_nary_op_t vn_nary_op_insert_stmt (gimple, tree);
vn_nary_op_t vn_nary_op_insert_pieces (unsigned int, enum tree_code,
tree, tree, tree, tree,
tree, tree, unsigned int);
void copy_reference_ops_from_ref (tree, VEC(vn_reference_op_s, heap) **);
void copy_reference_ops_from_call (gimple, VEC(vn_reference_op_s, heap) **);
tree vn_reference_lookup_pieces (VEC (tree, gc) *,
VEC (vn_reference_op_s, heap) *,