From: Richard Biener Date: Fri, 15 Nov 2013 14:48:22 +0000 (+0000) Subject: re PR middle-end/50262 (PTA doesn't disambiguate locally allocated heap objects from... X-Git-Tag: upstream/12.2.0~66578 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=11924f8b487dc3feb882f08b195bbcbfbacfd96d;p=platform%2Fupstream%2Fgcc.git re PR middle-end/50262 (PTA doesn't disambiguate locally allocated heap objects from pointed to by arguments) 2013-11-15 Richard Biener PR tree-optimization/50262 * tree-ssa-alias.h (struct pt_solution): Split vars_contains_global into vars_contains_nonlocal, vars_contains_escaped and vars_contains_escaped_heap. * tree-ssa-structalias.c (label_visit): Expand comment. (handle_lhs_call): Adjust comment. (set_uids_in_ptset): Set the new flags appropriately. (pt_solution_set): Adjust. (pt_solution_set_var): Likewise. (pt_solution_ior_into): Likewise. (pt_solution_includes_global): Likewise. (pt_solutions_intersect_1): Optimize escaped handling. (compute_points_to_sets): Remove heap variable globalization. (ipa_escaped_pt): Adjust initializer. (pass_data_ipa_pta): Do not run TODO_update_ssa. * gimple-pretty-print.c (pp_points_to_solution): Print split flags. * tree-ssa-alias.c (dump_points_to_solution): Likewise. * gcc.dg/tree-ssa/alias-28.c: New testcase. * gcc.dg/strlenopt-1.c: Adjust. * gcc.dg/strlenopt-1f.c: Likewise. From-SVN: r204845 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 576d5f7..697a5c6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,26 @@ 2013-11-15 Richard Biener + PR tree-optimization/50262 + * tree-ssa-alias.h (struct pt_solution): Split + vars_contains_global into vars_contains_nonlocal, + vars_contains_escaped and vars_contains_escaped_heap. + * tree-ssa-structalias.c (label_visit): Expand comment. + (handle_lhs_call): Adjust comment. + (set_uids_in_ptset): Set the new flags appropriately. + (pt_solution_set): Adjust. + (pt_solution_set_var): Likewise. + (pt_solution_ior_into): Likewise. + (pt_solution_includes_global): Likewise. + (pt_solutions_intersect_1): Optimize escaped handling. + (compute_points_to_sets): Remove heap variable globalization. + (ipa_escaped_pt): Adjust initializer. + (pass_data_ipa_pta): Do not run TODO_update_ssa. + * gimple-pretty-print.c (pp_points_to_solution): Print split + flags. + * tree-ssa-alias.c (dump_points_to_solution): Likewise. + +2013-11-15 Richard Biener + * tree-loop-distribution.c (tree_loop_distribution): Make sure to distribute all stores. diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 86c2a55..26d59d1 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -622,8 +622,18 @@ pp_points_to_solution (pretty_printer *buffer, struct pt_solution *pt) pp_space (buffer); } pp_right_brace (buffer); - if (pt->vars_contains_global) - pp_string (buffer, " (glob)"); + if (pt->vars_contains_nonlocal + && pt->vars_contains_escaped_heap) + pp_string (buffer, " (nonlocal, escaped heap)"); + else if (pt->vars_contains_nonlocal + && pt->vars_contains_escaped) + pp_string (buffer, " (nonlocal, escaped)"); + else if (pt->vars_contains_nonlocal) + pp_string (buffer, " (nonlocal)"); + else if (pt->vars_contains_escaped_heap) + pp_string (buffer, " (escaped heap)"); + else if (pt->vars_contains_escaped) + pp_string (buffer, " (escaped)"); } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ddfc46a..e5f6c89 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,12 @@ 2013-11-15 Richard Biener + PR tree-optimization/50262 + * gcc.dg/tree-ssa/alias-28.c: New testcase. + * gcc.dg/strlenopt-1.c: Adjust. + * gcc.dg/strlenopt-1f.c: Likewise. + +2013-11-15 Richard Biener + * gcc.dg/torture/20131115-1.c: New testcase. 2013-11-15 Joseph Myers diff --git a/gcc/testsuite/gcc.dg/strlenopt-1.c b/gcc/testsuite/gcc.dg/strlenopt-1.c index 5bc4f0c..5ed5be1 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-1.c +++ b/gcc/testsuite/gcc.dg/strlenopt-1.c @@ -16,9 +16,7 @@ foo (char *p, char *r) is immediately overwritten. */ strcat (q, "/"); strcat (q, "abcde"); - /* Due to inefficient PTA (PR50262) the above calls invalidate - string length of r, so it is optimized just into strcpy instead - of memcpy. */ + /* This can also be optimized into memcpy. */ strcat (q, r); return q; } @@ -39,8 +37,8 @@ main () } /* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 3 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ /* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ /* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ /* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-1f.c b/gcc/testsuite/gcc.dg/strlenopt-1f.c index ce1097f..e0a2c92 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-1f.c +++ b/gcc/testsuite/gcc.dg/strlenopt-1f.c @@ -6,8 +6,8 @@ #include "strlenopt-1.c" /* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 3 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 1 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 4 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen" } } */ /* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */ /* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ /* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-28.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-28.c new file mode 100644 index 0000000..8413230 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-28.c @@ -0,0 +1,26 @@ +/* { dg-do run } */ +/* { dg-options "-O3" } */ + +extern void abort (void); +extern void *malloc(__SIZE_TYPE__); + +int * __attribute__((noinline,noclone)) +foo (int *p) +{ + int *q = (int *) malloc (sizeof (int)); + *p = 1; + *q = 2; + if (*p != 1) + __link_error (); + *p = 3; + return q; +} + +int main() +{ + int i; + int *p = foo (&i); + if (i != 3 || *p != 2) + abort (); + return 0; +} diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 161a66a..a33b122 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -452,8 +452,18 @@ dump_points_to_solution (FILE *file, struct pt_solution *pt) { fprintf (file, ", points-to vars: "); dump_decl_set (file, pt->vars); - if (pt->vars_contains_global) - fprintf (file, " (includes global vars)"); + if (pt->vars_contains_nonlocal + && pt->vars_contains_escaped_heap) + fprintf (file, " (nonlocal, escaped heap)"); + else if (pt->vars_contains_nonlocal + && pt->vars_contains_escaped) + fprintf (file, " (nonlocal, escaped)"); + else if (pt->vars_contains_nonlocal) + fprintf (file, " (nonlocal)"); + else if (pt->vars_contains_escaped_heap) + fprintf (file, " (escaped heap)"); + else if (pt->vars_contains_escaped) + fprintf (file, " (escaped)"); } } diff --git a/gcc/tree-ssa-alias.h b/gcc/tree-ssa-alias.h index 581cd82..44485bd 100644 --- a/gcc/tree-ssa-alias.h +++ b/gcc/tree-ssa-alias.h @@ -48,9 +48,13 @@ struct GTY(()) pt_solution unsigned int null : 1; - /* Nonzero if the pt_vars bitmap includes a global variable. */ - unsigned int vars_contains_global : 1; - + /* Nonzero if the vars bitmap includes a variable included in 'nonlocal'. */ + unsigned int vars_contains_nonlocal : 1; + /* Nonzero if the vars bitmap includes a variable included in 'escaped'. */ + unsigned int vars_contains_escaped : 1; + /* Nonzero if the vars bitmap includes a anonymous heap variable that + escaped the function and thus became global. */ + unsigned int vars_contains_escaped_heap : 1; /* Set of variables that this pointer may point to. */ bitmap vars; diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index d8dbf05..481b9fe 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -2063,7 +2063,24 @@ condense_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n) si->scc_stack.safe_push (n); } -/* Label pointer equivalences. */ +/* Label pointer equivalences. + + This performs a value numbering of the constraint graph to + discover which variables will always have the same points-to sets + under the current set of constraints. + + The way it value numbers is to store the set of points-to bits + generated by the constraints and graph edges. This is just used as a + hash and equality comparison. The *actual set of points-to bits* is + completely irrelevant, in that we don't care about being able to + extract them later. + + The equality values (currently bitmaps) just have to satisfy a few + constraints, the main ones being: + 1. The combining operation must be order independent. + 2. The end result of a given set of operations must be unique iff the + combination of input values is unique + 3. Hashable. */ static void label_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n) @@ -3979,8 +3996,8 @@ handle_lhs_call (gimple stmt, tree lhs, int flags, vec rhsc, struct constraint_expr tmpc; rhsc.create (0); vi = make_heapvar ("HEAP"); - /* We delay marking allocated storage global until we know if - it escapes. */ + /* We marking allocated storage local, we deal with it becoming + global by escaping and setting of vars_contains_escaped_heap. */ DECL_EXTERNAL (vi->decl) = 0; vi->is_global_var = 0; /* If this is not a real malloc call assume the memory was @@ -5983,6 +6000,9 @@ set_uids_in_ptset (bitmap into, bitmap from, struct pt_solution *pt) { unsigned int i; bitmap_iterator bi; + varinfo_t escaped_vi = get_varinfo (find (escaped_id)); + bool everything_escaped + = escaped_vi->solution && bitmap_bit_p (escaped_vi->solution, anything_id); EXECUTE_IF_SET_IN_BITMAP (from, 0, i, bi) { @@ -5993,6 +6013,14 @@ set_uids_in_ptset (bitmap into, bitmap from, struct pt_solution *pt) if (vi->is_artificial_var && !vi->is_heap_var) continue; + if (everything_escaped + || (escaped_vi->solution + && bitmap_bit_p (escaped_vi->solution, i))) + { + pt->vars_contains_escaped = true; + pt->vars_contains_escaped_heap = vi->is_heap_var; + } + if (TREE_CODE (vi->decl) == VAR_DECL || TREE_CODE (vi->decl) == PARM_DECL || TREE_CODE (vi->decl) == RESULT_DECL) @@ -6007,7 +6035,7 @@ set_uids_in_ptset (bitmap into, bitmap from, struct pt_solution *pt) set contains global variables. */ bitmap_set_bit (into, DECL_PT_UID (vi->decl)); if (vi->is_global_var) - pt->vars_contains_global = true; + pt->vars_contains_nonlocal = true; } } } @@ -6164,11 +6192,15 @@ pt_solution_reset (struct pt_solution *pt) it contains restrict tag variables. */ void -pt_solution_set (struct pt_solution *pt, bitmap vars, bool vars_contains_global) +pt_solution_set (struct pt_solution *pt, bitmap vars, + bool vars_contains_nonlocal) { memset (pt, 0, sizeof (struct pt_solution)); pt->vars = vars; - pt->vars_contains_global = vars_contains_global; + pt->vars_contains_nonlocal = vars_contains_nonlocal; + pt->vars_contains_escaped + = (cfun->gimple_df->escaped.anything + || bitmap_intersect_p (cfun->gimple_df->escaped.vars, vars)); } /* Set the points-to solution *PT to point only to the variable VAR. */ @@ -6179,7 +6211,10 @@ pt_solution_set_var (struct pt_solution *pt, tree var) memset (pt, 0, sizeof (struct pt_solution)); pt->vars = BITMAP_GGC_ALLOC (); bitmap_set_bit (pt->vars, DECL_PT_UID (var)); - pt->vars_contains_global = is_global_var (var); + pt->vars_contains_nonlocal = is_global_var (var); + pt->vars_contains_escaped + = (cfun->gimple_df->escaped.anything + || bitmap_bit_p (cfun->gimple_df->escaped.vars, DECL_PT_UID (var))); } /* Computes the union of the points-to solutions *DEST and *SRC and @@ -6202,7 +6237,9 @@ pt_solution_ior_into (struct pt_solution *dest, struct pt_solution *src) dest->escaped |= src->escaped; dest->ipa_escaped |= src->ipa_escaped; dest->null |= src->null; - dest->vars_contains_global |= src->vars_contains_global; + dest->vars_contains_nonlocal |= src->vars_contains_nonlocal; + dest->vars_contains_escaped |= src->vars_contains_escaped; + dest->vars_contains_escaped_heap |= src->vars_contains_escaped_heap; if (!src->vars) return; @@ -6259,9 +6296,14 @@ pt_solution_includes_global (struct pt_solution *pt) { if (pt->anything || pt->nonlocal - || pt->vars_contains_global) + || pt->vars_contains_nonlocal + /* The following is a hack to make the malloc escape hack work. + In reality we'd need different sets for escaped-through-return + and escaped-to-callees and passes would need to be updated. */ + || pt->vars_contains_escaped_heap) return true; + /* 'escaped' is also a placeholder so we have to look into it. */ if (pt->escaped) return pt_solution_includes_global (&cfun->gimple_df->escaped); @@ -6331,28 +6373,19 @@ pt_solutions_intersect_1 (struct pt_solution *pt1, struct pt_solution *pt2) any global memory they alias. */ if ((pt1->nonlocal && (pt2->nonlocal - || pt2->vars_contains_global)) + || pt2->vars_contains_nonlocal)) || (pt2->nonlocal - && pt1->vars_contains_global)) + && pt1->vars_contains_nonlocal)) return true; - /* Check the escaped solution if required. */ - if ((pt1->escaped || pt2->escaped) - && !pt_solution_empty_p (&cfun->gimple_df->escaped)) - { - /* If both point to escaped memory and that solution - is not empty they alias. */ - if (pt1->escaped && pt2->escaped) - return true; - - /* If either points to escaped memory see if the escaped solution - intersects with the other. */ - if ((pt1->escaped - && pt_solutions_intersect_1 (&cfun->gimple_df->escaped, pt2)) - || (pt2->escaped - && pt_solutions_intersect_1 (&cfun->gimple_df->escaped, pt1))) - return true; - } + /* If either points to all escaped memory and the other points to + any escaped memory they alias. */ + if ((pt1->escaped + && (pt2->escaped + || pt2->vars_contains_escaped)) + || (pt2->escaped + && pt1->vars_contains_escaped)) + return true; /* Check the escaped solution if required. ??? Do we need to check the local against the IPA escaped sets? */ @@ -6800,14 +6833,6 @@ compute_points_to_sets (void) points-to solution queries. */ cfun->gimple_df->escaped.escaped = 0; - /* Mark escaped HEAP variables as global. */ - FOR_EACH_VEC_ELT (varmap, i, vi) - if (vi - && vi->is_heap_var - && !vi->is_global_var) - DECL_EXTERNAL (vi->decl) = vi->is_global_var - = pt_solution_includes (&cfun->gimple_df->escaped, vi->decl); - /* Compute the points-to sets for pointer SSA_NAMEs. */ for (i = 0; i < num_ssa_names; ++i) { @@ -7054,7 +7079,7 @@ gate_ipa_pta (void) /* IPA PTA solutions for ESCAPED. */ struct pt_solution ipa_escaped_pt - = { true, false, false, false, false, false, NULL }; + = { true, false, false, false, false, false, false, false, NULL }; /* Associate node with varinfo DATA. Worker for cgraph_for_node_and_aliases. */ @@ -7412,7 +7437,7 @@ const pass_data pass_data_ipa_pta = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_update_ssa, /* todo_flags_finish */ + 0, /* todo_flags_finish */ }; class pass_ipa_pta : public simple_ipa_opt_pass