diff options
-rw-r--r-- | gcc/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/gimple.c | 5 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/torture/pr40389.C | 84 | ||||
-rw-r--r-- | gcc/tree-ssa-structalias.c | 57 |
5 files changed, 147 insertions, 19 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0fe65b2..264e5cc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2009-06-14 Richard Guenther <rguenther@suse.de> + + PR middle-end/40389 + * gimple.c (walk_stmt_load_store_addr_ops): The LHS of a call + has its address taken if NRV was applied and it is addressable. + * tree-ssa-structalias.c (get_constraint_for_address_of): New + function split out from ... + (get_constraint_for_1): ... here. + (handle_rhs_call): Use it to mark the return slot escaped if + it is addressable and NRV was applied. + 2009-06-13 Aldy Hernandez <aldyh@redhat.com> * config/rs6000/rs6000-protos.h (altivec_resolve_overloaded_builtin): @@ -8,7 +19,7 @@ 2009-06-13 Richard Guenther <rguenther@suse.de> - PR tree-optimization/40389 + PR tree-optimization/40421 * tree-predcom.c (should_unroll_loop_p): Remove. (tree_predictive_commoning_loop): Use can_unroll_loop_p. diff --git a/gcc/gimple.c b/gcc/gimple.c index d3578da..24727bc 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -3264,6 +3264,11 @@ walk_stmt_load_store_addr_ops (gimple stmt, void *data, && TREE_CODE (gimple_call_chain (stmt)) == ADDR_EXPR) ret |= visit_addr (stmt, TREE_OPERAND (gimple_call_chain (stmt), 0), data); + if (visit_addr + && gimple_call_return_slot_opt_p (stmt) + && gimple_call_lhs (stmt) != NULL_TREE + && TREE_ADDRESSABLE (gimple_call_lhs (stmt))) + ret |= visit_addr (stmt, gimple_call_lhs (stmt), data); } else if (gimple_code (stmt) == GIMPLE_ASM) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4461910..4b7d929 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,6 +1,11 @@ +2009-06-14 Richard Guenther <rguenther@suse.de> + + PR middle-end/40389 + * g++.dg/torture/pr40389.C: New testcase. + 2009-06-13 Richard Guenther <rguenther@suse.de> - PR tree-optimization/40389 + PR tree-optimization/40421 * gfortran.fortran-torture/compile/pr40421.f: New testcase. 2009-06-12 Aldy Hernandez <aldyh@redhat.com> diff --git a/gcc/testsuite/g++.dg/torture/pr40389.C b/gcc/testsuite/g++.dg/torture/pr40389.C new file mode 100644 index 0000000..e3ceb12 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr40389.C @@ -0,0 +1,84 @@ +/* { dg-do run } */ + +template <typename V> struct S +{ + V *f, *l; + __attribute__ ((noinline)) S (void) { f = 0, l = 0; } + void foo (V *x) + { + if (x->p != 0) + x->p->n = x->n; + else + f = x->n; + if (x->n != 0) + x->n->p = x->p; + else + l = x->p; + } + __attribute__ ((noinline)) void bar (V *x) + { + x->n = 0; + x->p = l; + if (l != 0) + l->n = x; + else + f = x; + l = x; + } +}; + +struct H; + +struct A +{ + S <H> k; +}; + +struct H +{ + A *a; + H *p, *n; + __attribute__ ((noinline)) H (void) { p = 0, n = 0, a = 0; } + __attribute__ ((noinline)) H (A *b) : a (b) + { + p = 0; + n = 0; + if (a != 0) + a->k.bar (this); + } + __attribute__ ((noinline)) H (const H &h) : a (h.a) + { + p = 0; + n = 0; + if (a != 0) + a->k.bar (this); + } + ~H (void) { if (a != 0) a->k.foo (this); } + H &operator= (const H &o) + { + if (a != 0 || &o == this) + __builtin_abort (); + a = o.a; + if (a != 0) + a->k.bar (this); + return *this; + } +}; + +__attribute__ ((noinline)) +H baz (void) +{ + return H (new A); +} + +H g; + +int +main (void) +{ + g = baz (); + if (g.a->k.f != &g) + __builtin_abort (); + return 0; +} + diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index 827a916..7c95de4 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -3080,6 +3080,28 @@ do_deref (VEC (ce_s, heap) **constraints) } } +static void get_constraint_for_1 (tree, VEC (ce_s, heap) **, bool); + +/* Given a tree T, return the constraint expression for taking the + address of it. */ + +static void +get_constraint_for_address_of (tree t, VEC (ce_s, heap) **results) +{ + struct constraint_expr *c; + unsigned int i; + + get_constraint_for_1 (t, results, true); + + for (i = 0; VEC_iterate (ce_s, *results, i, c); i++) + { + if (c->type == DEREF) + c->type = SCALAR; + else + c->type = ADDRESSOF; + } +} + /* Given a tree T, return the constraint expression for it. */ static void @@ -3131,23 +3153,8 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p) switch (TREE_CODE (t)) { case ADDR_EXPR: - { - struct constraint_expr *c; - unsigned int i; - tree exp = TREE_OPERAND (t, 0); - - get_constraint_for_1 (exp, results, true); - - for (i = 0; VEC_iterate (ce_s, *results, i, c); i++) - { - if (c->type == DEREF) - c->type = SCALAR; - else - c->type = ADDRESSOF; - } - return; - } - break; + get_constraint_for_address_of (TREE_OPERAND (t, 0), results); + return; default:; } break; @@ -3333,6 +3340,22 @@ handle_rhs_call (gimple stmt, VEC(ce_s, heap) **results) if (gimple_call_chain (stmt)) make_escape_constraint (gimple_call_chain (stmt)); + /* And if we applied NRV the address of the return slot escapes as well. */ + if (gimple_call_return_slot_opt_p (stmt) + && gimple_call_lhs (stmt) != NULL_TREE + && TREE_ADDRESSABLE (gimple_call_lhs (stmt))) + { + VEC(ce_s, heap) *tmpc = NULL; + struct constraint_expr lhsc, *c; + get_constraint_for_address_of (gimple_call_lhs (stmt), &tmpc); + lhsc.var = escaped_id; + lhsc.offset = 0; + lhsc.type = SCALAR; + for (i = 0; VEC_iterate (ce_s, tmpc, i, c); ++i) + process_constraint (new_constraint (lhsc, *c)); + VEC_free(ce_s, heap, tmpc); + } + /* Regular functions return nonlocal memory. */ rhsc.var = nonlocal_id; rhsc.offset = 0; |