diff options
author | Richard Guenther <rguenther@suse.de> | 2009-03-27 22:36:33 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2009-03-27 22:36:33 +0000 |
commit | 472c7fbd0979129313e49c2fb73ff5b36d4b1d57 (patch) | |
tree | 6d9ebbc1d407783c84648954b0a8422eb2e7ad5c /gcc | |
parent | d9223014f991d207719b03fca8d8433edc58f27a (diff) | |
download | gcc-472c7fbd0979129313e49c2fb73ff5b36d4b1d57.zip gcc-472c7fbd0979129313e49c2fb73ff5b36d4b1d57.tar.gz gcc-472c7fbd0979129313e49c2fb73ff5b36d4b1d57.tar.bz2 |
re PR tree-optimization/39120 (Missed escape constraints for call results)
2009-03-27 Richard Guenther <rguenther@suse.de>
PR tree-optimization/39120
* tree-ssa-structalias.c (handle_rhs_call): Fill out return
constraints.
(handle_lhs_call): Process return constraints. Add escape
constraints if necessary.
(handle_const_call): Fill out return constraints. Make nested
case more precise. Avoid consttmp if possible.
(handle_pure_call): Fill out return constraints. Avoid
callused if possible.
(find_func_aliases): Simplify call handling.
* gcc.c-torture/execute/pr39120.c: New testcase.
2009-03-27 Richard Guenther <rguenther@suse.de>
PR tree-optimization/39120
* tree-ssa-structalias.c (do_sd_constraint): Do not use CALLUSED
as a representative.
(solve_graph): Do propagate CALLUSED.
(handle_pure_call): Use a scalar constraint from CALLUSED for
the return value.
(find_what_p_points_to): CALLUSED shall not appear in poins-to
solutions.
* gcc.dg/torture/pta-callused-1.c: New testcase.
From-SVN: r145137
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 24 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/pr39120.c | 18 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/pta-callused-1.c | 25 | ||||
-rw-r--r-- | gcc/tree-ssa-structalias.c | 194 |
5 files changed, 170 insertions, 101 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9ea8830..7fd95bc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2009-03-27 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/39120 + * tree-ssa-structalias.c (handle_rhs_call): Fill out return + constraints. + (handle_lhs_call): Process return constraints. Add escape + constraints if necessary. + (handle_const_call): Fill out return constraints. Make nested + case more precise. Avoid consttmp if possible. + (handle_pure_call): Fill out return constraints. Avoid + callused if possible. + (find_func_aliases): Simplify call handling. + +2009-03-27 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/39120 + * tree-ssa-structalias.c (do_sd_constraint): Do not use CALLUSED + as a representative. + (solve_graph): Do propagate CALLUSED. + (handle_pure_call): Use a scalar constraint from CALLUSED for + the return value. + (find_what_p_points_to): CALLUSED shall not appear in poins-to + solutions. + 2009-03-27 H.J. Lu <hongjiu.lu@intel.com> PR c/39323 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 269c540..5fea6b9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2009-03-27 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/39120 + * gcc.c-torture/execute/pr39120.c: New testcase. + +2009-03-27 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/39120 + * gcc.dg/torture/pta-callused-1.c: New testcase. + 2009-03-27 H.J. Lu <hongjiu.lu@intel.com> PR c/39323 diff --git a/gcc/testsuite/gcc.c-torture/execute/pr39120.c b/gcc/testsuite/gcc.c-torture/execute/pr39120.c new file mode 100644 index 0000000..8859848 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr39120.c @@ -0,0 +1,18 @@ +struct X { int *p; } x; + +struct X __attribute__((noinline)) +foo(int *p) { struct X x; x.p = p; return x; } + +void __attribute((noinline)) +bar() { *x.p = 1; } + +extern void abort (void); +int main() +{ + int i = 0; + x = foo(&i); + bar(); + if (i != 1) + abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pta-callused-1.c b/gcc/testsuite/gcc.dg/torture/pta-callused-1.c new file mode 100644 index 0000000..dfe994b --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pta-callused-1.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-fdump-tree-alias" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */ + +volatile int i; +int ** __attribute__((noinline,pure)) foo(int **p) { i; return p; } +int bar(void) +{ + int i = 0, j = 1; + int *p, **q; + p = &i; + q = foo(&p); + *q = &j; + return *p; +} +extern void abort (void); +int main() +{ + if (bar() != 1) + abort (); + return 0; +} + +/* { dg-final { scan-tree-dump "p.._., name memory tag: NMT..., is dereferenced, points-to vars: { i j }" "alias" } } */ +/* { dg-final { cleanup-tree-dump "alias" } } */ diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index 384fe18..32e25a2 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -1592,12 +1592,9 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c, if (get_varinfo (t)->is_special_var) flag |= bitmap_ior_into (sol, get_varinfo (t)->solution); /* Merging the solution from ESCAPED needlessly increases - the set. Use ESCAPED as representative instead. - Same for CALLUSED. */ + the set. Use ESCAPED as representative instead. */ else if (get_varinfo (t)->id == find (escaped_id)) flag |= bitmap_set_bit (sol, escaped_id); - else if (get_varinfo (t)->id == find (callused_id)) - flag |= bitmap_set_bit (sol, callused_id); else if (add_graph_edge (graph, lhs, t)) flag |= bitmap_ior_into (sol, get_varinfo (t)->solution); } @@ -2516,9 +2513,8 @@ solve_graph (constraint_graph_t graph) solution_empty = bitmap_empty_p (solution); if (!solution_empty - /* Do not propagate the ESCAPED/CALLUSED solutions. */ - && i != find (escaped_id) - && i != find (callused_id)) + /* Do not propagate the ESCAPED solutions. */ + && i != find (escaped_id)) { bitmap_iterator bi; @@ -3488,8 +3484,9 @@ make_escape_constraint (tree op) RHS. */ static void -handle_rhs_call (gimple stmt) +handle_rhs_call (gimple stmt, VEC(ce_s, heap) **results) { + struct constraint_expr rhsc; unsigned i; for (i = 0; i < gimple_call_num_args (stmt); ++i) @@ -3505,6 +3502,12 @@ handle_rhs_call (gimple stmt) /* The static chain escapes as well. */ if (gimple_call_chain (stmt)) make_escape_constraint (gimple_call_chain (stmt)); + + /* Regular functions return escaped addresses. */ + rhsc.var = escaped_id; + rhsc.offset = 0; + rhsc.type = ADDRESSOF; + VEC_safe_push (ce_s, heap, *results, &rhsc); } /* For non-IPA mode, generate constraints necessary for a call @@ -3512,10 +3515,9 @@ handle_rhs_call (gimple stmt) the LHS point to global and escaped variables. */ static void -handle_lhs_call (tree lhs, int flags) +handle_lhs_call (tree lhs, int flags, VEC(ce_s, heap) *rhsc) { VEC(ce_s, heap) *lhsc = NULL; - struct constraint_expr rhsc; unsigned int j; struct constraint_expr *lhsp; @@ -3523,6 +3525,7 @@ handle_lhs_call (tree lhs, int flags) if (flags & ECF_MALLOC) { + struct constraint_expr rhsc; tree heapvar = heapvar_lookup (lhs); varinfo_t vi; @@ -3546,15 +3549,30 @@ handle_lhs_call (tree lhs, int flags) vi->size = ~0; rhsc.type = ADDRESSOF; rhsc.offset = 0; + for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) + process_constraint (new_constraint (*lhsp, rhsc)); } - else + else if (VEC_length (ce_s, rhsc) > 0) { - rhsc.var = escaped_id; - rhsc.offset = 0; - rhsc.type = ADDRESSOF; + struct constraint_expr *lhsp, *rhsp; + unsigned int i, j; + /* If the store is to a global decl make sure to + add proper escape constraints. */ + lhs = get_base_address (lhs); + if (lhs + && DECL_P (lhs) + && is_global_var (lhs)) + { + struct constraint_expr tmpc; + tmpc.var = escaped_id; + tmpc.offset = 0; + tmpc.type = SCALAR; + VEC_safe_push (ce_s, heap, lhsc, &tmpc); + } + for (i = 0; VEC_iterate (ce_s, lhsc, i, lhsp); ++i) + for (j = 0; VEC_iterate (ce_s, rhsc, j, rhsp); ++j) + process_constraint (new_constraint (*lhsp, *rhsp)); } - for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) - process_constraint (new_constraint (*lhsp, rhsc)); VEC_free (ce_s, heap, lhsc); } @@ -3562,43 +3580,23 @@ handle_lhs_call (tree lhs, int flags) const function that returns a pointer in the statement STMT. */ static void -handle_const_call (gimple stmt) +handle_const_call (gimple stmt, VEC(ce_s, heap) **results) { - tree lhs = gimple_call_lhs (stmt); - VEC(ce_s, heap) *lhsc = NULL; - struct constraint_expr rhsc; - unsigned int j, k; - struct constraint_expr *lhsp; - tree tmpvar; - struct constraint_expr tmpc; + struct constraint_expr rhsc, tmpc; + tree tmpvar = NULL_TREE; + unsigned int k; - get_constraint_for (lhs, &lhsc); - - /* If this is a nested function then it can return anything. */ + /* Treat nested const functions the same as pure functions as far + as the static chain is concerned. */ if (gimple_call_chain (stmt)) { - rhsc.var = anything_id; + make_constraint_to (callused_id, gimple_call_chain (stmt)); + rhsc.var = callused_id; rhsc.offset = 0; - rhsc.type = ADDRESSOF; - for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) - process_constraint (new_constraint (*lhsp, rhsc)); - VEC_free (ce_s, heap, lhsc); - return; + rhsc.type = SCALAR; + VEC_safe_push (ce_s, heap, *results, &rhsc); } - /* We always use a temporary here, otherwise we end up with a quadratic - amount of constraints for - large_struct = const_call (large_struct); - in field-sensitive PTA. */ - tmpvar = create_tmp_var_raw (ptr_type_node, "consttmp"); - tmpc = get_constraint_exp_for_temp (tmpvar); - - /* May return addresses of globals. */ - rhsc.var = nonlocal_id; - rhsc.offset = 0; - rhsc.type = ADDRESSOF; - process_constraint (new_constraint (tmpc, rhsc)); - /* May return arguments. */ for (k = 0; k < gimple_call_num_args (stmt); ++k) { @@ -3610,26 +3608,41 @@ handle_const_call (gimple stmt) struct constraint_expr *argp; int i; + /* We always use a temporary here, otherwise we end up with + a quadratic amount of constraints for + large_struct = const_call (large_struct); + with field-sensitive PTA. */ + if (tmpvar == NULL_TREE) + { + tmpvar = create_tmp_var_raw (ptr_type_node, "consttmp"); + tmpc = get_constraint_exp_for_temp (tmpvar); + } + get_constraint_for (arg, &argc); for (i = 0; VEC_iterate (ce_s, argc, i, argp); i++) process_constraint (new_constraint (tmpc, *argp)); VEC_free (ce_s, heap, argc); } } + if (tmpvar != NULL_TREE) + VEC_safe_push (ce_s, heap, *results, &tmpc); - for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) - process_constraint (new_constraint (*lhsp, tmpc)); - - VEC_free (ce_s, heap, lhsc); + /* May return addresses of globals. */ + rhsc.var = nonlocal_id; + rhsc.offset = 0; + rhsc.type = ADDRESSOF; + VEC_safe_push (ce_s, heap, *results, &rhsc); } /* For non-IPA mode, generate constraints necessary for a call to a pure function in statement STMT. */ static void -handle_pure_call (gimple stmt) +handle_pure_call (gimple stmt, VEC(ce_s, heap) **results) { + struct constraint_expr rhsc; unsigned i; + bool need_callused = false; /* Memory reached from pointer arguments is call-used. */ for (i = 0; i < gimple_call_num_args (stmt); ++i) @@ -3637,48 +3650,31 @@ handle_pure_call (gimple stmt) tree arg = gimple_call_arg (stmt, i); if (could_have_pointers (arg)) - make_constraint_to (callused_id, arg); + { + make_constraint_to (callused_id, arg); + need_callused = true; + } } /* The static chain is used as well. */ if (gimple_call_chain (stmt)) - make_constraint_to (callused_id, gimple_call_chain (stmt)); - - /* If the call returns a pointer it may point to reachable memory - from the arguments. Not so for malloc functions though. */ - if (gimple_call_lhs (stmt) - && could_have_pointers (gimple_call_lhs (stmt)) - && !(gimple_call_flags (stmt) & ECF_MALLOC)) { - tree lhs = gimple_call_lhs (stmt); - VEC(ce_s, heap) *lhsc = NULL; - struct constraint_expr rhsc; - struct constraint_expr *lhsp; - unsigned j; - - get_constraint_for (lhs, &lhsc); - - /* If this is a nested function then it can return anything. */ - if (gimple_call_chain (stmt)) - { - rhsc.var = anything_id; - rhsc.offset = 0; - rhsc.type = ADDRESSOF; - for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) - process_constraint (new_constraint (*lhsp, rhsc)); - VEC_free (ce_s, heap, lhsc); - return; - } + make_constraint_to (callused_id, gimple_call_chain (stmt)); + need_callused = true; + } - /* Else just add the call-used memory here. Escaped variables - and globals will be dealt with in handle_lhs_call. */ + /* Pure functions may return callused and escaped memory. */ + if (need_callused) + { rhsc.var = callused_id; rhsc.offset = 0; - rhsc.type = ADDRESSOF; - for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) - process_constraint (new_constraint (*lhsp, rhsc)); - VEC_free (ce_s, heap, lhsc); + rhsc.type = SCALAR; + VEC_safe_push (ce_s, heap, *results, &rhsc); } + rhsc.var = escaped_id; + rhsc.offset = 0; + rhsc.type = ADDRESSOF; + VEC_safe_push (ce_s, heap, *results, &rhsc); } /* Walk statement T setting up aliasing constraints according to the @@ -3743,33 +3739,28 @@ find_func_aliases (gimple origt) { if (!in_ipa_mode) { + VEC(ce_s, heap) *rhsc = NULL; int flags = gimple_call_flags (t); /* Const functions can return their arguments and addresses of global memory but not of escaped memory. */ - if (flags & ECF_CONST) + if (flags & (ECF_CONST|ECF_NOVOPS)) { if (gimple_call_lhs (t) && could_have_pointers (gimple_call_lhs (t))) - handle_const_call (t); + handle_const_call (t, &rhsc); } /* Pure functions can return addresses in and of memory reachable from their arguments, but they are not an escape point for reachable memory of their arguments. */ - else if (flags & ECF_PURE) - { - handle_pure_call (t); - if (gimple_call_lhs (t) - && could_have_pointers (gimple_call_lhs (t))) - handle_lhs_call (gimple_call_lhs (t), flags); - } + else if (flags & (ECF_PURE|ECF_LOOPING_CONST_OR_PURE)) + handle_pure_call (t, &rhsc); else - { - handle_rhs_call (t); - if (gimple_call_lhs (t) - && could_have_pointers (gimple_call_lhs (t))) - handle_lhs_call (gimple_call_lhs (t), flags); - } + handle_rhs_call (t, &rhsc); + if (gimple_call_lhs (t) + && could_have_pointers (gimple_call_lhs (t))) + handle_lhs_call (gimple_call_lhs (t), flags, rhsc); + VEC_free (ce_s, heap, rhsc); } else { @@ -4925,9 +4916,10 @@ find_what_p_points_to (tree p) pi->pt_null = 1; else if (vi->id == anything_id || vi->id == nonlocal_id - || vi->id == escaped_id - || vi->id == callused_id) + || vi->id == escaped_id) was_pt_anything = 1; + else if (vi->id == callused_id) + gcc_unreachable (); else if (vi->id == readonly_id) was_pt_anything = 1; else if (vi->id == integer_id) |