This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR40022
- From: Richard Guenther <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 5 May 2009 15:20:01 +0200 (CEST)
- Subject: [PATCH] Fix PR40022
This fixes PR40022, a tuplification error in the phiprop pass. While
fixing it I took the opportunity to clean it up somewhat and add
some dumping to it for the 4.5 variant of the patch.
Bootstrapped and tested on x86_64-unknown-linux-gnu, the 4.4 variant
is still testing. Will apply after both have succeeded.
Richard.
2009-05-05 Richard Guenther <rguenther@suse.de>
PR tree-optimization/40022
* tree-ssa-phiprop.c (struct phiprop_d): Exchange vop_stmt for
the only vuse.
(phivn_valid_p): Fix tuplification error, simplify.
(phiprop_insert_phi): Add dumps.
(propagate_with_phi): Simplify.
* gcc.c-torture/execute/pr40022.c: New testcase.
Index: gcc/testsuite/gcc.c-torture/execute/pr40022.c
===================================================================
*** gcc/testsuite/gcc.c-torture/execute/pr40022.c (revision 0)
--- gcc/testsuite/gcc.c-torture/execute/pr40022.c (revision 0)
***************
*** 0 ****
--- 1,51 ----
+ extern void abort (void);
+
+ struct A
+ {
+ struct A *a;
+ };
+
+ struct B
+ {
+ struct A *b;
+ };
+
+ __attribute__((noinline))
+ struct A *
+ foo (struct A *x)
+ {
+ asm volatile ("" : : "g" (x) : "memory");
+ return x;
+ }
+
+ __attribute__((noinline))
+ void
+ bar (struct B *w, struct A *x, struct A *y, struct A *z)
+ {
+ struct A **c;
+ c = &w->b;
+ *c = foo (x);
+ while (*c)
+ c = &(*c)->a;
+ *c = foo (y);
+ while (*c)
+ c = &(*c)->a;
+ *c = foo (z);
+ }
+
+ struct B d;
+ struct A e, f, g;
+
+ int
+ main (void)
+ {
+ f.a = &g;
+ bar (&d, &e, &f, 0);
+ if (d.b == 0
+ || d.b->a == 0
+ || d.b->a->a == 0
+ || d.b->a->a->a != 0)
+ abort ();
+ return 0;
+ }
+
Index: gcc/tree-ssa-phiprop.c
===================================================================
*** gcc/tree-ssa-phiprop.c (revision 147093)
--- gcc/tree-ssa-phiprop.c (working copy)
*************** along with GCC; see the file COPYING3.
*** 90,101 ****
/* Structure to keep track of the value of a dereferenced PHI result
! and the set of virtual operands used for that dereference. */
struct phiprop_d
{
tree value;
! gimple vop_stmt;
};
/* Verify if the value recorded for NAME in PHIVN is still valid at
--- 90,101 ----
/* Structure to keep track of the value of a dereferenced PHI result
! and the virtual operand used for that dereference. */
struct phiprop_d
{
tree value;
! tree vuse;
};
/* Verify if the value recorded for NAME in PHIVN is still valid at
*************** struct phiprop_d
*** 104,137 ****
static bool
phivn_valid_p (struct phiprop_d *phivn, tree name, basic_block bb)
{
! gimple vop_stmt = phivn[SSA_NAME_VERSION (name)].vop_stmt;
! tree vuse;
! /* The def stmts of all virtual uses need to be post-dominated
! by bb. */
! if ((vuse = gimple_vuse (vop_stmt)))
{
! gimple use_stmt;
! imm_use_iterator ui2;
! bool ok = true;
!
! FOR_EACH_IMM_USE_STMT (use_stmt, ui2, vuse)
! {
! /* If BB does not dominate a VDEF, the value is invalid. */
! if (((is_gimple_assign (use_stmt)
! && gimple_vdef (use_stmt))
! || gimple_code (use_stmt) == GIMPLE_PHI)
! && !dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt), bb))
! {
! ok = false;
! BREAK_FROM_IMM_USE_STMT (ui2);
! }
}
- if (!ok)
- return false;
}
! return true;
}
/* Insert a new phi node for the dereference of PHI at basic_block
--- 104,130 ----
static bool
phivn_valid_p (struct phiprop_d *phivn, tree name, basic_block bb)
{
! tree vuse = phivn[SSA_NAME_VERSION (name)].vuse;
! gimple use_stmt;
! imm_use_iterator ui2;
! bool ok = true;
! /* The def stmts of the virtual uses need to be dominated by bb. */
! gcc_assert (vuse != NULL_TREE);
!
! FOR_EACH_IMM_USE_STMT (use_stmt, ui2, vuse)
{
! /* If BB does not dominate a VDEF, the value is invalid. */
! if ((gimple_vdef (use_stmt) != NULL_TREE
! || gimple_code (use_stmt) == GIMPLE_PHI)
! && !dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt), bb))
! {
! ok = false;
! BREAK_FROM_IMM_USE_STMT (ui2);
}
}
! return ok;
}
/* Insert a new phi node for the dereference of PHI at basic_block
*************** phiprop_insert_phi (basic_block bb, gimp
*** 154,159 ****
--- 147,158 ----
res = gimple_assign_lhs (use_stmt);
SSA_NAME_DEF_STMT (res) = new_phi = create_phi_node (res, bb);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Inserting PHI for result of load ");
+ print_gimple_stmt (dump_file, use_stmt, 0, 0);
+ }
+
/* Add PHI arguments for each edge inserting loads of the
addressable operands. */
FOR_EACH_EDGE (e, ei, bb->preds)
*************** phiprop_insert_phi (basic_block bb, gimp
*** 171,178 ****
}
if (TREE_CODE (old_arg) == SSA_NAME)
! /* Reuse a formerly created dereference. */
! new_var = phivn[SSA_NAME_VERSION (old_arg)].value;
else
{
gcc_assert (TREE_CODE (old_arg) == ADDR_EXPR);
--- 170,188 ----
}
if (TREE_CODE (old_arg) == SSA_NAME)
! {
! if (dump_file && (dump_flags & TDF_DETAILS))
! {
! fprintf (dump_file, " for edge defining ");
! print_generic_expr (dump_file, PHI_ARG_DEF_FROM_EDGE (phi, e), 0);
! fprintf (dump_file, " reusing PHI result ");
! print_generic_expr (dump_file,
! phivn[SSA_NAME_VERSION (old_arg)].value, 0);
! fprintf (dump_file, "\n");
! }
! /* Reuse a formerly created dereference. */
! new_var = phivn[SSA_NAME_VERSION (old_arg)].value;
! }
else
{
gcc_assert (TREE_CODE (old_arg) == ADDR_EXPR);
*************** phiprop_insert_phi (basic_block bb, gimp
*** 188,196 ****
gimple_assign_set_lhs (tmp, new_var);
gsi_insert_on_edge (e, tmp);
-
update_stmt (tmp);
! mark_symbols_for_renaming (tmp);
}
add_phi_arg (new_phi, new_var, e);
--- 198,212 ----
gimple_assign_set_lhs (tmp, new_var);
gsi_insert_on_edge (e, tmp);
update_stmt (tmp);
!
! if (dump_file && (dump_flags & TDF_DETAILS))
! {
! fprintf (dump_file, " for edge defining ");
! print_generic_expr (dump_file, PHI_ARG_DEF_FROM_EDGE (phi, e), 0);
! fprintf (dump_file, " inserting load ");
! print_gimple_stmt (dump_file, tmp, 0, 0);
! }
}
add_phi_arg (new_phi, new_var, e);
*************** phiprop_insert_phi (basic_block bb, gimp
*** 198,203 ****
--- 214,222 ----
update_stmt (new_phi);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ print_gimple_stmt (dump_file, new_phi, 0, 0);
+
return res;
}
*************** propagate_with_phi (basic_block bb, gimp
*** 270,275 ****
--- 289,295 ----
phi_inserted = false;
FOR_EACH_IMM_USE_STMT (use_stmt, ui, ptr)
{
+ gimple def_stmt;
tree vuse;
/* Check whether this is a load of *ptr. */
*************** propagate_with_phi (basic_block bb, gimp
*** 281,297 ****
&& !stmt_can_throw_internal (use_stmt)))
continue;
! /* Check if we can move the loads. The def stmts of all virtual uses
! need to be post-dominated by bb. */
! if ((vuse = gimple_vuse (use_stmt)) != NULL_TREE)
! {
! gimple def_stmt = SSA_NAME_DEF_STMT (vuse);
! if (!SSA_NAME_IS_DEFAULT_DEF (vuse)
! && (gimple_bb (def_stmt) == bb
! || !dominated_by_p (CDI_DOMINATORS,
! bb, gimple_bb (def_stmt))))
! goto next;
! }
/* Found a proper dereference. Insert a phi node if this
is the first load transformation. */
--- 301,315 ----
&& !stmt_can_throw_internal (use_stmt)))
continue;
! /* Check if we can move the loads. The def stmt of the virtual use
! needs to be in a different basic block post-dominated by bb
! (which it is if the def stmt is not a PHI node). */
! vuse = gimple_vuse (use_stmt);
! def_stmt = SSA_NAME_DEF_STMT (vuse);
! if (!SSA_NAME_IS_DEFAULT_DEF (vuse)
! && (gimple_code (def_stmt) == GIMPLE_PHI
! || gimple_bb (def_stmt) == bb))
! goto next;
/* Found a proper dereference. Insert a phi node if this
is the first load transformation. */
*************** propagate_with_phi (basic_block bb, gimp
*** 301,307 ****
/* Remember the value we created for *ptr. */
phivn[SSA_NAME_VERSION (ptr)].value = res;
! phivn[SSA_NAME_VERSION (ptr)].vop_stmt = use_stmt;
/* Remove old stmt. The phi is taken care of by DCE, if we
want to delete it here we also have to delete all intermediate
--- 319,325 ----
/* Remember the value we created for *ptr. */
phivn[SSA_NAME_VERSION (ptr)].value = res;
! phivn[SSA_NAME_VERSION (ptr)].vuse = vuse;
/* Remove old stmt. The phi is taken care of by DCE, if we
want to delete it here we also have to delete all intermediate
2009-05-05 Richard Guenther <rguenther@suse.de>
PR tree-optimization/40022
* tree-ssa-phiprop.c (phivn_valid_p): Fix tuplification error.
* gcc.c-torture/execute/pr40022.c: New testcase.
Index: gcc/tree-ssa-phiprop.c
===================================================================
*** gcc/tree-ssa-phiprop.c (revision 147123)
--- gcc/tree-ssa-phiprop.c (working copy)
*************** phivn_valid_p (struct phiprop_d *phivn,
*** 119,126 ****
FOR_EACH_IMM_USE_STMT (use_stmt, ui2, vuse)
{
/* If BB does not dominate a VDEF, the value is invalid. */
! if (((is_gimple_assign (use_stmt)
! && !ZERO_SSA_OPERANDS (use_stmt, SSA_OP_VDEF))
|| gimple_code (use_stmt) == GIMPLE_PHI)
&& !dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt), bb))
{
--- 119,125 ----
FOR_EACH_IMM_USE_STMT (use_stmt, ui2, vuse)
{
/* If BB does not dominate a VDEF, the value is invalid. */
! if ((!ZERO_SSA_OPERANDS (use_stmt, SSA_OP_VDEF)
|| gimple_code (use_stmt) == GIMPLE_PHI)
&& !dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt), bb))
{
Index: gcc/testsuite/gcc.c-torture/execute/pr40022.c
===================================================================
*** gcc/testsuite/gcc.c-torture/execute/pr40022.c (revision 0)
--- gcc/testsuite/gcc.c-torture/execute/pr40022.c (revision 0)
***************
*** 0 ****
--- 1,51 ----
+ extern void abort (void);
+
+ struct A
+ {
+ struct A *a;
+ };
+
+ struct B
+ {
+ struct A *b;
+ };
+
+ __attribute__((noinline))
+ struct A *
+ foo (struct A *x)
+ {
+ asm volatile ("" : : "g" (x) : "memory");
+ return x;
+ }
+
+ __attribute__((noinline))
+ void
+ bar (struct B *w, struct A *x, struct A *y, struct A *z)
+ {
+ struct A **c;
+ c = &w->b;
+ *c = foo (x);
+ while (*c)
+ c = &(*c)->a;
+ *c = foo (y);
+ while (*c)
+ c = &(*c)->a;
+ *c = foo (z);
+ }
+
+ struct B d;
+ struct A e, f, g;
+
+ int
+ main (void)
+ {
+ f.a = &g;
+ bar (&d, &e, &f, 0);
+ if (d.b == 0
+ || d.b->a == 0
+ || d.b->a->a == 0
+ || d.b->a->a->a != 0)
+ abort ();
+ return 0;
+ }
+