tree-ssa-structalias.c (struct variable_info): Add is_fn_info flag.

2010-04-15  Richard Guenther  <rguenther@suse.de>

	* tree-ssa-structalias.c (struct variable_info): Add
	is_fn_info flag.
	(new_var_info): Initialize it.
	(dump_constraints): Support printing last added constraints.
	(debug_constraints): Adjust.
	(dump_constraint_graph): Likewise.
	(make_heapvar_for): Check for NULL cfun.
	(get_function_part_constraint): New function.
	(get_fi_for_callee): Likewise.
	(find_func_aliases): Properly implement IPA PTA constraints.
	(process_ipa_clobber): New function.
	(find_func_clobbers): Likewise.
	(insert_into_field_list_sorted): Remove.
	(create_function_info_for): Properly allocate vars for IPA mode.
	Do not use insert_into_field_list_sorted.
	(create_variable_info_for): Properly generate constraints for
	global vars in IPA mode.
	(dump_solution_for_var): Always dump the solution.
	(set_uids_in_ptset): Initialize DECL_PT_UID if in ipa-mode.
	(find_what_var_points_to): Adjust.
	(pt_solution_set): Change.
	(pt_solution_ior_into): New function.
	(pt_solution_empty_p): Export.
	(pt_solution_includes_global): Adjust.
	(pt_solution_includes_1): Likewise.
	(pt_solutions_intersect_1): Likewise.
	(dump_sa_points_to_info): Check some invariants.
	(solve_constraints): Move constraint dumping ...
	(compute_points_to_sets): ... here.
	(ipa_pta_execute): ... and here.
	(compute_may_aliases): Do not re-compute points-to info
	locally if IPA info is available.
	(ipa_escaped_pt): New global var.
	(ipa_pta_execute): Properly implement IPA PTA.
	* tree-into-ssa.c (dump_decl_set): Support dumping
	decls not in referenced-vars.
	* tree-flow.h (struct gimple_df): Add ipa_pta flag.
	* tree-ssa-alias.c (ptr_deref_may_alias_decl_p): Adjust.
	(dump_points_to_solution): Likewise.
	* tree-dfa.c (dump_variable): Also dump DECL_PT_UID.
	* tree-inline.c (remap_ssa_name): Copy IPA points-to solution.
	(remap_gimple_stmt): Reset call clobber/use information if
	necessary.
	(copy_decl_to_var): Copy DECL_PT_UID.
	(copy_result_decl_to_var): Likewise.
	* tree.c (make_node_stat): Initialize DECL_PT_UID.
	(copy_node_stat): Copy it.
	* tree.h (DECL_PT_UID): New macro.
	(SET_DECL_PT_UID): Likewise.
	(DECL_PT_UID_SET_P): Likewise.
	(struct tree_decl_minimal): Add pt_uid member.
	* tree-ssa-alias.h (struct pt_solution): Add ipa_escaped flag.
	(pt_solution_empty_p): Declare.
	(pt_solution_set): Adjust.
	(ipa_escaped_pt): Declare.
	* cfgexpand.c (update_alias_info_with_stack_vars): Adjust.
	* gimple-pretty-print.c (pp_points_to_solution): New function.
	(dump_gimple_call): Dump call clobber/use information.
	* tree-dump.c (dump_option_value_in): Add TDF_ALIAS entry.
	* tree-pass.h (TDF_ALIAS): New dump option.
	* tree-pretty-print.c (dump_decl_name): Dump DECL_PT_UID if asked to.
	* doc/invoke.texi (-fipa-pta): Update documentation.

	* gcc.dg/ipa/ipa-pta-1.c: New testcase.
	* gcc.dg/ipa/ipa-pta-2.c: Likewise.
	* gcc.dg/ipa/ipa-pta-3.c: Likewise.
	* gcc.dg/ipa/ipa-pta-4.c: Likewise.
	* gcc.dg/ipa/ipa-pta-5.c: Likewise.
	* gcc.dg/ipa/ipa-pta-6.c: Likewise.
	* gcc.dg/ipa/ipa-pta-7.c: Likewise.
	* gcc.dg/ipa/ipa-pta-8.c: Likewise.
	* gcc.dg/ipa/ipa-pta-9.c: Likewise.
	* gcc.dg/ipa/ipa-pta-10.c: Likewise.
	* gcc.dg/ipa/ipa-pta-11.c: Likewise.
	* gcc.dg/ipa/ipa-pta-12.c: Likewise.
	* gcc.dg/ipa/ipa-pta-13.c: Likewise.
	* gcc.dg/torture/ipa-pta-2.c: Likewise.
	* gcc.dg/torture/ipa-pta-1.c: Adjust.

From-SVN: r158374
This commit is contained in:
Richard Guenther 2010-04-15 13:16:44 +00:00 committed by Richard Biener
parent cbdd87d444
commit 25a6a8731c
32 changed files with 1758 additions and 183 deletions

View file

@ -1,3 +1,68 @@
2010-04-15 Richard Guenther <rguenther@suse.de>
* tree-ssa-structalias.c (struct variable_info): Add
is_fn_info flag.
(new_var_info): Initialize it.
(dump_constraints): Support printing last added constraints.
(debug_constraints): Adjust.
(dump_constraint_graph): Likewise.
(make_heapvar_for): Check for NULL cfun.
(get_function_part_constraint): New function.
(get_fi_for_callee): Likewise.
(find_func_aliases): Properly implement IPA PTA constraints.
(process_ipa_clobber): New function.
(find_func_clobbers): Likewise.
(insert_into_field_list_sorted): Remove.
(create_function_info_for): Properly allocate vars for IPA mode.
Do not use insert_into_field_list_sorted.
(create_variable_info_for): Properly generate constraints for
global vars in IPA mode.
(dump_solution_for_var): Always dump the solution.
(set_uids_in_ptset): Initialize DECL_PT_UID if in ipa-mode.
(find_what_var_points_to): Adjust.
(pt_solution_set): Change.
(pt_solution_ior_into): New function.
(pt_solution_empty_p): Export.
(pt_solution_includes_global): Adjust.
(pt_solution_includes_1): Likewise.
(pt_solutions_intersect_1): Likewise.
(dump_sa_points_to_info): Check some invariants.
(solve_constraints): Move constraint dumping ...
(compute_points_to_sets): ... here.
(ipa_pta_execute): ... and here.
(compute_may_aliases): Do not re-compute points-to info
locally if IPA info is available.
(ipa_escaped_pt): New global var.
(ipa_pta_execute): Properly implement IPA PTA.
* tree-into-ssa.c (dump_decl_set): Support dumping
decls not in referenced-vars.
* tree-flow.h (struct gimple_df): Add ipa_pta flag.
* tree-ssa-alias.c (ptr_deref_may_alias_decl_p): Adjust.
(dump_points_to_solution): Likewise.
* tree-dfa.c (dump_variable): Also dump DECL_PT_UID.
* tree-inline.c (remap_ssa_name): Copy IPA points-to solution.
(remap_gimple_stmt): Reset call clobber/use information if
necessary.
(copy_decl_to_var): Copy DECL_PT_UID.
(copy_result_decl_to_var): Likewise.
* tree.c (make_node_stat): Initialize DECL_PT_UID.
(copy_node_stat): Copy it.
* tree.h (DECL_PT_UID): New macro.
(SET_DECL_PT_UID): Likewise.
(DECL_PT_UID_SET_P): Likewise.
(struct tree_decl_minimal): Add pt_uid member.
* tree-ssa-alias.h (struct pt_solution): Add ipa_escaped flag.
(pt_solution_empty_p): Declare.
(pt_solution_set): Adjust.
(ipa_escaped_pt): Declare.
* cfgexpand.c (update_alias_info_with_stack_vars): Adjust.
* gimple-pretty-print.c (pp_points_to_solution): New function.
(dump_gimple_call): Dump call clobber/use information.
* tree-dump.c (dump_option_value_in): Add TDF_ALIAS entry.
* tree-pass.h (TDF_ALIAS): New dump option.
* tree-pretty-print.c (dump_decl_name): Dump DECL_PT_UID if asked to.
* doc/invoke.texi (-fipa-pta): Update documentation.
2010-04-15 Richard Guenther <rguenther@suse.de>
* Makefile.in (OBJS-common): Add gimple-fold.o.

View file

@ -500,12 +500,12 @@ update_alias_info_with_stack_vars (void)
for (j = i; j != EOC; j = stack_vars[j].next)
{
tree decl = stack_vars[j].decl;
unsigned int uid = DECL_UID (decl);
unsigned int uid = DECL_PT_UID (decl);
/* We should never end up partitioning SSA names (though they
may end up on the stack). Neither should we allocate stack
space to something that is unused and thus unreferenced. */
gcc_assert (DECL_P (decl)
&& referenced_var_lookup (uid));
&& referenced_var_lookup (DECL_UID (decl)));
bitmap_set_bit (part, uid);
*((bitmap *) pointer_map_insert (decls_to_partitions,
(void *)(size_t) uid)) = part;
@ -515,7 +515,7 @@ update_alias_info_with_stack_vars (void)
/* Make the SSA name point to all partition members. */
pi = get_ptr_info (name);
pt_solution_set (&pi->pt, part);
pt_solution_set (&pi->pt, part, false, false);
}
/* Make all points-to sets that contain one member of a partition

View file

@ -6577,8 +6577,10 @@ With this flag, the program debug info reflects a new structure layout.
@item -fipa-pta
@opindex fipa-pta
Perform interprocedural pointer analysis. This option is experimental
and does not affect generated code.
Perform interprocedural pointer analysis and interprocedural modification
and reference analysis. This option can cause excessive memory and
compile-time usage on large compilation units. It is not enabled by
default at any optimization level.
@item -fipa-cp
@opindex fipa-cp

View file

@ -477,6 +477,60 @@ dump_gimple_call_args (pretty_printer *buffer, gimple gs, int flags)
}
}
/* Dump the points-to solution *PT to BUFFER. */
static void
pp_points_to_solution (pretty_printer *buffer, struct pt_solution *pt)
{
if (pt->anything)
{
pp_string (buffer, "anything ");
return;
}
if (pt->nonlocal)
pp_string (buffer, "nonlocal ");
if (pt->escaped)
pp_string (buffer, "escaped ");
if (pt->ipa_escaped)
pp_string (buffer, "unit-escaped ");
if (pt->null)
pp_string (buffer, "null ");
if (pt->vars
&& !bitmap_empty_p (pt->vars))
{
bitmap_iterator bi;
unsigned i;
pp_string (buffer, "{ ");
EXECUTE_IF_SET_IN_BITMAP (pt->vars, 0, i, bi)
{
struct tree_decl_minimal in;
tree var;
in.uid = i;
var = (tree) htab_find_with_hash (gimple_referenced_vars (cfun),
&in, i);
if (var)
{
dump_generic_node (buffer, var, 0, dump_flags, false);
if (DECL_PT_UID (var) != DECL_UID (var))
{
pp_string (buffer, "ptD.");
pp_decimal_int (buffer, DECL_PT_UID (var));
}
}
else
{
pp_string (buffer, "D.");
pp_decimal_int (buffer, i);
}
pp_character (buffer, ' ');
}
pp_character (buffer, '}');
if (pt->vars_contains_global)
pp_string (buffer, " (glob)");
if (pt->vars_contains_restrict)
pp_string (buffer, " (restr)");
}
}
/* Dump the call statement GS. BUFFER, SPC and FLAGS are as in
dump_gimple_stmt. */
@ -486,6 +540,25 @@ dump_gimple_call (pretty_printer *buffer, gimple gs, int spc, int flags)
{
tree lhs = gimple_call_lhs (gs);
if (flags & TDF_ALIAS)
{
struct pt_solution *pt;
pt = gimple_call_use_set (gs);
if (!pt_solution_empty_p (pt))
{
pp_string (buffer, "# USE = ");
pp_points_to_solution (buffer, pt);
newline_and_indent (buffer, spc);
}
pt = gimple_call_clobber_set (gs);
if (!pt_solution_empty_p (pt))
{
pp_string (buffer, "# CLB = ");
pp_points_to_solution (buffer, pt);
newline_and_indent (buffer, spc);
}
}
if (flags & TDF_RAW)
{
dump_gimple_fmt (buffer, spc, flags, "%G <%T, %T",

View file

@ -1,3 +1,21 @@
2010-04-15 Richard Guenther <rguenther@suse.de>
* gcc.dg/ipa/ipa-pta-1.c: New testcase.
* gcc.dg/ipa/ipa-pta-2.c: Likewise.
* gcc.dg/ipa/ipa-pta-3.c: Likewise.
* gcc.dg/ipa/ipa-pta-4.c: Likewise.
* gcc.dg/ipa/ipa-pta-5.c: Likewise.
* gcc.dg/ipa/ipa-pta-6.c: Likewise.
* gcc.dg/ipa/ipa-pta-7.c: Likewise.
* gcc.dg/ipa/ipa-pta-8.c: Likewise.
* gcc.dg/ipa/ipa-pta-9.c: Likewise.
* gcc.dg/ipa/ipa-pta-10.c: Likewise.
* gcc.dg/ipa/ipa-pta-11.c: Likewise.
* gcc.dg/ipa/ipa-pta-12.c: Likewise.
* gcc.dg/ipa/ipa-pta-13.c: Likewise.
* gcc.dg/torture/ipa-pta-2.c: Likewise.
* gcc.dg/torture/ipa-pta-1.c: Adjust.
2010-04-14 Bernd Schmidt <bernd.schmidt@codesourcery.com>
PR target/21803

View file

@ -0,0 +1,50 @@
/* { dg-do run } */
/* { dg-options "-O -fipa-pta -fdump-ipa-pta-details" } */
static int __attribute__((noinline))
foo (int *p, int *q)
{
*p = 2;
*q = 1;
return *p;
}
static int __attribute__((noinline))
bar (int *p, int *q)
{
*p = -2;
*q = -1;
return *p;
}
static int __attribute__((noinline,noclone))
foobar (int foo_p)
{
int a;
int (*fn)(int *, int *);
if (foo_p)
fn = foo;
else
fn = bar;
return (*fn)(&a, &a);
}
extern void abort (void);
int main()
{
if (foobar (1) != 1)
abort ();
return 0;
}
/* IPA PTA needs to handle indirect calls properly. Verify that
both bar and foo get a (and only a) in their arguments points-to sets. */
/* { dg-final { scan-ipa-dump "fn_1 = { bar foo }" "pta" } } */
/* { dg-final { scan-ipa-dump "bar.arg0 = { a }" "pta" } } */
/* { dg-final { scan-ipa-dump "bar.arg1 = { a }" "pta" } } */
/* { dg-final { scan-ipa-dump "foo.arg0 = { a }" "pta" } } */
/* { dg-final { scan-ipa-dump "foo.arg1 = { a }" "pta" } } */
/* { dg-final { cleanup-ipa-dump "pta" } } */

View file

@ -0,0 +1,30 @@
/* { dg-do run } */
/* { dg-options "-O2 -fipa-pta -fdump-ipa-pta-details" } */
#include <stdarg.h>
static void __attribute__((noinline,noclone))
foo (int i, ...)
{
va_list ap;
int *p;
va_start (ap, i);
p = va_arg (ap, int *);
*p = 1;
va_end (ap);
}
extern void abort (void);
int main()
{
int i = 0;
foo (0, &i);
if (i != 1)
abort ();
return 0;
}
/* Verify we properly handle variadic arguments and do not let escape
stuff through it. */
/* { dg-final { scan-ipa-dump "ESCAPED = { }" "pta" } } */
/* { dg-final { cleanup-ipa-dump "pta" } } */

View file

@ -0,0 +1,33 @@
/* { dg-do link } */
/* { dg-options "-O2 -fipa-pta -fdump-ipa-pta-details" } */
static int i;
/* i should not escape here, p should point to i only. */
/* { dg-final { scan-ipa-dump "p = { i }" "pta" } } */
static int *p = &i;
int j;
/* q should point to j only. */
/* { dg-final { scan-ipa-dump "q = { j }" "pta" } } */
static int *q = &j;
static int k;
/* k should escape here, r should point to NONLOCAL, ESCAPED, k. */
int *r = &k;
/* { dg-final { scan-ipa-dump "r = { ESCAPED NONLOCAL k }" "pta" } } */
int l;
/* s should point to NONLOCAL, ESCAPED, l. */
int *s = &l;
/* { dg-final { scan-ipa-dump "s = { ESCAPED NONLOCAL l }" "pta" } } */
int main()
{
return 0;
}
/* It isn't clear if the escape if l is strictly necessary, if it were
we should have i, r and s in ESCAPED as well. */
/* { dg-final { scan-ipa-dump "ESCAPED = { ESCAPED NONLOCAL l k }" "pta" } } */
/* { dg-final { cleanup-ipa-dump "pta" } } */

View file

@ -0,0 +1,34 @@
static int i, j;
static void __attribute__((noinline,noclone))
foo (void) { i = 1; }
static void __attribute__((noinline,noclone))
bar (void) { j = 1; }
typedef void (*fn_t)(void);
void escapeme (fn_t);
fn_t getme (void);
extern void link_error (void);
int main()
{
fn_t fn;
escapeme (foo);
fn = getme();
i = 0;
fn();
if (i != 1)
return 100;
j = 0;
fn();
if (j != 0)
link_error ();
bar();
if (j != 1)
return 200;
return 0;
}

View file

@ -0,0 +1,56 @@
/* { dg-do link } */
/* { dg-options "-O2 -fipa-pta -fdump-ipa-pta-details -fdump-tree-fre" } */
static int x, y;
static __attribute__((noinline,noclone)) void
local (int *p)
{
*p = 1;
}
static __attribute__((noinline,noclone)) void
local_address_taken (int *p)
{
*p = 1;
}
/* Even though not referenced in this TU we should have added constraints
for the initializer. */
/* { dg-final { scan-ipa-dump "ex = &local_address_taken" "pta" } } */
void (*ex)(int *) = local_address_taken;
extern void link_error (void);
int main()
{
void (*anyfn)(int *) = (void (*)(int *))(__SIZE_TYPE__)x;
/* The following should cause local_address_taken to get &x
as argument, but not local. We shouldn't get &x added to
arbitrary special sub-vars of local_address_taken though,
a missed optimization currently.
As local_address_taken escapes the translation unit its
argument points-to set needs to include ESCAPED and NONLOCAL.
We shouldn't get the functions sub-vars in the ESCAPED solution
though, another missed-optimization. This also causes the functions
uses to be messed up even further. */
/* { dg-final { scan-ipa-dump "local_address_taken.arg0 = { ESCAPED NONLOCAL y x }" "pta" } } */
/* { dg-final { scan-ipa-dump "local_address_taken.clobber = { ESCAPED NONLOCAL y x }" "pta" } } */
/* { dg-final { scan-ipa-dump "local_address_taken.use = { }" "pta" { xfail *-*-* } } } */
(*anyfn) (&x);
x = 0;
local (&y);
/* Thus we should be able to disambiguate x against the call to local
and CSE the stored value. */
if (x != 0)
link_error ();
x = 1;
local_address_taken (&y);
/* As we are computing flow- and context-insensitive we may not
CSE the load of x here. */
/* { dg-final { scan-tree-dump " = x;" "fre" } } */
return x;
}
/* { dg-final { cleanup-ipa-dump "pta" } } */
/* { dg-final { cleanup-tree-dump "fre" } } */

View file

@ -0,0 +1,25 @@
/* { dg-do compile } */
/* { dg-options "-O -fipa-pta -fdump-ipa-pta-details" } */
int (*fn)(int *);
static int __attribute__((noinline,noclone))
foo (int *p)
{
return *p;
}
extern void bar (void);
int main()
{
fn = foo;
bar ();
return 0;
}
/* Make sure that when a local function escapes its argument points-to sets
are properly adjusted. */
/* { dg-final { scan-ipa-dump "foo.arg0 = { ESCAPED NONLOCAL }" "pta" } } */
/* { dg-final { cleanup-ipa-dump "pta" } } */

View file

@ -0,0 +1,28 @@
/* { dg-do run } */
/* { dg-options "-O2 -fipa-pta -fdump-ipa-pta-details -fdump-tree-fre-details" } */
static int __attribute__((noinline,noclone))
foo (int *p, int *q)
{
*p = 1;
*q = 0;
return *p;
}
extern void abort (void);
int main()
{
int a, b;
if (foo (&a, &b) != 1)
abort ();
return 0;
}
/* Verify we can disambiguate *p and *q in foo. */
/* { dg-final { scan-ipa-dump "foo.arg0 = &a" "pta" } } */
/* { dg-final { scan-ipa-dump "foo.arg1 = &b" "pta" } } */
/* { dg-final { scan-tree-dump "Replaced \\\*p_1\\\(D\\\) with 1" "fre" } } */
/* { dg-final { cleanup-tree-dump "fre" } } */
/* { dg-final { cleanup-ipa-dump "pta" } } */

View file

@ -0,0 +1,33 @@
/* { dg-do run } */
/* { dg-options "-O2 -fipa-pta -fdump-ipa-pta-details -fdump-tree-fre-details" } */
int a, b;
static int __attribute__((noinline,noclone))
foo (int *p, int *q)
{
int res;
*p = 1;
*q = 0;
res = *p;
a = 1;
b = 1;
return res;
}
extern void abort (void);
int main()
{
if (foo (&a, &b) != 1)
abort ();
return 0;
}
/* Verify we can disambiguate *p and *q in foo. */
/* { dg-final { scan-ipa-dump "foo.arg0 = &a" "pta" } } */
/* { dg-final { scan-ipa-dump "foo.arg1 = &b" "pta" } } */
/* { dg-final { scan-tree-dump "Replaced \\\*p_1\\\(D\\\) with 1" "fre" } } */
/* { dg-final { cleanup-tree-dump "fre" } } */
/* { dg-final { cleanup-ipa-dump "pta" } } */

View file

@ -0,0 +1,26 @@
/* { dg-do run } */
/* { dg-options "-O2 -fipa-pta -fdump-ipa-pta-details" } */
int **x;
static int __attribute__((noinline,noclone))
foo (int **q)
{
int a = 1;
**q = 0;
*x = &a;
return **q;
}
extern void abort (void);
int main()
{
int b;
int *p = &b;
x = &p;
if (foo (&p) != 1)
abort ();
return 0;
}
/* { dg-final { cleanup-ipa-dump "pta" } } */

View file

@ -0,0 +1,25 @@
/* { dg-do run } */
/* { dg-options "-O -fipa-pta -fdump-ipa-pta-details" } */
static void __attribute__((noinline,noclone))
foo (int *p)
{
*p = 1;
}
extern void abort (void);
int main()
{
int i = 0;
foo (&i);
if (i != 1)
abort ();
return 0;
}
/* Verify we correctly compute the units ESCAPED set as empty but
still properly account for the store via *p in foo. */
/* { dg-final { scan-ipa-dump "ESCAPED = { }" "pta" } } */
/* { dg-final { cleanup-ipa-dump "pta" } } */

View file

@ -0,0 +1,30 @@
/* { dg-do run } */
/* { dg-options "-O2 -fno-early-inlining -fipa-pta" } */
static void __attribute__((noinline,noclone))
clobber_me (int *p, int how)
{
*p = how;
}
/* When foo is inlined into main we have to make sure to adjust
main()s IPA CLOBBERED set according to the decl remappings
inlining does. */
static int
foo (void)
{
int a = 0;
clobber_me (&a, 1);
return a;
}
extern void abort (void);
int main()
{
if (foo () != 1)
abort ();
return 0;
}

View file

@ -0,0 +1,31 @@
/* { dg-do run } */
/* { dg-options "-O2 -fno-early-inlining -fipa-pta" } */
static int *__attribute__((noinline,noclone))
pass_me (int *p)
{
return p;
}
/* When foo is inlined into main we have to make sure to adjust
main()s IPA CLOBBERED set according to the decl remappings
inlining does. */
static int
foo (void)
{
int a = 0;
int *p = pass_me (&a);
*p = 1;
return a;
}
extern void abort (void);
int main()
{
if (foo () != 1)
abort ();
return 0;
}

View file

@ -0,0 +1,17 @@
/* { dg-do run } */
/* { dg-options "-O2 -fipa-pta" } */
static void __attribute__((noinline,noclone))
foo (int *p, int *q)
{
__builtin_memcpy (p, q, sizeof (int));
}
extern void abort (void);
int main()
{
int i = 0, j = 1;
foo (&i, &j);
if (i != 1)
abort ();
return 0;
}

View file

@ -42,5 +42,5 @@ void test4 (int a4, char b, char c, char d, char e, char f, char g, char h)
bar (p);
}
/* { dg-final { scan-ipa-dump "bar.arg0 = { a4 a3 a2 a1 }" "pta" } } */
/* { dg-final { scan-ipa-dump "bar.arg0 = { test4.arg0 test3.arg0 test2.arg0 test1.arg0 }" "pta" } } */
/* { dg-final { cleanup-ipa-dump "pta" } } */

View file

@ -0,0 +1,24 @@
/* { dg-do run } */
/* { dg-options "-fipa-pta" } */
int **x;
static int __attribute__((noinline,noclone))
foo (int **p)
{
int a = 1;
**p = 0;
*x = &a;
return **p;
}
extern void abort (void);
int main()
{
int b;
int *p = &b;
x = &p;
if (foo (&p) != 1)
abort ();
return 0;
}

View file

@ -269,6 +269,8 @@ dump_variable (FILE *file, tree var)
ann = var_ann (var);
fprintf (file, ", UID D.%u", (unsigned) DECL_UID (var));
if (DECL_PT_UID (var) != DECL_UID (var))
fprintf (file, ", PT-UID D.%u", (unsigned) DECL_PT_UID (var));
fprintf (file, ", ");
print_generic_expr (file, TREE_TYPE (var), dump_flags);

View file

@ -821,6 +821,7 @@ static const struct dump_option_value_info dump_options[] =
{"memsyms", TDF_MEMSYMS},
{"verbose", TDF_VERBOSE},
{"eh", TDF_EH},
{"alias", TDF_ALIAS},
{"nouid", TDF_NOUID},
{"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA
| TDF_STMTADDR | TDF_GRAPH | TDF_DIAGNOSTIC | TDF_VERBOSE

View file

@ -76,6 +76,9 @@ struct GTY(()) gimple_df {
/* True if the code is in ssa form. */
unsigned int in_ssa_p : 1;
/* True if IPA points-to information was computed for this function. */
unsigned int ipa_pta : 1;
struct ssa_operands ssa_operands;
};
@ -111,9 +114,10 @@ typedef struct
---------------------------------------------------------------------------*/
/* Aliasing information for SSA_NAMEs representing pointer variables. */
struct GTY(()) ptr_info_def
{
/* The points-to solution, TBAA-pruned if the pointer is dereferenced. */
/* The points-to solution. */
struct pt_solution pt;
};

View file

@ -211,11 +211,21 @@ remap_ssa_name (tree name, copy_body_data *id)
&& (TREE_CODE (SSA_NAME_VAR (name)) != RESULT_DECL
|| !id->transform_return_to_modify))
{
struct ptr_info_def *pi;
new_tree = make_ssa_name (new_tree, NULL);
insert_decl_map (id, name, new_tree);
SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_tree)
= SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name);
TREE_TYPE (new_tree) = TREE_TYPE (SSA_NAME_VAR (new_tree));
/* At least IPA points-to info can be directly transferred. */
if (id->src_cfun->gimple_df
&& id->src_cfun->gimple_df->ipa_pta
&& (pi = SSA_NAME_PTR_INFO (name))
&& !pi->pt.anything)
{
struct ptr_info_def *new_pi = get_ptr_info (new_tree);
new_pi->pt = pi->pt;
}
if (gimple_nop_p (SSA_NAME_DEF_STMT (name)))
{
/* By inlining function having uninitialized variable, we might
@ -1392,12 +1402,11 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
break;
}
/* Reset alias info.
??? By maintaining DECL_PT_UID this should not
be necessary, but the plan is to only maintain
it when IPA-PTA was run. It's not too easy to
detect this here ... */
gimple_call_reset_alias_info (copy);
/* Reset alias info if we didn't apply measures to
keep it valid over inlining by setting DECL_PT_UID. */
if (!id->src_cfun->gimple_df
|| !id->src_cfun->gimple_df->ipa_pta)
gimple_call_reset_alias_info (copy);
}
break;
@ -4516,6 +4525,8 @@ copy_decl_to_var (tree decl, copy_body_data *id)
copy = build_decl (DECL_SOURCE_LOCATION (id->dst_fn),
VAR_DECL, DECL_NAME (decl), type);
if (DECL_PT_UID_SET_P (decl))
SET_DECL_PT_UID (copy, DECL_PT_UID (decl));
TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
TREE_READONLY (copy) = TREE_READONLY (decl);
TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
@ -4541,6 +4552,8 @@ copy_result_decl_to_var (tree decl, copy_body_data *id)
copy = build_decl (DECL_SOURCE_LOCATION (id->dst_fn),
VAR_DECL, DECL_NAME (decl), type);
if (DECL_PT_UID_SET_P (decl))
SET_DECL_PT_UID (copy, DECL_PT_UID (decl));
TREE_READONLY (copy) = TREE_READONLY (decl);
TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
if (!DECL_BY_REFERENCE (decl))

View file

@ -1475,7 +1475,15 @@ dump_decl_set (FILE *file, bitmap set)
EXECUTE_IF_SET_IN_BITMAP (set, 0, i, bi)
{
print_generic_expr (file, referenced_var (i), 0);
struct tree_decl_minimal in;
tree var;
in.uid = i;
var = (tree) htab_find_with_hash (gimple_referenced_vars (cfun),
&in, i);
if (var)
print_generic_expr (file, var, 0);
else
fprintf (file, "D.%u", i);
fprintf (file, " ");
}

View file

@ -78,8 +78,9 @@ enum tree_dump_index
#define TDF_ASMNAME (1 << 18) /* display asm names of decls */
#define TDF_EH (1 << 19) /* display EH region number
holding this gimple statement. */
#define TDF_NOUID (1 << 20) /* omit UIDs from dumps. */
#define TDF_ALIAS (1 << 21) /* display alias information */
/* In tree-dump.c */

View file

@ -199,6 +199,13 @@ dump_decl_name (pretty_printer *buffer, tree node, int flags)
pp_printf (buffer, "%c.%u", c, DECL_UID (node));
}
}
if ((flags & TDF_ALIAS) && DECL_PT_UID (node) != DECL_UID (node))
{
if (flags & TDF_NOUID)
pp_printf (buffer, "ptD.xxxx");
else
pp_printf (buffer, "ptD.%u", DECL_PT_UID (node));
}
}
/* Like the above, but used for pretty printing function calls. */

View file

@ -214,7 +214,7 @@ ptr_deref_may_alias_decl_p (tree ptr, tree decl)
if (DECL_RESTRICTED_P (decl)
&& TYPE_RESTRICT (TREE_TYPE (ptr))
&& pi->pt.vars_contains_restrict)
return bitmap_bit_p (pi->pt.vars, DECL_UID (decl));
return bitmap_bit_p (pi->pt.vars, DECL_PT_UID (decl));
return pt_solution_includes (&pi->pt, decl);
}
@ -401,6 +401,9 @@ dump_points_to_solution (FILE *file, struct pt_solution *pt)
if (pt->escaped)
fprintf (file, ", points-to escaped");
if (pt->ipa_escaped)
fprintf (file, ", points-to unit escaped");
if (pt->null)
fprintf (file, ", points-to NULL");
@ -410,6 +413,8 @@ dump_points_to_solution (FILE *file, struct pt_solution *pt)
dump_decl_set (file, pt->vars);
if (pt->vars_contains_global)
fprintf (file, " (includes global vars)");
if (pt->vars_contains_restrict)
fprintf (file, " (includes restrict tags)");
}
}

View file

@ -38,9 +38,14 @@ struct GTY(()) pt_solution
even if this is zero pt_vars can still include global variables. */
unsigned int nonlocal : 1;
/* Nonzero if the points-to set includes any escaped local variable. */
/* Nonzero if the points-to set includes the local escaped solution by
reference. */
unsigned int escaped : 1;
/* Nonzero if the points-to set includes the IPA escaped solution by
reference. */
unsigned int ipa_escaped : 1;
/* Nonzero if the points-to set includes 'nothing', the points-to set
includes memory at address NULL. */
unsigned int null : 1;
@ -118,14 +123,17 @@ extern void dump_alias_stats (FILE *);
/* In tree-ssa-structalias.c */
extern unsigned int compute_may_aliases (void);
extern void delete_alias_heapvars (void);
extern bool pt_solution_empty_p (struct pt_solution *);
extern bool pt_solution_includes_global (struct pt_solution *);
extern bool pt_solution_includes (struct pt_solution *, const_tree);
extern bool pt_solutions_intersect (struct pt_solution *, struct pt_solution *);
extern bool pt_solutions_same_restrict_base (struct pt_solution *,
struct pt_solution *);
extern void pt_solution_reset (struct pt_solution *);
extern void pt_solution_set (struct pt_solution *, bitmap);
extern void pt_solution_set (struct pt_solution *, bitmap, bool, bool);
extern void dump_pta_stats (FILE *);
extern GTY(()) struct pt_solution ipa_escaped_pt;
#endif /* TREE_SSA_ALIAS_H */

File diff suppressed because it is too large Load diff

View file

@ -883,7 +883,10 @@ make_node_stat (enum tree_code code MEM_STAT_DECL)
if (TREE_CODE (t) == DEBUG_EXPR_DECL)
DECL_UID (t) = --next_debug_decl_uid;
else
DECL_UID (t) = next_decl_uid++;
{
DECL_UID (t) = next_decl_uid++;
SET_DECL_PT_UID (t, -1);
}
if (TREE_CODE (t) == LABEL_DECL)
LABEL_DECL_UID (t) = -1;
@ -963,7 +966,11 @@ copy_node_stat (tree node MEM_STAT_DECL)
if (code == DEBUG_EXPR_DECL)
DECL_UID (t) = --next_debug_decl_uid;
else
DECL_UID (t) = next_decl_uid++;
{
DECL_UID (t) = next_decl_uid++;
if (DECL_PT_UID_SET_P (node))
SET_DECL_PT_UID (t, DECL_PT_UID (node));
}
if ((TREE_CODE (node) == PARM_DECL || TREE_CODE (node) == VAR_DECL)
&& DECL_HAS_VALUE_EXPR_P (node))
{

View file

@ -2489,6 +2489,15 @@ struct function;
uses. */
#define DEBUG_TEMP_UID(NODE) (-DECL_UID (TREE_CHECK ((NODE), DEBUG_EXPR_DECL)))
/* Every ..._DECL node gets a unique number that stays the same even
when the decl is copied by the inliner once it is set. */
#define DECL_PT_UID(NODE) (DECL_MINIMAL_CHECK (NODE)->decl_minimal.pt_uid == -1u ? (NODE)->decl_minimal.uid : (NODE)->decl_minimal.pt_uid)
/* Initialize the ..._DECL node pt-uid to the decls uid. */
#define SET_DECL_PT_UID(NODE, UID) (DECL_MINIMAL_CHECK (NODE)->decl_minimal.pt_uid = (UID))
/* Whether the ..._DECL node pt-uid has been initialized and thus needs to
be preserved when copyin the decl. */
#define DECL_PT_UID_SET_P(NODE) (DECL_MINIMAL_CHECK (NODE)->decl_minimal.pt_uid != -1u)
/* These two fields describe where in the source code the declaration
was. If the declaration appears in several places (as for a C
function that is declared first and then defined later), this
@ -2512,6 +2521,7 @@ struct GTY(()) tree_decl_minimal {
struct tree_common common;
location_t locus;
unsigned int uid;
unsigned int pt_uid;
tree name;
tree context;
};