re PR middle-end/50262 (PTA doesn't disambiguate locally allocated heap objects from...
authorRichard Biener <rguenther@suse.de>
Fri, 15 Nov 2013 14:48:22 +0000 (14:48 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Fri, 15 Nov 2013 14:48:22 +0000 (14:48 +0000)
2013-11-15  Richard Biener  <rguenther@suse.de>

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

gcc/ChangeLog
gcc/gimple-pretty-print.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/strlenopt-1.c
gcc/testsuite/gcc.dg/strlenopt-1f.c
gcc/testsuite/gcc.dg/tree-ssa/alias-28.c [new file with mode: 0644]
gcc/tree-ssa-alias.c
gcc/tree-ssa-alias.h
gcc/tree-ssa-structalias.c

index 576d5f7..697a5c6 100644 (file)
@@ -1,5 +1,26 @@
 2013-11-15  Richard Biener  <rguenther@suse.de>
 
+       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  <rguenther@suse.de>
+
        * tree-loop-distribution.c (tree_loop_distribution): Make sure
        to distribute all stores.
 
index 86c2a55..26d59d1 100644 (file)
@@ -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)");
     }
 }
 
index ddfc46a..e5f6c89 100644 (file)
@@ -1,5 +1,12 @@
 2013-11-15  Richard Biener  <rguenther@suse.de>
 
+       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  <rguenther@suse.de>
+
        * gcc.dg/torture/20131115-1.c: New testcase.
 
 2013-11-15  Joseph Myers  <joseph@codesourcery.com>
index 5bc4f0c..5ed5be1 100644 (file)
@@ -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" } } */
index ce1097f..e0a2c92 100644 (file)
@@ -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 (file)
index 0000000..8413230
--- /dev/null
@@ -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;
+}
index 161a66a..a33b122 100644 (file)
@@ -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)");
     }
 }
 
index 581cd82..44485bd 100644 (file)
@@ -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;
index d8dbf05..481b9fe 100644 (file)
@@ -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<ce_s> 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