Commit 11924f8b by Richard Biener Committed by Richard Biener

re PR middle-end/50262 (PTA doesn't disambiguate locally allocated heap objects…

re PR middle-end/50262 (PTA doesn't disambiguate locally allocated heap objects from pointed to by arguments)

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
parent e179190c
2013-11-15 Richard Biener <rguenther@suse.de> 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 * tree-loop-distribution.c (tree_loop_distribution): Make sure
to distribute all stores. to distribute all stores.
...@@ -622,8 +622,18 @@ pp_points_to_solution (pretty_printer *buffer, struct pt_solution *pt) ...@@ -622,8 +622,18 @@ pp_points_to_solution (pretty_printer *buffer, struct pt_solution *pt)
pp_space (buffer); pp_space (buffer);
} }
pp_right_brace (buffer); pp_right_brace (buffer);
if (pt->vars_contains_global) if (pt->vars_contains_nonlocal
pp_string (buffer, " (glob)"); && 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)");
} }
} }
......
2013-11-15 Richard Biener <rguenther@suse.de> 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. * gcc.dg/torture/20131115-1.c: New testcase.
2013-11-15 Joseph Myers <joseph@codesourcery.com> 2013-11-15 Joseph Myers <joseph@codesourcery.com>
......
...@@ -16,9 +16,7 @@ foo (char *p, char *r) ...@@ -16,9 +16,7 @@ foo (char *p, char *r)
is immediately overwritten. */ is immediately overwritten. */
strcat (q, "/"); strcat (q, "/");
strcat (q, "abcde"); strcat (q, "abcde");
/* Due to inefficient PTA (PR50262) the above calls invalidate /* This can also be optimized into memcpy. */
string length of r, so it is optimized just into strcpy instead
of memcpy. */
strcat (q, r); strcat (q, r);
return q; return q;
} }
...@@ -39,8 +37,8 @@ main () ...@@ -39,8 +37,8 @@ main ()
} }
/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ /* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
/* { dg-final { scan-tree-dump-times "memcpy \\(" 3 "strlen" } } */ /* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "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 "strcat \\(" 0 "strlen" } } */
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ /* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ /* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
......
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
#include "strlenopt-1.c" #include "strlenopt-1.c"
/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ /* { 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 "__memcpy_chk \\(" 4 "strlen" } } */
/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 1 "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 "__strcat_chk \\(" 0 "strlen" } } */
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ /* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen" } } */ /* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen" } } */
......
/* { 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;
}
...@@ -452,8 +452,18 @@ dump_points_to_solution (FILE *file, struct pt_solution *pt) ...@@ -452,8 +452,18 @@ dump_points_to_solution (FILE *file, struct pt_solution *pt)
{ {
fprintf (file, ", points-to vars: "); fprintf (file, ", points-to vars: ");
dump_decl_set (file, pt->vars); dump_decl_set (file, pt->vars);
if (pt->vars_contains_global) if (pt->vars_contains_nonlocal
fprintf (file, " (includes global vars)"); && 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)");
} }
} }
......
...@@ -48,9 +48,13 @@ struct GTY(()) pt_solution ...@@ -48,9 +48,13 @@ struct GTY(()) pt_solution
unsigned int null : 1; unsigned int null : 1;
/* Nonzero if the pt_vars bitmap includes a global variable. */ /* Nonzero if the vars bitmap includes a variable included in 'nonlocal'. */
unsigned int vars_contains_global : 1; 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. */ /* Set of variables that this pointer may point to. */
bitmap vars; bitmap vars;
......
...@@ -2063,7 +2063,24 @@ condense_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n) ...@@ -2063,7 +2063,24 @@ condense_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n)
si->scc_stack.safe_push (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 static void
label_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n) 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, ...@@ -3979,8 +3996,8 @@ handle_lhs_call (gimple stmt, tree lhs, int flags, vec<ce_s> rhsc,
struct constraint_expr tmpc; struct constraint_expr tmpc;
rhsc.create (0); rhsc.create (0);
vi = make_heapvar ("HEAP"); vi = make_heapvar ("HEAP");
/* We delay marking allocated storage global until we know if /* We marking allocated storage local, we deal with it becoming
it escapes. */ global by escaping and setting of vars_contains_escaped_heap. */
DECL_EXTERNAL (vi->decl) = 0; DECL_EXTERNAL (vi->decl) = 0;
vi->is_global_var = 0; vi->is_global_var = 0;
/* If this is not a real malloc call assume the memory was /* 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) ...@@ -5983,6 +6000,9 @@ set_uids_in_ptset (bitmap into, bitmap from, struct pt_solution *pt)
{ {
unsigned int i; unsigned int i;
bitmap_iterator bi; 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) 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) ...@@ -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) if (vi->is_artificial_var && !vi->is_heap_var)
continue; 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 if (TREE_CODE (vi->decl) == VAR_DECL
|| TREE_CODE (vi->decl) == PARM_DECL || TREE_CODE (vi->decl) == PARM_DECL
|| TREE_CODE (vi->decl) == RESULT_DECL) || TREE_CODE (vi->decl) == RESULT_DECL)
...@@ -6007,7 +6035,7 @@ set_uids_in_ptset (bitmap into, bitmap from, struct pt_solution *pt) ...@@ -6007,7 +6035,7 @@ set_uids_in_ptset (bitmap into, bitmap from, struct pt_solution *pt)
set contains global variables. */ set contains global variables. */
bitmap_set_bit (into, DECL_PT_UID (vi->decl)); bitmap_set_bit (into, DECL_PT_UID (vi->decl));
if (vi->is_global_var) 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) ...@@ -6164,11 +6192,15 @@ pt_solution_reset (struct pt_solution *pt)
it contains restrict tag variables. */ it contains restrict tag variables. */
void 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)); memset (pt, 0, sizeof (struct pt_solution));
pt->vars = vars; 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. */ /* 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) ...@@ -6179,7 +6211,10 @@ pt_solution_set_var (struct pt_solution *pt, tree var)
memset (pt, 0, sizeof (struct pt_solution)); memset (pt, 0, sizeof (struct pt_solution));
pt->vars = BITMAP_GGC_ALLOC (); pt->vars = BITMAP_GGC_ALLOC ();
bitmap_set_bit (pt->vars, DECL_PT_UID (var)); 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 /* 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) ...@@ -6202,7 +6237,9 @@ pt_solution_ior_into (struct pt_solution *dest, struct pt_solution *src)
dest->escaped |= src->escaped; dest->escaped |= src->escaped;
dest->ipa_escaped |= src->ipa_escaped; dest->ipa_escaped |= src->ipa_escaped;
dest->null |= src->null; 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) if (!src->vars)
return; return;
...@@ -6259,9 +6296,14 @@ pt_solution_includes_global (struct pt_solution *pt) ...@@ -6259,9 +6296,14 @@ pt_solution_includes_global (struct pt_solution *pt)
{ {
if (pt->anything if (pt->anything
|| pt->nonlocal || 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; return true;
/* 'escaped' is also a placeholder so we have to look into it. */
if (pt->escaped) if (pt->escaped)
return pt_solution_includes_global (&cfun->gimple_df->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) ...@@ -6331,28 +6373,19 @@ pt_solutions_intersect_1 (struct pt_solution *pt1, struct pt_solution *pt2)
any global memory they alias. */ any global memory they alias. */
if ((pt1->nonlocal if ((pt1->nonlocal
&& (pt2->nonlocal && (pt2->nonlocal
|| pt2->vars_contains_global)) || pt2->vars_contains_nonlocal))
|| (pt2->nonlocal || (pt2->nonlocal
&& pt1->vars_contains_global)) && pt1->vars_contains_nonlocal))
return true; return true;
/* Check the escaped solution if required. */ /* If either points to all escaped memory and the other points to
if ((pt1->escaped || pt2->escaped) any escaped memory they alias. */
&& !pt_solution_empty_p (&cfun->gimple_df->escaped)) if ((pt1->escaped
{ && (pt2->escaped
/* If both point to escaped memory and that solution || pt2->vars_contains_escaped))
is not empty they alias. */ || (pt2->escaped
if (pt1->escaped && pt2->escaped) && pt1->vars_contains_escaped))
return true; 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;
}
/* Check the escaped solution if required. /* Check the escaped solution if required.
??? Do we need to check the local against the IPA escaped sets? */ ??? Do we need to check the local against the IPA escaped sets? */
...@@ -6800,14 +6833,6 @@ compute_points_to_sets (void) ...@@ -6800,14 +6833,6 @@ compute_points_to_sets (void)
points-to solution queries. */ points-to solution queries. */
cfun->gimple_df->escaped.escaped = 0; 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. */ /* Compute the points-to sets for pointer SSA_NAMEs. */
for (i = 0; i < num_ssa_names; ++i) for (i = 0; i < num_ssa_names; ++i)
{ {
...@@ -7054,7 +7079,7 @@ gate_ipa_pta (void) ...@@ -7054,7 +7079,7 @@ gate_ipa_pta (void)
/* IPA PTA solutions for ESCAPED. */ /* IPA PTA solutions for ESCAPED. */
struct pt_solution ipa_escaped_pt 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 /* Associate node with varinfo DATA. Worker for
cgraph_for_node_and_aliases. */ cgraph_for_node_and_aliases. */
...@@ -7412,7 +7437,7 @@ const pass_data pass_data_ipa_pta = ...@@ -7412,7 +7437,7 @@ const pass_data pass_data_ipa_pta =
0, /* properties_provided */ 0, /* properties_provided */
0, /* properties_destroyed */ 0, /* properties_destroyed */
0, /* todo_flags_start */ 0, /* todo_flags_start */
TODO_update_ssa, /* todo_flags_finish */ 0, /* todo_flags_finish */
}; };
class pass_ipa_pta : public simple_ipa_opt_pass class pass_ipa_pta : public simple_ipa_opt_pass
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment