Commit ce94d354 by Richard Guenther Committed by Richard Biener

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
parent 0f3a057a
2008-07-29 Richard Guenther <rguenther@suse.de> 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 * gimplify.c (gimplify_expr): Clear TREE_SIDE_EFFECTS for
OBJ_TYPE_REF. OBJ_TYPE_REF.
......
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> 2008-07-29 Jakub Jelinek <jakub@redhat.com>
PR c++/36852 PR c++/36852
......
/* { 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" } } */
...@@ -2421,64 +2421,56 @@ static VEC(gimple,heap) *inserted_exprs; ...@@ -2421,64 +2421,56 @@ static VEC(gimple,heap) *inserted_exprs;
to see which expressions need to be put into GC'able memory */ to see which expressions need to be put into GC'able memory */
static VEC(gimple, heap) *need_creation; static VEC(gimple, heap) *need_creation;
/* For COMPONENT_REF's and ARRAY_REF's, we can't have any intermediates for the /* The actual worker for create_component_ref_by_pieces. */
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 static tree
create_component_ref_by_pieces (basic_block block, vn_reference_t ref, create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
unsigned int operand, unsigned int *operand, gimple_seq *stmts,
gimple_seq *stmts, gimple domstmt)
gimple domstmt,
bool in_call)
{ {
vn_reference_op_t currop = VEC_index (vn_reference_op_s, ref->operands, vn_reference_op_t currop = VEC_index (vn_reference_op_s, ref->operands,
operand); *operand);
tree genop; tree genop;
++*operand;
switch (currop->opcode) switch (currop->opcode)
{ {
case CALL_EXPR: case CALL_EXPR:
{ {
tree folded; tree folded;
unsigned int i; unsigned int nargs = 0;
vn_reference_op_t declop = VEC_index (vn_reference_op_s, tree *args = XNEWVEC (tree, VEC_length (vn_reference_op_s,
ref->operands, 1); ref->operands) - 1);
unsigned int nargs = VEC_length (vn_reference_op_s, ref->operands) - 2; while (*operand < VEC_length (vn_reference_op_s, ref->operands))
tree *args = XNEWVEC (tree, nargs);
for (i = 0; i < nargs; i++)
{ {
args[i] = create_component_ref_by_pieces (block, ref, args[nargs] = create_component_ref_by_pieces_1 (block, ref,
operand + 2 + i, stmts, operand, stmts,
domstmt, true); domstmt);
nargs++;
} }
folded = build_call_array (currop->type, folded = build_call_array (currop->type,
TREE_CODE (declop->op0) == FUNCTION_DECL TREE_CODE (currop->op0) == FUNCTION_DECL
? build_fold_addr_expr (declop->op0) ? build_fold_addr_expr (currop->op0)
: declop->op0, : currop->op0,
nargs, args); nargs, args);
free (args); free (args);
return folded; return folded;
} }
break; break;
case ADDR_EXPR:
if (currop->op0)
{
gcc_assert (is_gimple_min_invariant (currop->op0));
return currop->op0;
}
/* Fallthrough. */
case REALPART_EXPR: case REALPART_EXPR:
case IMAGPART_EXPR: case IMAGPART_EXPR:
case VIEW_CONVERT_EXPR: case VIEW_CONVERT_EXPR:
{ {
tree folded; tree folded;
tree genop0 = create_component_ref_by_pieces (block, ref, tree genop0 = create_component_ref_by_pieces_1 (block, ref,
operand + 1, operand,
stmts, domstmt, stmts, domstmt);
in_call);
if (!genop0) if (!genop0)
return NULL_TREE; return NULL_TREE;
folded = fold_build1 (currop->opcode, currop->type, folded = fold_build1 (currop->opcode, currop->type,
...@@ -2490,45 +2482,25 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref, ...@@ -2490,45 +2482,25 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
case MISALIGNED_INDIRECT_REF: case MISALIGNED_INDIRECT_REF:
case INDIRECT_REF: case INDIRECT_REF:
{ {
/* Inside a CALL_EXPR op0 is the actual indirect_ref. */ tree folded;
if (in_call) tree genop1 = create_component_ref_by_pieces_1 (block, ref,
{ operand,
tree folded; stmts, domstmt);
tree op0 = TREE_OPERAND (currop->op0, 0); if (!genop1)
pre_expr op0expr = get_or_alloc_expr_for (op0); return NULL_TREE;
tree genop0 = find_or_generate_expression (block, op0expr, stmts, genop1 = fold_convert (build_pointer_type (currop->type),
domstmt); genop1);
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 (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, folded = fold_build1 (currop->opcode, currop->type,
genop1); genop1);
return folded; return folded;
}
} }
break; break;
case BIT_FIELD_REF: case BIT_FIELD_REF:
{ {
tree folded; tree folded;
tree genop0 = create_component_ref_by_pieces (block, ref, operand + 1, tree genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
stmts, domstmt, stmts, domstmt);
in_call);
pre_expr op1expr = get_or_alloc_expr_for (currop->op0); pre_expr op1expr = get_or_alloc_expr_for (currop->op0);
pre_expr op2expr = get_or_alloc_expr_for (currop->op1); pre_expr op2expr = get_or_alloc_expr_for (currop->op1);
tree genop1; tree genop1;
...@@ -2553,17 +2525,14 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref, ...@@ -2553,17 +2525,14 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
case ARRAY_RANGE_REF: case ARRAY_RANGE_REF:
case ARRAY_REF: case ARRAY_REF:
{ {
vn_reference_op_t op0expr;
tree genop0; tree genop0;
tree genop1 = currop->op0; tree genop1 = currop->op0;
pre_expr op1expr; pre_expr op1expr;
tree genop2 = currop->op1; tree genop2 = currop->op1;
pre_expr op2expr; pre_expr op2expr;
tree genop3; tree genop3;
op0expr = VEC_index (vn_reference_op_s, ref->operands, operand + 1); genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
genop0 = create_component_ref_by_pieces (block, ref, operand + 1, stmts, domstmt);
stmts, domstmt,
in_call);
if (!genop0) if (!genop0)
return NULL_TREE; return NULL_TREE;
op1expr = get_or_alloc_expr_for (genop1); op1expr = get_or_alloc_expr_for (genop1);
...@@ -2589,8 +2558,8 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref, ...@@ -2589,8 +2558,8 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
tree op1; tree op1;
tree genop2 = currop->op1; tree genop2 = currop->op1;
pre_expr op2expr; pre_expr op2expr;
op0 = create_component_ref_by_pieces (block, ref, operand + 1, op0 = create_component_ref_by_pieces_1 (block, ref, operand,
stmts, domstmt, in_call); stmts, domstmt);
if (!op0) if (!op0)
return NULL_TREE; return NULL_TREE;
/* op1 should be a FIELD_DECL, which are represented by /* 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, ...@@ -2626,11 +2595,6 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref,
case CONST_DECL: case CONST_DECL:
case RESULT_DECL: case RESULT_DECL:
case FUNCTION_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; return currop->op0;
default: default:
...@@ -2638,6 +2602,26 @@ create_component_ref_by_pieces (basic_block block, vn_reference_t ref, ...@@ -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 /* Find a leader for an expression, or generate one using
create_expression_by_pieces if it's ANTIC but create_expression_by_pieces if it's ANTIC but
complex. complex.
...@@ -2743,8 +2727,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr, ...@@ -2743,8 +2727,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
case REFERENCE: case REFERENCE:
{ {
vn_reference_t ref = PRE_EXPR_REFERENCE (expr); vn_reference_t ref = PRE_EXPR_REFERENCE (expr);
folded = create_component_ref_by_pieces (block, ref, 0, stmts, folded = create_component_ref_by_pieces (block, ref, stmts, domstmt);
domstmt, false);
} }
break; break;
case NARY: case NARY:
...@@ -3616,6 +3599,8 @@ compute_avail (void) ...@@ -3616,6 +3599,8 @@ compute_avail (void)
add_to_exp_gen (block, vro->op0); add_to_exp_gen (block, vro->op0);
if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME) if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME)
add_to_exp_gen (block, vro->op1); 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 = (pre_expr) pool_alloc (pre_expr_pool);
result->kind = REFERENCE; result->kind = REFERENCE;
...@@ -3688,6 +3673,8 @@ compute_avail (void) ...@@ -3688,6 +3673,8 @@ compute_avail (void)
add_to_exp_gen (block, vro->op0); add_to_exp_gen (block, vro->op0);
if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME) if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME)
add_to_exp_gen (block, vro->op1); 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 = (pre_expr) pool_alloc (pre_expr_pool);
result->kind = REFERENCE; result->kind = REFERENCE;
......
...@@ -557,7 +557,7 @@ shared_vuses_from_stmt (gimple stmt) ...@@ -557,7 +557,7 @@ shared_vuses_from_stmt (gimple stmt)
/* Copy the operations present in load/store REF into RESULT, a vector of /* Copy the operations present in load/store REF into RESULT, a vector of
vn_reference_op_s's. */ vn_reference_op_s's. */
static void void
copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result) copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
{ {
if (TREE_CODE (ref) == TARGET_MEM_REF) 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) ...@@ -646,6 +646,13 @@ copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
case SSA_NAME: case SSA_NAME:
temp.op0 = ref; temp.op0 = ref;
break; break;
case ADDR_EXPR:
if (is_gimple_min_invariant (ref))
{
temp.op0 = ref;
break;
}
/* Fallthrough. */
/* These are only interesting for their operands, their /* These are only interesting for their operands, their
existence, and their type. They will never be the last existence, and their type. They will never be the last
ref in the chain of references (IE they require an 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) ...@@ -654,15 +661,15 @@ copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
case IMAGPART_EXPR: case IMAGPART_EXPR:
case REALPART_EXPR: case REALPART_EXPR:
case VIEW_CONVERT_EXPR: case VIEW_CONVERT_EXPR:
case ADDR_EXPR:
break; break;
default: default:
gcc_unreachable (); gcc_unreachable ();
} }
VEC_safe_push (vn_reference_op_s, heap, *result, &temp); 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); ref = TREE_OPERAND (ref, 0);
else else
ref = NULL_TREE; ref = NULL_TREE;
...@@ -677,7 +684,6 @@ copy_reference_ops_from_call (gimple call, ...@@ -677,7 +684,6 @@ copy_reference_ops_from_call (gimple call,
VEC(vn_reference_op_s, heap) **result) VEC(vn_reference_op_s, heap) **result)
{ {
vn_reference_op_s temp; vn_reference_op_s temp;
tree callfn;
unsigned i; unsigned i;
/* Copy the call_expr opcode, type, function being called, and /* Copy the call_expr opcode, type, function being called, and
...@@ -685,33 +691,15 @@ copy_reference_ops_from_call (gimple call, ...@@ -685,33 +691,15 @@ copy_reference_ops_from_call (gimple call,
memset (&temp, 0, sizeof (temp)); memset (&temp, 0, sizeof (temp));
temp.type = gimple_call_return_type (call); temp.type = gimple_call_return_type (call);
temp.opcode = CALL_EXPR; temp.opcode = CALL_EXPR;
temp.op0 = gimple_call_fn (call);
VEC_safe_push (vn_reference_op_s, heap, *result, &temp); VEC_safe_push (vn_reference_op_s, heap, *result, &temp);
/* FIXME tuples /* Copy the call arguments. As they can be references as well,
We make no attempt to simplify the called function because just chain them together. */
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);
for (i = 0; i < gimple_call_num_args (call); ++i) for (i = 0; i < gimple_call_num_args (call); ++i)
{ {
tree callarg = gimple_call_arg (call, i); tree callarg = gimple_call_arg (call, i);
memset (&temp, 0, sizeof (temp)); copy_reference_ops_from_ref (callarg, result);
temp.type = TREE_TYPE (callarg);
temp.opcode = TREE_CODE (callarg);
temp.op0 = callarg;
VEC_safe_push (vn_reference_op_s, heap, *result, &temp);
} }
return; return;
} }
......
...@@ -174,6 +174,7 @@ vn_nary_op_t vn_nary_op_insert_stmt (gimple, tree); ...@@ -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, vn_nary_op_t vn_nary_op_insert_pieces (unsigned int, enum tree_code,
tree, tree, tree, tree, tree, tree, tree, tree,
tree, tree, unsigned int); 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) **); void copy_reference_ops_from_call (gimple, VEC(vn_reference_op_s, heap) **);
tree vn_reference_lookup_pieces (VEC (tree, gc) *, tree vn_reference_lookup_pieces (VEC (tree, gc) *,
VEC (vn_reference_op_s, heap) *, VEC (vn_reference_op_s, heap) *,
......
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