The following separates the escape solution for return stmts not
only during points-to solving but also for later querying.  This
requires adjusting the points-to-global tests to include escapes
through returns.  Technically the patch replaces the existing
post-processing which computes the transitive closure of the
returned value solution by a proper artificial variable with
transitive closure constraints.  Instead of adding the solution
to escaped we track it separately.

Bootstrapped and tested on x86_64-unknown-linux-gnu, will push.

Richard.

        PR tree-optimization/112653
        * gimple-ssa.h (gimple_df): Add escaped_return solution.
        * tree-ssa.cc (init_tree_ssa): Reset it.
        (delete_tree_ssa): Likewise.
        * tree-ssa-structalias.cc (escaped_return_id): New.
        (find_func_aliases): Handle non-IPA return stmts by
        adding to ESCAPED_RETURN.
        (set_uids_in_ptset): Adjust HEAP escaping to also cover
        escapes through return.
        (init_base_vars): Initialize ESCAPED_RETURN.
        (compute_points_to_sets): Replace ESCAPED post-processing
        with recording the ESCAPED_RETURN solution.
        * tree-ssa-alias.cc (ref_may_alias_global_p_1): Check
        the ESCAPED_RETUNR solution.
        (dump_alias_info): Dump it.
        * cfgexpand.cc (update_alias_info_with_stack_vars): Update it.
        * ipa-icf.cc (sem_item_optimizer::fixup_points_to_sets):
        Likewise.
        * tree-parloops.cc (expand_call_inline): Reset it.
        * tree-sra.cc (maybe_add_sra_candidate): Check it.

        * gcc.dg/tree-ssa/pta-return-1.c: New testcase.
---
 gcc/cfgexpand.cc                             |   3 +-
 gcc/gimple-ssa.h                             |   4 +-
 gcc/ipa-icf.cc                               |   1 +
 gcc/testsuite/gcc.dg/tree-ssa/pta-return-1.c |  16 +++
 gcc/tree-inline.cc                           |   5 +-
 gcc/tree-parloops.cc                         |   5 +-
 gcc/tree-sra.cc                              |   2 +-
 gcc/tree-ssa-alias.cc                        |   6 +-
 gcc/tree-ssa-structalias.cc                  | 124 +++++++------------
 gcc/tree-ssa.cc                              |   2 +
 10 files changed, 85 insertions(+), 83 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pta-return-1.c

diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc
index e58327b239b..feed001f3c9 100644
--- a/gcc/cfgexpand.cc
+++ b/gcc/cfgexpand.cc
@@ -863,7 +863,8 @@ update_alias_info_with_stack_vars (void)
 
       add_partitioned_vars_to_ptset (&cfun->gimple_df->escaped,
                                     decls_to_partitions, &visited, temp);
-
+      add_partitioned_vars_to_ptset (&cfun->gimple_df->escaped_return,
+                                    decls_to_partitions, &visited, temp);
       delete decls_to_partitions;
       BITMAP_FREE (temp);
     }
diff --git a/gcc/gimple-ssa.h b/gcc/gimple-ssa.h
index f2cffa2b159..79637058f70 100644
--- a/gcc/gimple-ssa.h
+++ b/gcc/gimple-ssa.h
@@ -76,8 +76,10 @@ struct GTY(()) gimple_df {
   /* Artificial variable used for the virtual operand FUD chain.  */
   tree vop;
 
-  /* The PTA solution for the ESCAPED artificial variable.  */
+  /* The PTA solution for the ESCAPED and ESCAPED_RETURN artificial
+     variables.  */
   struct pt_solution escaped;
+  struct pt_solution escaped_return;
 
   /* A map of decls to artificial ssa-names that point to the partition
      of the decl.  */
diff --git a/gcc/ipa-icf.cc b/gcc/ipa-icf.cc
index bbdfd445397..c72c9d57a80 100644
--- a/gcc/ipa-icf.cc
+++ b/gcc/ipa-icf.cc
@@ -3506,6 +3506,7 @@ sem_item_optimizer::fixup_points_to_sets (void)
            && SSA_NAME_PTR_INFO (name))
          fixup_pt_set (&SSA_NAME_PTR_INFO (name)->pt);
       fixup_pt_set (&fn->gimple_df->escaped);
+      fixup_pt_set (&fn->gimple_df->escaped_return);
 
        /* The above gets us to 99% I guess, at least catching the
          address compares.  Below also gets us aliasing correct
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pta-return-1.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pta-return-1.c
new file mode 100644
index 00000000000..9c2416e7810
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pta-return-1.c
@@ -0,0 +1,16 @@
+/* PR112653 */
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-optimized" } */
+
+char *test;
+char *
+copy_test ()
+{
+  char *test2 = __builtin_malloc (1000);
+  __builtin_memmove (test2, test, 1000);
+  return test2;
+}
+
+/* We should be able to turn the memmove into memcpy by means of alias
+   analysis.  */
+/* { dg-final { scan-tree-dump "memcpy" "optimized" } } */
diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc
index 0b14118b94b..59847166842 100644
--- a/gcc/tree-inline.cc
+++ b/gcc/tree-inline.cc
@@ -5147,7 +5147,10 @@ expand_call_inline (basic_block bb, gimple *stmt, 
copy_body_data *id,
 
   /* Reset the escaped solution.  */
   if (cfun->gimple_df)
-    pt_solution_reset (&cfun->gimple_df->escaped);
+    {
+      pt_solution_reset (&cfun->gimple_df->escaped);
+      pt_solution_reset (&cfun->gimple_df->escaped_return);
+    }
 
   /* Add new automatic variables to IFN_GOMP_SIMT_ENTER arguments.  */
   if (id->dst_simt_vars && id->dst_simt_vars->length () > 0)
diff --git a/gcc/tree-parloops.cc b/gcc/tree-parloops.cc
index 80f3dd6dce2..50e61f00413 100644
--- a/gcc/tree-parloops.cc
+++ b/gcc/tree-parloops.cc
@@ -4147,7 +4147,10 @@ parallelize_loops (bool oacc_kernels_p)
      which local variables will escape.  Reset the points-to solution
      for ESCAPED.  */
   if (changed)
-    pt_solution_reset (&cfun->gimple_df->escaped);
+    {
+      pt_solution_reset (&cfun->gimple_df->escaped);
+      pt_solution_reset (&cfun->gimple_df->escaped_return);
+    }
 
   return changed;
 }
diff --git a/gcc/tree-sra.cc b/gcc/tree-sra.cc
index 3a0d52675fe..0349410972e 100644
--- a/gcc/tree-sra.cc
+++ b/gcc/tree-sra.cc
@@ -2026,7 +2026,7 @@ maybe_add_sra_candidate (tree var)
        /* There are cases where non-addressable variables fail the
          pt_solutions_check test, e.g in gcc.dg/uninit-40.c. */
        || (TREE_ADDRESSABLE (var)
-          && pt_solution_includes (&cfun->gimple_df->escaped, var))
+          && pt_solution_includes (&cfun->gimple_df->escaped_return, var))
        || (TREE_CODE (var) == RESULT_DECL
           && !DECL_BY_REFERENCE (var)
           && aggregate_value_p (var, current_function_decl)))
diff --git a/gcc/tree-ssa-alias.cc b/gcc/tree-ssa-alias.cc
index 373940b5f6c..a708f7e8d28 100644
--- a/gcc/tree-ssa-alias.cc
+++ b/gcc/tree-ssa-alias.cc
@@ -496,7 +496,8 @@ ref_may_alias_global_p_1 (tree base, bool escaped_local_p)
   if (DECL_P (base))
     return (is_global_var (base)
            || (escaped_local_p
-               && pt_solution_includes (&cfun->gimple_df->escaped, base)));
+               && pt_solution_includes (&cfun->gimple_df->escaped_return,
+                                        base)));
   else if (TREE_CODE (base) == MEM_REF
           || TREE_CODE (base) == TARGET_MEM_REF)
     return ptr_deref_may_alias_global_p (TREE_OPERAND (base, 0),
@@ -579,6 +580,9 @@ dump_alias_info (FILE *file)
   fprintf (file, "\nESCAPED");
   dump_points_to_solution (file, &cfun->gimple_df->escaped);
 
+  fprintf (file, "\nESCAPED_RETURN");
+  dump_points_to_solution (file, &cfun->gimple_df->escaped_return);
+
   fprintf (file, "\n\nFlow-insensitive points-to information\n\n");
 
   FOR_EACH_SSA_NAME (i, ptr, cfun)
diff --git a/gcc/tree-ssa-structalias.cc b/gcc/tree-ssa-structalias.cc
index ee9313c59ca..6db10d5fe11 100644
--- a/gcc/tree-ssa-structalias.cc
+++ b/gcc/tree-ssa-structalias.cc
@@ -365,8 +365,8 @@ vi_next (varinfo_t vi)
 /* Static IDs for the special variables.  Variable ID zero is unused
    and used as terminator for the sub-variable chain.  */
 enum { nothing_id = 1, anything_id = 2, string_id = 3,
-       escaped_id = 4, nonlocal_id = 5,
-       storedanything_id = 6, integer_id = 7 };
+       escaped_id = 4, nonlocal_id = 5, escaped_return_id = 6,
+       storedanything_id = 7, integer_id = 8 };
 
 /* Return a new variable info structure consisting for a variable
    named NAME, and using constraint graph node NODE.  Append it
@@ -5221,23 +5221,18 @@ find_func_aliases (struct function *fn, gimple *origt)
           && gimple_return_retval (as_a <greturn *> (t)) != NULL_TREE)
     {
       greturn *return_stmt = as_a <greturn *> (t);
-      fi = NULL;
-      if (!in_ipa_mode
-         && SSA_VAR_P (gimple_return_retval (return_stmt)))
-       {
-         /* We handle simple returns by post-processing the solutions.  */
-         ;
-       }
-      if (!(fi = get_vi_for_tree (fn->decl)))
-       make_escape_constraint (gimple_return_retval (return_stmt));
-      else if (in_ipa_mode)
+      tree retval = gimple_return_retval (return_stmt);
+      if (!in_ipa_mode)
+       make_constraint_to (escaped_return_id, retval);
+      else
        {
          struct constraint_expr lhs ;
          struct constraint_expr *rhsp;
          unsigned i;
 
+         fi = lookup_vi_for_tree (fn->decl);
          lhs = get_function_part_constraint (fi, fi_result);
-         get_constraint_for_rhs (gimple_return_retval (return_stmt), &rhsc);
+         get_constraint_for_rhs (retval, &rhsc);
          FOR_EACH_VEC_ELT (rhsc, i, rhsp)
            process_constraint (new_constraint (lhs, *rhsp));
        }
@@ -6665,6 +6660,7 @@ 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));
+  varinfo_t escaped_return_vi = get_varinfo (find (escaped_return_id));
   bool everything_escaped
     = escaped_vi->solution && bitmap_bit_p (escaped_vi->solution, anything_id);
 
@@ -6682,6 +6678,9 @@ set_uids_in_ptset (bitmap into, bitmap from, struct 
pt_solution *pt,
          pt->vars_contains_escaped = true;
          pt->vars_contains_escaped_heap |= vi->is_heap_var;
        }
+      if (escaped_return_vi->solution
+         && bitmap_bit_p (escaped_return_vi->solution, i))
+       pt->vars_contains_escaped_heap |= vi->is_heap_var;
 
       if (vi->is_restrict_var)
        pt->vars_contains_restrict = true;
@@ -7196,6 +7195,7 @@ init_base_vars (void)
   varinfo_t var_string;
   varinfo_t var_escaped;
   varinfo_t var_nonlocal;
+  varinfo_t var_escaped_return;
   varinfo_t var_storedanything;
   varinfo_t var_integer;
 
@@ -7271,6 +7271,16 @@ init_base_vars (void)
   var_nonlocal->fullsize = ~0;
   var_nonlocal->is_special_var = 1;
 
+  /* Create the ESCAPED_RETURN variable, used to represent the set of escaped
+     memory via a regular return stmt.  */
+  var_escaped_return = new_var_info (NULL_TREE, "ESCAPED_RETURN", false);
+  gcc_assert (var_escaped_return->id == escaped_return_id);
+  var_escaped_return->is_artificial_var = 1;
+  var_escaped_return->offset = 0;
+  var_escaped_return->size = ~0;
+  var_escaped_return->fullsize = ~0;
+  var_escaped_return->is_special_var = 0;
+
   /* ESCAPED = *ESCAPED, because escaped is may-deref'd at calls, etc.  */
   lhs.type = SCALAR;
   lhs.var = escaped_id;
@@ -7315,6 +7325,24 @@ init_base_vars (void)
   rhs.offset = 0;
   process_constraint (new_constraint (lhs, rhs));
 
+  /* Transitively close ESCAPED_RETURN.
+     ESCAPED_RETURN = ESCAPED_RETURN + UNKNOWN_OFFSET
+     ESCAPED_RETURN = *ESCAPED_RETURN.  */
+  lhs.type = SCALAR;
+  lhs.var = escaped_return_id;
+  lhs.offset = 0;
+  rhs.type = SCALAR;
+  rhs.var = escaped_return_id;
+  rhs.offset = UNKNOWN_OFFSET;
+  process_constraint (new_constraint (lhs, rhs));
+  lhs.type = SCALAR;
+  lhs.var = escaped_return_id;
+  lhs.offset = 0;
+  rhs.type = DEREF;
+  rhs.var = escaped_return_id;
+  rhs.offset = 0;
+  process_constraint (new_constraint (lhs, rhs));
+
   /* Create the STOREDANYTHING variable, used to represent the set of
      variables stored to *ANYTHING.  */
   var_storedanything = new_var_info (NULL_TREE, "STOREDANYTHING", false);
@@ -7555,70 +7583,6 @@ compute_points_to_sets (void)
   /* From the constraints compute the points-to sets.  */
   solve_constraints ();
 
-  /* Post-process solutions for escapes through returns.  */
-  edge_iterator ei;
-  edge e;
-  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
-    if (greturn *ret = safe_dyn_cast <greturn *> (*gsi_last_bb (e->src)))
-      {
-       tree val = gimple_return_retval (ret);
-       /* ???  Easy to handle simple indirections with some work.
-          Arbitrary references like foo.bar.baz are more difficult
-          (but conservatively easy enough with just looking at the base).
-          Mind to fixup find_func_aliases as well.  */
-       if (!val || !SSA_VAR_P (val))
-         continue;
-       /* returns happen last in non-IPA so they only influence
-          the ESCAPED solution and we can filter local variables.  */
-       varinfo_t escaped_vi = get_varinfo (find (escaped_id));
-       varinfo_t vi = lookup_vi_for_tree (val);
-       bitmap delta = BITMAP_ALLOC (&pta_obstack);
-       bitmap_iterator bi;
-       unsigned i;
-       for (; vi; vi = vi_next (vi))
-         {
-           varinfo_t part_vi = get_varinfo (find (vi->id));
-           EXECUTE_IF_AND_COMPL_IN_BITMAP (part_vi->solution,
-                                           escaped_vi->solution, 0, i, bi)
-             {
-               varinfo_t pointed_to_vi = get_varinfo (i);
-               if (pointed_to_vi->is_global_var
-                   /* We delay marking of heap memory as global.  */
-                   || pointed_to_vi->is_heap_var)
-                 bitmap_set_bit (delta, i);
-             }
-         }
-
-       /* Now compute the transitive closure.  */
-       bitmap_ior_into (escaped_vi->solution, delta);
-       bitmap new_delta = BITMAP_ALLOC (&pta_obstack);
-       while (!bitmap_empty_p (delta))
-         {
-           EXECUTE_IF_SET_IN_BITMAP (delta, 0, i, bi)
-             {
-               varinfo_t pointed_to_vi = get_varinfo (i);
-               pointed_to_vi = get_varinfo (find (pointed_to_vi->id));
-               unsigned j;
-               bitmap_iterator bi2;
-               EXECUTE_IF_AND_COMPL_IN_BITMAP (pointed_to_vi->solution,
-                                               escaped_vi->solution,
-                                               0, j, bi2)
-                 {
-                   varinfo_t pointed_to_vi2 = get_varinfo (j);
-                   if (pointed_to_vi2->is_global_var
-                       /* We delay marking of heap memory as global.  */
-                       || pointed_to_vi2->is_heap_var)
-                     bitmap_set_bit (new_delta, j);
-                 }
-             }
-           bitmap_ior_into (escaped_vi->solution, new_delta);
-           bitmap_clear (delta);
-           std::swap (delta, new_delta);
-         }
-       BITMAP_FREE (delta);
-       BITMAP_FREE (new_delta);
-      }
-
   if (dump_file && (dump_flags & TDF_STATS))
     dump_sa_stats (dump_file);
 
@@ -7634,6 +7598,12 @@ compute_points_to_sets (void)
      points-to solution queries.  */
   cfun->gimple_df->escaped.escaped = 0;
 
+  /* The ESCAPED_RETURN solution is what contains all memory that needs
+     to be considered global.  */
+  cfun->gimple_df->escaped_return
+    = find_what_var_points_to (cfun->decl, get_varinfo (escaped_return_id));
+  cfun->gimple_df->escaped_return.escaped = 1;
+
   /* Compute the points-to sets for pointer SSA_NAMEs.  */
   unsigned i;
   tree ptr;
diff --git a/gcc/tree-ssa.cc b/gcc/tree-ssa.cc
index 3858a63de20..9e6233fea2c 100644
--- a/gcc/tree-ssa.cc
+++ b/gcc/tree-ssa.cc
@@ -1216,6 +1216,7 @@ init_tree_ssa (struct function *fn, int size)
   fn->gimple_df = ggc_cleared_alloc<gimple_df> ();
   fn->gimple_df->default_defs = hash_table<ssa_name_hasher>::create_ggc (20);
   pt_solution_reset (&fn->gimple_df->escaped);
+  pt_solution_reset (&fn->gimple_df->escaped_return);
   init_ssanames (fn, size);
 }
 
@@ -1233,6 +1234,7 @@ delete_tree_ssa (struct function *fn)
   fn->gimple_df->default_defs->empty ();
   fn->gimple_df->default_defs = NULL;
   pt_solution_reset (&fn->gimple_df->escaped);
+  pt_solution_reset (&fn->gimple_df->escaped_return);
   if (fn->gimple_df->decls_to_pointers != NULL)
     delete fn->gimple_df->decls_to_pointers;
   fn->gimple_df->decls_to_pointers = NULL;
-- 
2.35.3

Reply via email to