[PATCH] Fix PR36945, PRE and call-exprs
Richard Guenther
rguenther@suse.de
Tue Jul 29 19:38:00 GMT 2008
This fixes value-numbering and re-constructing call expressions which
can have arguments with an arbitrary complicated reference structure.
Fixed by just using copy_reference_ops_from_ref and de-serializing
arguments on-the-fly. For consistency I made invariant addresses
always serialized as a single reference op - this avoids touching
phi-translation and more.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.
Richard.
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.
Index: gcc/tree-ssa-sccvn.c
===================================================================
*** gcc/tree-ssa-sccvn.c.orig 2008-07-29 15:43:41.000000000 +0200
--- gcc/tree-ssa-sccvn.c 2008-07-29 18:10:27.000000000 +0200
*************** shared_vuses_from_stmt (gimple stmt)
*** 557,563 ****
/* Copy the operations present in load/store REF into RESULT, a vector of
vn_reference_op_s's. */
! static void
copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
{
if (TREE_CODE (ref) == TARGET_MEM_REF)
--- 557,563 ----
/* Copy the operations present in load/store REF into RESULT, a vector of
vn_reference_op_s's. */
! void
copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
{
if (TREE_CODE (ref) == TARGET_MEM_REF)
*************** copy_reference_ops_from_ref (tree ref, V
*** 646,651 ****
--- 646,658 ----
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
*************** copy_reference_ops_from_ref (tree ref, V
*** 654,668 ****
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)
ref = TREE_OPERAND (ref, 0);
else
ref = NULL_TREE;
--- 661,675 ----
case IMAGPART_EXPR:
case REALPART_EXPR:
case VIEW_CONVERT_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
! && !is_gimple_min_invariant (ref)))
ref = TREE_OPERAND (ref, 0);
else
ref = NULL_TREE;
*************** copy_reference_ops_from_call (gimple cal
*** 677,683 ****
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
--- 684,689 ----
*************** copy_reference_ops_from_call (gimple cal
*** 685,717 ****
memset (&temp, 0, sizeof (temp));
temp.type = gimple_call_return_type (call);
temp.opcode = CALL_EXPR;
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);
!
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);
}
return;
}
--- 691,705 ----
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);
! /* 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);
! copy_reference_ops_from_ref (callarg, result);
}
return;
}
Index: gcc/tree-ssa-pre.c
===================================================================
*** gcc/tree-ssa-pre.c.orig 2008-07-29 15:43:41.000000000 +0200
--- gcc/tree-ssa-pre.c 2008-07-29 18:10:27.000000000 +0200
*************** static VEC(gimple,heap) *inserted_exprs;
*** 2421,2484 ****
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.
!
! 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)
{
vn_reference_op_t currop = VEC_index (vn_reference_op_s, ref->operands,
! operand);
tree genop;
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++)
{
! args[i] = create_component_ref_by_pieces (block, ref,
! operand + 2 + i, stmts,
! domstmt, true);
}
folded = build_call_array (currop->type,
! TREE_CODE (declop->op0) == FUNCTION_DECL
! ? build_fold_addr_expr (declop->op0)
! : declop->op0,
nargs, args);
free (args);
return folded;
}
break;
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);
if (!genop0)
return NULL_TREE;
folded = fold_build1 (currop->opcode, currop->type,
--- 2421,2476 ----
to see which expressions need to be put into GC'able memory */
static VEC(gimple, heap) *need_creation;
! /* The actual worker for create_component_ref_by_pieces. */
static tree
! 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);
tree genop;
+ ++*operand;
switch (currop->opcode)
{
case CALL_EXPR:
{
tree folded;
! 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[nargs] = create_component_ref_by_pieces_1 (block, ref,
! operand, stmts,
! domstmt);
! nargs++;
}
folded = build_call_array (currop->type,
! 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_1 (block, ref,
! operand,
! stmts, domstmt);
if (!genop0)
return NULL_TREE;
folded = fold_build1 (currop->opcode, currop->type,
*************** create_component_ref_by_pieces (basic_bl
*** 2490,2534 ****
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 (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;
! }
}
break;
case BIT_FIELD_REF:
{
tree folded;
! tree genop0 = create_component_ref_by_pieces (block, ref, operand + 1,
! stmts, domstmt,
! in_call);
pre_expr op1expr = get_or_alloc_expr_for (currop->op0);
pre_expr op2expr = get_or_alloc_expr_for (currop->op1);
tree genop1;
--- 2482,2506 ----
case MISALIGNED_INDIRECT_REF:
case INDIRECT_REF:
{
! 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);
! folded = fold_build1 (currop->opcode, currop->type,
! genop1);
! return folded;
}
break;
case BIT_FIELD_REF:
{
tree folded;
! 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;
*************** create_component_ref_by_pieces (basic_bl
*** 2553,2569 ****
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);
if (!genop0)
return NULL_TREE;
op1expr = get_or_alloc_expr_for (genop1);
--- 2525,2538 ----
case ARRAY_RANGE_REF:
case ARRAY_REF:
{
tree genop0;
tree genop1 = currop->op0;
pre_expr op1expr;
tree genop2 = currop->op1;
pre_expr op2expr;
tree genop3;
! genop0 = create_component_ref_by_pieces_1 (block, ref, operand,
! stmts, domstmt);
if (!genop0)
return NULL_TREE;
op1expr = get_or_alloc_expr_for (genop1);
*************** create_component_ref_by_pieces (basic_bl
*** 2589,2596 ****
tree op1;
tree genop2 = currop->op1;
pre_expr op2expr;
! op0 = create_component_ref_by_pieces (block, ref, operand + 1,
! stmts, domstmt, in_call);
if (!op0)
return NULL_TREE;
/* op1 should be a FIELD_DECL, which are represented by
--- 2558,2565 ----
tree op1;
tree genop2 = currop->op1;
pre_expr op2expr;
! 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
*************** create_component_ref_by_pieces (basic_bl
*** 2626,2636 ****
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:
--- 2595,2600 ----
*************** create_component_ref_by_pieces (basic_bl
*** 2638,2643 ****
--- 2602,2627 ----
}
}
+ /* 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.
*************** create_expression_by_pieces (basic_block
*** 2743,2750 ****
case REFERENCE:
{
vn_reference_t ref = PRE_EXPR_REFERENCE (expr);
! folded = create_component_ref_by_pieces (block, ref, 0, stmts,
! domstmt, false);
}
break;
case NARY:
--- 2727,2733 ----
case REFERENCE:
{
vn_reference_t ref = PRE_EXPR_REFERENCE (expr);
! folded = create_component_ref_by_pieces (block, ref, stmts, domstmt);
}
break;
case NARY:
*************** compute_avail (void)
*** 3616,3621 ****
--- 3599,3606 ----
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;
*************** compute_avail (void)
*** 3688,3693 ****
--- 3673,3680 ----
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;
Index: gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-18.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-18.c 2008-07-29 18:10:27.000000000 +0200
***************
*** 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" } } */
Index: gcc/tree-ssa-sccvn.h
===================================================================
*** gcc/tree-ssa-sccvn.h.orig 2008-07-29 18:10:06.000000000 +0200
--- gcc/tree-ssa-sccvn.h 2008-07-29 18:10:27.000000000 +0200
*************** vn_nary_op_t vn_nary_op_insert_stmt (gim
*** 174,179 ****
--- 174,180 ----
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) *,
More information about the Gcc-patches
mailing list