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:
parent
cbdd87d444
commit
25a6a8731c
32 changed files with 1758 additions and 183 deletions
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
50
gcc/testsuite/gcc.dg/ipa/ipa-pta-1.c
Normal file
50
gcc/testsuite/gcc.dg/ipa/ipa-pta-1.c
Normal 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" } } */
|
30
gcc/testsuite/gcc.dg/ipa/ipa-pta-10.c
Normal file
30
gcc/testsuite/gcc.dg/ipa/ipa-pta-10.c
Normal 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" } } */
|
33
gcc/testsuite/gcc.dg/ipa/ipa-pta-11.c
Normal file
33
gcc/testsuite/gcc.dg/ipa/ipa-pta-11.c
Normal 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" } } */
|
34
gcc/testsuite/gcc.dg/ipa/ipa-pta-12.c
Normal file
34
gcc/testsuite/gcc.dg/ipa/ipa-pta-12.c
Normal 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;
|
||||
}
|
56
gcc/testsuite/gcc.dg/ipa/ipa-pta-13.c
Normal file
56
gcc/testsuite/gcc.dg/ipa/ipa-pta-13.c
Normal 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" } } */
|
25
gcc/testsuite/gcc.dg/ipa/ipa-pta-2.c
Normal file
25
gcc/testsuite/gcc.dg/ipa/ipa-pta-2.c
Normal 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" } } */
|
28
gcc/testsuite/gcc.dg/ipa/ipa-pta-3.c
Normal file
28
gcc/testsuite/gcc.dg/ipa/ipa-pta-3.c
Normal 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" } } */
|
33
gcc/testsuite/gcc.dg/ipa/ipa-pta-4.c
Normal file
33
gcc/testsuite/gcc.dg/ipa/ipa-pta-4.c
Normal 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" } } */
|
26
gcc/testsuite/gcc.dg/ipa/ipa-pta-5.c
Normal file
26
gcc/testsuite/gcc.dg/ipa/ipa-pta-5.c
Normal 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" } } */
|
25
gcc/testsuite/gcc.dg/ipa/ipa-pta-6.c
Normal file
25
gcc/testsuite/gcc.dg/ipa/ipa-pta-6.c
Normal 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" } } */
|
30
gcc/testsuite/gcc.dg/ipa/ipa-pta-7.c
Normal file
30
gcc/testsuite/gcc.dg/ipa/ipa-pta-7.c
Normal 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;
|
||||
}
|
31
gcc/testsuite/gcc.dg/ipa/ipa-pta-8.c
Normal file
31
gcc/testsuite/gcc.dg/ipa/ipa-pta-8.c
Normal 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;
|
||||
}
|
17
gcc/testsuite/gcc.dg/ipa/ipa-pta-9.c
Normal file
17
gcc/testsuite/gcc.dg/ipa/ipa-pta-9.c
Normal 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;
|
||||
}
|
|
@ -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" } } */
|
||||
|
|
24
gcc/testsuite/gcc.dg/torture/ipa-pta-2.c
Normal file
24
gcc/testsuite/gcc.dg/torture/ipa-pta-2.c
Normal 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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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, " ");
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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)");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
11
gcc/tree.c
11
gcc/tree.c
|
@ -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))
|
||||
{
|
||||
|
|
10
gcc/tree.h
10
gcc/tree.h
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue