https://gcc.gnu.org/g:ebc1fc6853b7673b7301d88f4075bc2db3468643
commit ebc1fc6853b7673b7301d88f4075bc2db3468643 Author: Richard Biener <rguent...@suse.de> Date: Mon Nov 27 10:20:02 2023 +0100 tree-optimization/112653 - PTA and return 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. 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-inline.cc (expand_call_inline): Reset it. * tree-parloops.cc (parallelize_loops): Likewise. * tree-sra.cc (maybe_add_sra_candidate): Check it. * gcc.dg/tree-ssa/pta-return-1.c: New testcase. (cherry picked from commit f7884f7673444b8a2c10ea0981d480f2e82dd16a) Diff: --- 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(-) diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc index 4262703a138c..3fee2569680f 100644 --- a/gcc/cfgexpand.cc +++ b/gcc/cfgexpand.cc @@ -859,7 +859,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 604af8b96b7b..0d9fbd30c56e 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 836d0914ded2..82aaf6445924 100644 --- a/gcc/ipa-icf.cc +++ b/gcc/ipa-icf.cc @@ -3505,6 +3505,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 000000000000..9c2416e78107 --- /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 d63060c9429c..65c5df0763bb 100644 --- a/gcc/tree-inline.cc +++ b/gcc/tree-inline.cc @@ -5133,7 +5133,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 e495bbd65270..892fc9f47002 100644 --- a/gcc/tree-parloops.cc +++ b/gcc/tree-parloops.cc @@ -4141,7 +4141,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 671a6407bfd9..3b36cf553893 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 373940b5f6c2..a708f7e8d28e 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 ee9313c59ca5..6db10d5fe113 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 2f3210fcf616..76856be971dd 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;