aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog21
-rw-r--r--gcc/gimple-pretty-print.c14
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-1.c8
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-1f.c4
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/alias-28.c26
-rw-r--r--gcc/tree-ssa-alias.c14
-rw-r--r--gcc/tree-ssa-alias.h10
-rw-r--r--gcc/tree-ssa-structalias.c101
9 files changed, 153 insertions, 52 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 576d5f7..697a5c6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 86c2a55..26d59d1 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -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)");
}
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index ddfc46a..e5f6c89 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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>
diff --git a/gcc/testsuite/gcc.dg/strlenopt-1.c b/gcc/testsuite/gcc.dg/strlenopt-1.c
index 5bc4f0c..5ed5be1 100644
--- a/gcc/testsuite/gcc.dg/strlenopt-1.c
+++ b/gcc/testsuite/gcc.dg/strlenopt-1.c
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-1f.c b/gcc/testsuite/gcc.dg/strlenopt-1f.c
index ce1097f..e0a2c92 100644
--- a/gcc/testsuite/gcc.dg/strlenopt-1f.c
+++ b/gcc/testsuite/gcc.dg/strlenopt-1f.c
@@ -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
index 0000000..8413230
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-28.c
@@ -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;
+}
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index 161a66a..a33b122 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -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)");
}
}
diff --git a/gcc/tree-ssa-alias.h b/gcc/tree-ssa-alias.h
index 581cd82..44485bd 100644
--- a/gcc/tree-ssa-alias.h
+++ b/gcc/tree-ssa-alias.h
@@ -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;
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index d8dbf05..481b9fe 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -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