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>
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.
......@@ -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)");
}
}
......
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>
......
......@@ -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" } } */
......
......@@ -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" } } */
......
/* { 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)
{
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)");
}
}
......
......@@ -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;
......
......@@ -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))
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)
&& pt1->vars_contains_nonlocal))
return true;
/* If either points to escaped memory see if the escaped solution
intersects with the other. */
/* If either points to all escaped memory and the other points to
any escaped memory they alias. */
if ((pt1->escaped
&& pt_solutions_intersect_1 (&cfun->gimple_df->escaped, pt2))
&& (pt2->escaped
|| pt2->vars_contains_escaped))
|| (pt2->escaped
&& pt_solutions_intersect_1 (&cfun->gimple_df->escaped, pt1)))
&& 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
......
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