This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH][alias-improvements] "Clean up" call-clobbering
- From: Richard Guenther <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sat, 10 Jan 2009 22:26:11 +0100 (CET)
- Subject: Re: [PATCH][alias-improvements] "Clean up" call-clobbering
- References: <alpine.LNX.2.00.0901092313160.24314@zhemvz.fhfr.qr>
On Fri, 9 Jan 2009, Richard Guenther wrote:
>
> This cleans up how we "compute" call-clobbering, store it and query it.
> It properly separates points-to solution handling (struct pt_solution
> and functions to query it, pt_solution_includes, pt_solutions_intersect)
> and call-clobber and call-used queries. "computing" call-clobbering
> now boils down to
>
> find_what_var_points_to (var_escaped, &cfun->gimple_df->escaped, false);
> find_what_var_points_to (var_callused, &cfun->gimple_df->callused, false);
>
> that is, just store away the points-to solutions for ESCAPED and
> CALLUSED. Of course we now rely on that suckers to be correct - thus
> some (maybe overeager) fixes to constraints we got wrong (not that I'm
> 100% sure I got them right or even minimal).
>
> I got rid of the last place we store escape_reason - because we have no
> meaningful way to set this for all escaped variables (and we don't try
> for any). It's unused anyway.
>
> Bootstrapped and tested on x86_64-unknown-linux-gnu, scheduled for the
> branch once the current rev has gone through the automatic performance
> tests.
The following is what I applied after doing more cleanup and bugfixes.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to the
branch.
Richard.
2009-01-09 Richard Guenther <rguenther@suse.de>
* Makefile.in (GTFILES): Add tree-ssa-alias.h.
* ipa-struct-reorg.c (finalize_var_creation): Do not mark vars
call-clobbered.
* tree-dfa.c (dump_variable): Do not dump escape reason. Dump
call-used state.
(add_referenced_var): Remove call-clobber related code.
(remove_referenced_var): Likewise.
* tree-flow-inline.h (gimple_call_clobbered_vars): Remove.
(gimple_call_used_vars): Likewise.
(may_be_aliased): Take a const_tree argument.
(is_call_clobbered): Query the escaped solution if the variable
may be aliased.
(is_call_used): Query the callused solution if the variable may
be aliased.
(mark_call_clobbered): Remove.
(clear_call_clobbered): Likewise.
* tree-flow.h (struct gimple_df): Remove call_clobbered_vars and
call_used_vars, add escaped and callused solutions.
(struct var_ann): Remove escape_mask.
* tree-outof-ssa.c (create_temp): Do not fiddle with call-clobber
state.
* tree-ssa-alias.c (may_point_to_decl): Use pt_solution_includes.
(may_point_to_same_object): Use pt_solutions_intersect.
(get_ptr_info): Use pt_solution_reset.
(dump_points_to_info): Dump pt_callused state.
* tree-ssa-alias.h (struct pt_solution): Move here from tree-flow.h.
Add callused flag.
(pt_solution_includes): Declare.
(pt_solution_reset): Likewise.
(pt_solutions_intersect): Likewise.
* tree-ssa-structalias.c (handle_lhs_call): Use a scalar
NONLOCAL constraint for the return value.
(make_copy_constraint): New function.
(create_variable_info_for): Globals point to what NONLOCAL
points to.
(find_what_var_points_to): Properly separate NONLOCAL, ESCAPED,
and CALLUSED.
(clobber_what_escaped): Remove.
(compute_call_used_vars): Likewise.
(pt_solution_reset): New function.
(pt_solution_empty_p): Likewise.
(pt_solution_includes): Likewise.
(pt_solutions_intersect): Likewise.
(pt_solution_merge_into): Likewise.
(init_base_vars): Use a pointer type for the artificial variables.
Add a NONLOCAL = &NONLOCAL constraint. Add *ESCAPED = NONLOCAL
constraint. Remove *ESCAPED = &ESCAPED and *ESCAPED = &NONLOCAL
constraints.
(compute_points_to_sets): Build the ESCAPED and CALLUSED solutions.
(compute_call_clobbered): Remove.
(compute_may_aliases): Do not call compute_call_clobbered.
* tree-ssa.c (verify_call_clobbering): Remove.
(verify_alias_info): Likewise.
(verify_ssa): Do not call verify_alias_info.
(init_tree_ssa): Reset the escaped and callused solutions.
(delete_tree_ssa): Likewise.
(execute_update_addresses_taken): Do not clear call-clobber state.
testsuite/
* gcc.dg/torture/ssa-pta-fn-1.c: New testcase.
Index: alias-improvements/gcc/Makefile.in
===================================================================
*** alias-improvements.orig/gcc/Makefile.in 2009-01-10 17:25:45.000000000 +0100
--- alias-improvements/gcc/Makefile.in 2009-01-10 20:28:31.000000000 +0100
*************** GTFILES = $(CPP_ID_DATA_H) $(srcdir)/inp
*** 3329,3335 ****
$(srcdir)/tree-ssa-propagate.c \
$(srcdir)/tree-phinodes.c \
$(srcdir)/ipa-reference.c $(srcdir)/tree-ssa-structalias.h \
! $(srcdir)/tree-ssa-structalias.c \
@all_gtfiles@
# Compute the list of GT header files from the corresponding C sources,
--- 3329,3335 ----
$(srcdir)/tree-ssa-propagate.c \
$(srcdir)/tree-phinodes.c \
$(srcdir)/ipa-reference.c $(srcdir)/tree-ssa-structalias.h \
! $(srcdir)/tree-ssa-structalias.c $(srcdir)/tree-ssa-alias.h \
@all_gtfiles@
# Compute the list of GT header files from the corresponding C sources,
Index: alias-improvements/gcc/ipa-struct-reorg.c
===================================================================
*** alias-improvements.orig/gcc/ipa-struct-reorg.c 2009-01-10 17:25:45.000000000 +0100
--- alias-improvements/gcc/ipa-struct-reorg.c 2009-01-10 20:28:31.000000000 +0100
*************** static void
*** 496,503 ****
finalize_var_creation (tree new_decl)
{
add_referenced_var (new_decl);
- if (is_global_var (new_decl))
- mark_call_clobbered (new_decl, ESCAPE_UNKNOWN);
mark_sym_for_renaming (new_decl);
}
--- 496,501 ----
Index: alias-improvements/gcc/tree-dfa.c
===================================================================
*** alias-improvements.orig/gcc/tree-dfa.c 2009-01-10 17:25:45.000000000 +0100
--- alias-improvements/gcc/tree-dfa.c 2009-01-10 20:28:31.000000000 +0100
*************** dump_variable (FILE *file, tree var)
*** 308,340 ****
fprintf (file, ", is volatile");
if (is_call_clobbered (var))
! {
! const char *s = "";
! var_ann_t va = var_ann (var);
! unsigned int escape_mask = va->escape_mask;
!
! fprintf (file, ", call clobbered");
! fprintf (file, " (");
! if (escape_mask & ESCAPE_STORED_IN_GLOBAL)
! { fprintf (file, "%sstored in global", s); s = ", "; }
! if (escape_mask & ESCAPE_TO_ASM)
! { fprintf (file, "%sgoes through ASM", s); s = ", "; }
! if (escape_mask & ESCAPE_TO_CALL)
! { fprintf (file, "%spassed to call", s); s = ", "; }
! if (escape_mask & ESCAPE_BAD_CAST)
! { fprintf (file, "%sbad cast", s); s = ", "; }
! if (escape_mask & ESCAPE_TO_RETURN)
! { fprintf (file, "%sreturned from func", s); s = ", "; }
! if (escape_mask & ESCAPE_TO_PURE_CONST)
! { fprintf (file, "%spassed to pure/const", s); s = ", "; }
! if (escape_mask & ESCAPE_IS_GLOBAL)
! { fprintf (file, "%sis global var", s); s = ", "; }
! if (escape_mask & ESCAPE_IS_PARM)
! { fprintf (file, "%sis incoming pointer", s); s = ", "; }
! if (escape_mask & ESCAPE_UNKNOWN)
! { fprintf (file, "%sunknown escape", s); s = ", "; }
! fprintf (file, ")");
! }
if (ann->noalias_state == NO_ALIAS)
fprintf (file, ", NO_ALIAS (does not alias other NO_ALIAS symbols)");
--- 308,316 ----
fprintf (file, ", is volatile");
if (is_call_clobbered (var))
! fprintf (file, ", call clobbered");
! else if (is_call_used (var))
! fprintf (file, ", call used");
if (ann->noalias_state == NO_ALIAS)
fprintf (file, ", NO_ALIAS (does not alias other NO_ALIAS symbols)");
*************** add_referenced_var (tree var)
*** 622,636 ****
/* Insert VAR into the referenced_vars has table if it isn't present. */
if (referenced_var_check_and_insert (var))
{
- /* If this is a new global or addressable variable conservatively
- initialize its call-clobber state. */
- if (is_global_var (var))
- mark_call_clobbered (var, ESCAPE_IS_GLOBAL);
- else if (TREE_ADDRESSABLE (var))
- mark_call_clobbered (var, ESCAPE_UNKNOWN);
- else
- clear_call_clobbered (var);
-
/* Scan DECL_INITIAL for pointer variables as they may contain
address arithmetic referencing the address of other
variables.
--- 598,603 ----
*************** remove_referenced_var (tree var)
*** 654,661 ****
void **loc;
unsigned int uid = DECL_UID (var);
- clear_call_clobbered (var);
- bitmap_clear_bit (gimple_call_used_vars (cfun), uid);
/* Preserve var_anns of globals. */
if (!is_global_var (var)
&& (v_ann = var_ann (var)))
--- 621,626 ----
Index: alias-improvements/gcc/tree-flow-inline.h
===================================================================
*** alias-improvements.orig/gcc/tree-flow-inline.h 2009-01-10 20:28:24.000000000 +0100
--- alias-improvements/gcc/tree-flow-inline.h 2009-01-10 20:28:31.000000000 +0100
*************** gimple_in_ssa_p (const struct function *
*** 35,58 ****
return fun && fun->gimple_df && fun->gimple_df->in_ssa_p;
}
- /* Call clobbered variables in the function. If bit I is set, then
- REFERENCED_VARS (I) is call-clobbered. */
- static inline bitmap
- gimple_call_clobbered_vars (const struct function *fun)
- {
- gcc_assert (fun && fun->gimple_df);
- return fun->gimple_df->call_clobbered_vars;
- }
-
- /* Call-used variables in the function. If bit I is set, then
- REFERENCED_VARS (I) is call-used at pure function call-sites. */
- static inline bitmap
- gimple_call_used_vars (const struct function *fun)
- {
- gcc_assert (fun && fun->gimple_df);
- return fun->gimple_df->call_used_vars;
- }
-
/* Array of all variables referenced in the function. */
static inline htab_t
gimple_referenced_vars (const struct function *fun)
--- 35,40 ----
*************** is_global_var (const_tree t)
*** 577,583 ****
or possibly by another TU. */
static inline bool
! may_be_aliased (tree var)
{
return (TREE_PUBLIC (var) || DECL_EXTERNAL (var) || TREE_ADDRESSABLE (var));
}
--- 559,565 ----
or possibly by another TU. */
static inline bool
! may_be_aliased (const_tree var)
{
return (TREE_PUBLIC (var) || DECL_EXTERNAL (var) || TREE_ADDRESSABLE (var));
}
*************** static inline bool
*** 617,623 ****
is_call_clobbered (const_tree var)
{
return (is_global_var (var)
! || bitmap_bit_p (gimple_call_clobbered_vars (cfun), DECL_UID (var)));
}
/* Return true if VAR is used by function calls. */
--- 599,606 ----
is_call_clobbered (const_tree var)
{
return (is_global_var (var)
! || (may_be_aliased (var)
! && pt_solution_includes (&cfun->gimple_df->escaped, var)));
}
/* Return true if VAR is used by function calls. */
*************** static inline bool
*** 625,651 ****
is_call_used (const_tree var)
{
return (is_call_clobbered (var)
! || bitmap_bit_p (gimple_call_used_vars (cfun), DECL_UID (var)));
! }
!
! /* Mark variable VAR as being clobbered by function calls. */
! static inline void
! mark_call_clobbered (tree var, unsigned int escape_type)
! {
! if (is_global_var (var))
! return;
! var_ann (var)->escape_mask |= escape_type;
! bitmap_set_bit (gimple_call_clobbered_vars (cfun), DECL_UID (var));
! }
!
! /* Clear the call-clobbered attribute from variable VAR. */
! static inline void
! clear_call_clobbered (tree var)
! {
! if (is_global_var (var))
! return;
! var_ann (var)->escape_mask = 0;
! bitmap_clear_bit (gimple_call_clobbered_vars (cfun), DECL_UID (var));
}
/* Return the common annotation for T. Return NULL if the annotation
--- 608,615 ----
is_call_used (const_tree var)
{
return (is_call_clobbered (var)
! || (may_be_aliased (var)
! && pt_solution_includes (&cfun->gimple_df->callused, var)));
}
/* Return the common annotation for T. Return NULL if the annotation
Index: alias-improvements/gcc/tree-flow.h
===================================================================
*** alias-improvements.orig/gcc/tree-flow.h 2009-01-10 17:25:45.000000000 +0100
--- alias-improvements/gcc/tree-flow.h 2009-01-10 20:28:31.000000000 +0100
*************** struct gimple_df GTY(())
*** 67,79 ****
variables. */
tree nonlocal_all;
! /* Call clobbered variables in the function. If bit I is set, then
! REFERENCED_VARS (I) is call-clobbered. */
! bitmap call_clobbered_vars;
!
! /* Call-used variables in the function. If bit I is set, then
! REFERENCED_VARS (I) is call-used at pure function call-sites. */
! bitmap call_used_vars;
/* Free list of SSA_NAMEs. */
tree free_ssanames;
--- 67,77 ----
variables. */
tree nonlocal_all;
! /* The PTA solution for the ESCAPED artificial variable. */
! struct pt_solution escaped;
!
! /* The PTA solution for the CALLUSED artificial variable. */
! struct pt_solution callused;
/* Free list of SSA_NAMEs. */
tree free_ssanames;
*************** struct ptr_info_def GTY(())
*** 129,162 ****
/* Nonzero if this pointer is really dereferenced. */
unsigned int is_dereferenced : 1;
! /* The points-to solution.
!
! The points-to solution is a union of pt_vars and the abstract
! sets specified by the flags. */
! struct pt_solution
! {
! /* Nonzero if points-to analysis couldn't determine where this pointer
! is pointing to. */
! unsigned int anything : 1;
!
! /* Nonzero if the points-to set includes any global memory. Note that
! 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. */
! unsigned int escaped : 1;
!
! /* Nonzero if the points-to set includes 'nothing', the points-to set
! includes memory at address NULL. */
! unsigned int null : 1;
!
!
! /* Nonzero if the pt_vars bitmap includes a global variable. */
! unsigned int vars_contains_global : 1;
!
! /* Set of variables that this pointer may point to. */
! bitmap vars;
! } pt;
};
--- 127,134 ----
/* Nonzero if this pointer is really dereferenced. */
unsigned int is_dereferenced : 1;
! /* The points-to solution. */
! struct pt_solution pt;
};
*************** struct var_ann_d GTY(())
*** 271,280 ****
information on each attribute. */
ENUM_BITFIELD (noalias_state) noalias_state : 2;
- /* Mask of values saying the reasons why this variable has escaped
- the function. */
- ENUM_BITFIELD (escape_type) escape_mask : 9;
-
/* Used when going out of SSA form to indicate which partition this
variable represents storage for. */
unsigned partition;
--- 243,248 ----
*************** char *get_lsm_tmp_name (tree, unsigned);
*** 910,916 ****
/* In tree-flow-inline.h */
static inline bool is_call_clobbered (const_tree);
- static inline void mark_call_clobbered (tree, unsigned int);
static inline void set_is_used (tree);
static inline bool unmodifiable_var_p (const_tree);
static inline bool ref_contains_array_ref (const_tree);
--- 878,883 ----
Index: alias-improvements/gcc/tree-outof-ssa.c
===================================================================
*** alias-improvements.orig/gcc/tree-outof-ssa.c 2009-01-10 17:25:45.000000000 +0100
--- alias-improvements/gcc/tree-outof-ssa.c 2009-01-10 20:28:31.000000000 +0100
*************** create_temp (tree t)
*** 122,134 ****
DECL_GIMPLE_REG_P (tmp) = DECL_GIMPLE_REG_P (t);
add_referenced_var (tmp);
! /* add_referenced_var will create the annotation and set up some
! of the flags in the annotation. However, some flags we need to
! inherit from our original variable. */
! if (is_call_clobbered (t))
! mark_call_clobbered (tmp, var_ann (t)->escape_mask);
! if (bitmap_bit_p (gimple_call_used_vars (cfun), DECL_UID (t)))
! bitmap_set_bit (gimple_call_used_vars (cfun), DECL_UID (tmp));
return tmp;
}
--- 122,131 ----
DECL_GIMPLE_REG_P (tmp) = DECL_GIMPLE_REG_P (t);
add_referenced_var (tmp);
! /* We should never have copied variables in non-automatic storage
! or variables that have their address taken. So it is pointless
! to try to copy call-clobber state here. */
! gcc_assert (!may_be_aliased (t) && !is_global_var (t));
return tmp;
}
Index: alias-improvements/gcc/tree-ssa-alias.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-alias.c 2009-01-10 17:25:45.000000000 +0100
--- alias-improvements/gcc/tree-ssa-alias.c 2009-01-10 20:28:31.000000000 +0100
*************** may_point_to_decl (tree ptr, tree decl)
*** 118,137 ****
/* If we do not have useful points-to information for this pointer
we cannot disambiguate anything else. */
pi = SSA_NAME_PTR_INFO (ptr);
! if (!pi
! || pi->pt.anything)
return true;
! /* If the points-to set includes the variable we are done. */
! if (bitmap_bit_p (pi->pt.vars, DECL_UID (decl)))
! return true;
!
! /* pt_nonlocal includes any global variable. */
! if (is_global_var (decl)
! && pi->pt.nonlocal)
! return true;
!
! return false;
}
/* Return true if PTR1 and PTR2 may point to the same memory object. */
--- 118,127 ----
/* If we do not have useful points-to information for this pointer
we cannot disambiguate anything else. */
pi = SSA_NAME_PTR_INFO (ptr);
! if (!pi)
return true;
! return pt_solution_includes (&pi->pt, decl);
}
/* Return true if PTR1 and PTR2 may point to the same memory object. */
*************** may_point_to_same_object (tree ptr1, tre
*** 163,185 ****
we cannot disambiguate anything else. */
pi1 = SSA_NAME_PTR_INFO (ptr1);
pi2 = SSA_NAME_PTR_INFO (ptr2);
! if (!pi1 || !pi2
! || pi1->pt.anything || pi2->pt.anything)
! return true;
!
! /* If either points to unknown global memory and the other points to
! any global memory they alias. */
! if ((pi1->pt.nonlocal
! && (pi2->pt.nonlocal
! || pi2->pt.vars_contains_global))
! || (pi2->pt.nonlocal
! && pi1->pt.vars_contains_global))
return true;
! /* Now both pointers alias if their points-to solution intersects. */
! return (pi1->pt.vars
! && pi2->pt.vars
! && bitmap_intersect_p (pi1->pt.vars, pi2->pt.vars));
}
/* Return true if STMT is an "escape" site from the current function. Escape
--- 153,162 ----
we cannot disambiguate anything else. */
pi1 = SSA_NAME_PTR_INFO (ptr1);
pi2 = SSA_NAME_PTR_INFO (ptr2);
! if (!pi1 || !pi2)
return true;
! return pt_solutions_intersect (&pi1->pt, &pi2->pt);
}
/* Return true if STMT is an "escape" site from the current function. Escape
*************** get_ptr_info (tree t)
*** 323,329 ****
if (pi == NULL)
{
pi = GGC_CNEW (struct ptr_info_def);
! pi->pt.anything = 1;
SSA_NAME_PTR_INFO (t) = pi;
}
--- 300,306 ----
if (pi == NULL)
{
pi = GGC_CNEW (struct ptr_info_def);
! pt_solution_reset (&pi->pt);
SSA_NAME_PTR_INFO (t) = pi;
}
*************** dump_points_to_info_for (FILE *file, tre
*** 353,358 ****
--- 330,338 ----
if (pi->pt.escaped)
fprintf (file, ", points-to escaped");
+ if (pi->pt.callused)
+ fprintf (file, ", points-to call-used");
+
if (pi->pt.null)
fprintf (file, ", points-to NULL");
Index: alias-improvements/gcc/tree-ssa-alias.h
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-alias.h 2009-01-10 17:25:45.000000000 +0100
--- alias-improvements/gcc/tree-ssa-alias.h 2009-01-10 20:28:31.000000000 +0100
*************** enum escape_type
*** 43,48 ****
--- 43,82 ----
above. */
};
+
+ /* The points-to solution.
+
+ The points-to solution is a union of pt_vars and the abstract
+ sets specified by the flags. */
+ struct pt_solution GTY(())
+ {
+ /* Nonzero if points-to analysis couldn't determine where this pointer
+ is pointing to. */
+ unsigned int anything : 1;
+
+ /* Nonzero if the points-to set includes any global memory. Note that
+ 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. */
+ unsigned int escaped : 1;
+
+ /* Nonzero if the points-to set includes any callused variable. */
+ unsigned int callused : 1;
+
+ /* Nonzero if the points-to set includes 'nothing', the points-to set
+ includes memory at address NULL. */
+ unsigned int null : 1;
+
+
+ /* Nonzero if the pt_vars bitmap includes a global variable. */
+ unsigned int vars_contains_global : 1;
+
+ /* Set of variables that this pointer may point to. */
+ bitmap vars;
+ };
+
+
/* In tree-ssa-alias.c */
extern enum escape_type is_escape_site (gimple);
extern bool may_point_to_global_var (tree);
*************** extern void debug_points_to_info_for (tr
*** 62,67 ****
--- 96,104 ----
/* In tree-ssa-structalias.c */
extern unsigned int compute_may_aliases (void);
extern void delete_alias_heapvars (void);
+ extern bool pt_solution_includes (struct pt_solution *, const_tree);
+ extern bool pt_solutions_intersect (struct pt_solution *, struct pt_solution *);
+ extern void pt_solution_reset (struct pt_solution *);
/* In tree-dfa.c */
Index: alias-improvements/gcc/tree-ssa-structalias.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-structalias.c 2009-01-10 17:25:45.000000000 +0100
--- alias-improvements/gcc/tree-ssa-structalias.c 2009-01-10 21:02:42.000000000 +0100
*************** handle_lhs_call (tree lhs, int flags)
*** 3510,3518 ****
}
else
{
! rhsc.var = escaped_id;
rhsc.offset = 0;
! rhsc.type = ADDRESSOF;
}
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
process_constraint (new_constraint (*lhsp, rhsc));
--- 3510,3518 ----
}
else
{
! rhsc.var = nonlocal_id;
rhsc.offset = 0;
! rhsc.type = SCALAR;
}
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
process_constraint (new_constraint (*lhsp, rhsc));
*************** make_constraint_from (varinfo_t vi, int
*** 4191,4196 ****
--- 4191,4213 ----
process_constraint (new_constraint (lhs, rhs));
}
+ /* Create a constraint ID = FROM. */
+
+ static void
+ make_copy_constraint (varinfo_t vi, int from)
+ {
+ struct constraint_expr lhs, rhs;
+
+ lhs.var = vi->id;
+ lhs.offset = 0;
+ lhs.type = SCALAR;
+
+ rhs.var = from;
+ rhs.offset = 0;
+ rhs.type = SCALAR;
+ process_constraint (new_constraint (lhs, rhs));
+ }
+
/* Count the number of arguments DECL has, and set IS_VARARGS to true
if it is a varargs function. */
*************** create_variable_info_for (tree decl, con
*** 4391,4397 ****
&& var_ann (decl)->noalias_state == NO_ALIAS_ANYTHING)
make_constraint_from (vi, vi->id);
else
! make_constraint_from (vi, escaped_id);
}
stats.total_vars++;
--- 4408,4414 ----
&& var_ann (decl)->noalias_state == NO_ALIAS_ANYTHING)
make_constraint_from (vi, vi->id);
else
! make_copy_constraint (vi, nonlocal_id);
}
stats.total_vars++;
*************** create_variable_info_for (tree decl, con
*** 4471,4477 ****
VEC_safe_push (varinfo_t, heap, varmap, newvi);
if (is_global && (!flag_whole_program || !in_ipa_mode)
&& fo->may_have_pointers)
! make_constraint_from (newvi, escaped_id);
stats.total_vars++;
}
--- 4488,4494 ----
VEC_safe_push (varinfo_t, heap, varmap, newvi);
if (is_global && (!flag_whole_program || !in_ipa_mode)
&& fo->may_have_pointers)
! make_copy_constraint (newvi, nonlocal_id);
stats.total_vars++;
}
*************** find_what_var_points_to (varinfo_t vi, s
*** 4913,4931 ****
if (vi->id == nothing_id)
pt->null = 1;
else if (vi->id == escaped_id)
! {
! pt->escaped = 1;
! /* ??? We need to compute the escaped solution and store
! it somewhere. */
! pt->anything = 1;
! }
else if (vi->id == nonlocal_id)
pt->nonlocal = 1;
else if (vi->is_heap_var)
/* We represent heapvars in the points-to set properly. */
;
else if (vi->id == anything_id
- || vi->id == callused_id
|| vi->id == readonly_id
|| vi->id == integer_id)
pt->anything = 1;
--- 4930,4944 ----
if (vi->id == nothing_id)
pt->null = 1;
else if (vi->id == escaped_id)
! pt->escaped = 1;
! else if (vi->id == callused_id)
! pt->callused = 1;
else if (vi->id == nonlocal_id)
pt->nonlocal = 1;
else if (vi->is_heap_var)
/* We represent heapvars in the points-to set properly. */
;
else if (vi->id == anything_id
|| vi->id == readonly_id
|| vi->id == integer_id)
pt->anything = 1;
*************** find_what_p_points_to (tree p)
*** 5008,5122 ****
}
}
! /* Mark the ESCAPED solution as call clobbered. Returns false if
! pt_anything escaped which needs all locals that have their address
! taken marked call clobbered as well. */
static bool
! clobber_what_escaped (void)
{
! varinfo_t vi;
! unsigned int i;
! bitmap_iterator bi;
! if (!have_alias_info)
return false;
! /* This variable may have been collapsed, let's get the real
! variable for escaped_id. */
! vi = get_varinfo (find (escaped_id));
! /* If call-used memory escapes we need to include it in the
! set of escaped variables. This can happen if a pure
! function returns a pointer and this pointer escapes. */
! if (bitmap_bit_p (vi->solution, callused_id))
! {
! varinfo_t cu_vi = get_varinfo (find (callused_id));
! bitmap_ior_into (vi->solution, cu_vi->solution);
! }
! /* Mark variables in the solution call-clobbered. */
! EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
! {
! varinfo_t vi = get_varinfo (i);
! if (vi->is_artificial_var)
! {
! /* nothing_id and readonly_id do not cause any
! call clobber ops. For anything_id and integer_id
! we need to clobber all addressable vars. */
! if (vi->id == anything_id
! || vi->id == integer_id)
! return false;
! }
! /* Only artificial heap-vars are further interesting. */
! if (vi->is_artificial_var && !vi->is_heap_var)
! continue;
! if ((TREE_CODE (vi->decl) == VAR_DECL
! || TREE_CODE (vi->decl) == PARM_DECL
! || TREE_CODE (vi->decl) == RESULT_DECL)
! && !unmodifiable_var_p (vi->decl))
! mark_call_clobbered (vi->decl, ESCAPE_TO_CALL);
! }
! return true;
! }
! /* Compute the call-used variables. */
! static void
! compute_call_used_vars (void)
! {
! varinfo_t vi;
! unsigned int i;
! bitmap_iterator bi;
! bool has_anything_id = false;
! if (!have_alias_info)
! return;
! /* This variable may have been collapsed, let's get the real
! variable for escaped_id. */
! vi = get_varinfo (find (callused_id));
! /* Mark variables in the solution call-clobbered. */
! EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
! {
! varinfo_t vi = get_varinfo (i);
! if (vi->is_artificial_var)
! {
! /* For anything_id and integer_id we need to make
! all local addressable vars call-used. */
! if (vi->id == anything_id
! || vi->id == integer_id)
! has_anything_id = true;
! }
! /* Only artificial heap-vars are further interesting. */
! if (vi->is_artificial_var && !vi->is_heap_var)
! continue;
! if ((TREE_CODE (vi->decl) == VAR_DECL
! || TREE_CODE (vi->decl) == PARM_DECL
! || TREE_CODE (vi->decl) == RESULT_DECL)
! && !unmodifiable_var_p (vi->decl))
! bitmap_set_bit (gimple_call_used_vars (cfun), DECL_UID (vi->decl));
! }
!
! /* If anything is call-used, add all addressable locals to the set. */
! if (has_anything_id)
! {
! referenced_var_iterator rvi;
! tree var;
!
! FOR_EACH_REFERENCED_VAR (var, rvi)
! if (!is_global_var (var)
! && TREE_ADDRESSABLE (var))
! bitmap_set_bit (gimple_call_used_vars (cfun), DECL_UID (var));
}
}
--- 5021,5174 ----
}
}
! /* Reset the points-to solution *PT to a conservative default
! (point to anything). */
!
! void
! pt_solution_reset (struct pt_solution *pt)
! {
! memset (pt, 0, sizeof (struct pt_solution));
! pt->anything = true;
! }
!
! /* Return true if the points-to solution *PT is empty. */
static bool
! pt_solution_empty_p (struct pt_solution *pt)
{
! if (pt->anything
! || pt->nonlocal)
! return false;
! if (pt->vars
! && !bitmap_empty_p (pt->vars))
return false;
! /* If this isn't already the escaped solution, check if that is empty. */
! if (pt->escaped
! && &cfun->gimple_df->escaped != pt
! && !pt_solution_empty_p (&cfun->gimple_df->escaped))
! return false;
! /* If this isn't already the callused solution, check if that is empty. */
! if (pt->callused
! && &cfun->gimple_df->callused != pt
! && !pt_solution_empty_p (&cfun->gimple_df->callused))
! return false;
! return true;
! }
! /* Return true if the points-to solution *PT includes the variable
! declaration DECL. */
! bool
! pt_solution_includes (struct pt_solution *pt, const_tree decl)
! {
! if (pt->anything)
! return true;
! if (pt->nonlocal
! && is_global_var (decl))
! return true;
! if (bitmap_bit_p (pt->vars, DECL_UID (decl)))
! return true;
! /* If this isn't already the escaped solution, union it with that. */
! if (pt->escaped
! && &cfun->gimple_df->escaped != pt
! && pt_solution_includes (&cfun->gimple_df->escaped, decl))
! return true;
! /* If this isn't already the callused solution, union it with that. */
! if (pt->callused
! && &cfun->gimple_df->callused != pt
! && pt_solution_includes (&cfun->gimple_df->callused, decl))
! return true;
! return false;
! }
! /* Return true if both points-to solutions PT1 and PT2 have a non-empty
! intersection. */
! bool
! pt_solutions_intersect (struct pt_solution *pt1, struct pt_solution *pt2)
! {
! if (pt1->anything || pt2->anything)
! return true;
! /* If either points to unknown global memory and the other points to
! any global memory they alias. */
! if ((pt1->nonlocal
! && (pt2->nonlocal
! || pt2->vars_contains_global))
! || (pt2->nonlocal
! && pt1->vars_contains_global))
! return true;
! /* Check the escaped solution if required. */
! if ((pt1->escaped || pt1 == &cfun->gimple_df->escaped
! || pt2->escaped || pt2 == &cfun->gimple_df->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 || pt1 == &cfun->gimple_df->escaped)
! && (pt2->escaped || pt2 == &cfun->gimple_df->escaped))
! return true;
!
! /* If either points to escaped memory see if the escaped solution
! intersects. */
! if (((pt1->escaped || pt1 == &cfun->gimple_df->escaped)
! && pt_solutions_intersect (&cfun->gimple_df->escaped, pt1))
! || ((pt2->escaped || pt2 == &cfun->gimple_df->escaped)
! && pt_solutions_intersect (&cfun->gimple_df->escaped, pt2)))
! return true;
! }
! /* Check the callused solution if required. */
! if ((pt1->callused || pt1 == &cfun->gimple_df->callused
! || pt2->callused || pt2 == &cfun->gimple_df->callused)
! && !pt_solution_empty_p (&cfun->gimple_df->callused))
! {
! /* If both point to callused memory and that solution
! is not empty they alias. */
! if ((pt1->callused || pt1 == &cfun->gimple_df->callused)
! && (pt2->callused || pt2 == &cfun->gimple_df->callused))
! return true;
!
! /* If either points to callused memory see if the callused solution
! intersects. */
! if (((pt1->callused || pt1 == &cfun->gimple_df->callused)
! && pt_solutions_intersect (&cfun->gimple_df->callused, pt1))
! || ((pt2->callused || pt2 == &cfun->gimple_df->callused)
! && pt_solutions_intersect (&cfun->gimple_df->callused, pt2)))
! return true;
}
+
+ /* Now both pointers alias if their points-to solution intersects. */
+ return (pt1->vars
+ && pt2->vars
+ && bitmap_intersect_p (pt1->vars, pt2->vars));
+ }
+
+ /* Merge the solution SRC into the solution DEST. */
+
+ static void
+ pt_solution_merge_into (struct pt_solution *dest, struct pt_solution *src)
+ {
+ dest->anything |= src->anything;
+ dest->nonlocal |= src->nonlocal;
+ dest->escaped |= src->escaped;
+ dest->callused |= src->callused;
+ dest->null |= src->null;
+ dest->vars_contains_global |= src->vars_contains_global;
+ if (src->vars && dest->vars)
+ bitmap_ior_into (dest->vars, src->vars);
+ else if (src->vars)
+ dest->vars = src->vars;
}
*************** init_base_vars (void)
*** 5181,5187 ****
/* Create the ANYTHING variable, used to represent that a variable
points to some unknown piece of memory. */
! anything_tree = create_tmp_var_raw (void_type_node, "ANYTHING");
var_anything = new_var_info (anything_tree, anything_id, "ANYTHING");
insert_vi_for_tree (anything_tree, var_anything);
var_anything->is_artificial_var = 1;
--- 5233,5239 ----
/* Create the ANYTHING variable, used to represent that a variable
points to some unknown piece of memory. */
! anything_tree = create_tmp_var_raw (ptr_type_node, "ANYTHING");
var_anything = new_var_info (anything_tree, anything_id, "ANYTHING");
insert_vi_for_tree (anything_tree, var_anything);
var_anything->is_artificial_var = 1;
*************** init_base_vars (void)
*** 5209,5215 ****
/* Create the READONLY variable, used to represent that a variable
points to readonly memory. */
! readonly_tree = create_tmp_var_raw (void_type_node, "READONLY");
var_readonly = new_var_info (readonly_tree, readonly_id, "READONLY");
var_readonly->is_artificial_var = 1;
var_readonly->offset = 0;
--- 5261,5267 ----
/* Create the READONLY variable, used to represent that a variable
points to readonly memory. */
! readonly_tree = create_tmp_var_raw (ptr_type_node, "READONLY");
var_readonly = new_var_info (readonly_tree, readonly_id, "READONLY");
var_readonly->is_artificial_var = 1;
var_readonly->offset = 0;
*************** init_base_vars (void)
*** 5234,5240 ****
/* Create the ESCAPED variable, used to represent the set of escaped
memory. */
! escaped_tree = create_tmp_var_raw (void_type_node, "ESCAPED");
var_escaped = new_var_info (escaped_tree, escaped_id, "ESCAPED");
insert_vi_for_tree (escaped_tree, var_escaped);
var_escaped->is_artificial_var = 1;
--- 5286,5292 ----
/* Create the ESCAPED variable, used to represent the set of escaped
memory. */
! escaped_tree = create_tmp_var_raw (ptr_type_node, "ESCAPED");
var_escaped = new_var_info (escaped_tree, escaped_id, "ESCAPED");
insert_vi_for_tree (escaped_tree, var_escaped);
var_escaped->is_artificial_var = 1;
*************** init_base_vars (void)
*** 5245,5262 ****
VEC_safe_push (varinfo_t, heap, varmap, var_escaped);
gcc_assert (VEC_index (varinfo_t, varmap, 3) == var_escaped);
- /* ESCAPED = *ESCAPED, because escaped is may-deref'd at calls, etc. */
- lhs.type = SCALAR;
- lhs.var = escaped_id;
- lhs.offset = 0;
- rhs.type = DEREF;
- rhs.var = escaped_id;
- rhs.offset = 0;
- process_constraint (new_constraint (lhs, rhs));
-
/* Create the NONLOCAL variable, used to represent the set of nonlocal
memory. */
! nonlocal_tree = create_tmp_var_raw (void_type_node, "NONLOCAL");
var_nonlocal = new_var_info (nonlocal_tree, nonlocal_id, "NONLOCAL");
insert_vi_for_tree (nonlocal_tree, var_nonlocal);
var_nonlocal->is_artificial_var = 1;
--- 5297,5305 ----
VEC_safe_push (varinfo_t, heap, varmap, var_escaped);
gcc_assert (VEC_index (varinfo_t, varmap, 3) == var_escaped);
/* Create the NONLOCAL variable, used to represent the set of nonlocal
memory. */
! nonlocal_tree = create_tmp_var_raw (ptr_type_node, "NONLOCAL");
var_nonlocal = new_var_info (nonlocal_tree, nonlocal_id, "NONLOCAL");
insert_vi_for_tree (nonlocal_tree, var_nonlocal);
var_nonlocal->is_artificial_var = 1;
*************** init_base_vars (void)
*** 5266,5284 ****
var_nonlocal->is_special_var = 1;
VEC_safe_push (varinfo_t, heap, varmap, var_nonlocal);
! /* Nonlocal memory points to escaped (which includes nonlocal),
! in order to make deref easier. */
lhs.type = SCALAR;
lhs.var = nonlocal_id;
lhs.offset = 0;
rhs.type = ADDRESSOF;
rhs.var = escaped_id;
rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs));
/* Create the CALLUSED variable, used to represent the set of call-used
memory. */
! callused_tree = create_tmp_var_raw (void_type_node, "CALLUSED");
var_callused = new_var_info (callused_tree, callused_id, "CALLUSED");
insert_vi_for_tree (callused_tree, var_callused);
var_callused->is_artificial_var = 1;
--- 5309,5351 ----
var_nonlocal->is_special_var = 1;
VEC_safe_push (varinfo_t, heap, varmap, var_nonlocal);
! /* ESCAPED = *ESCAPED, because escaped is may-deref'd at calls, etc. */
! lhs.type = SCALAR;
! lhs.var = escaped_id;
! lhs.offset = 0;
! rhs.type = DEREF;
! rhs.var = escaped_id;
! rhs.offset = 0;
! process_constraint (new_constraint (lhs, rhs));
!
! /* *ESCAPED = NONLOCAL. This is true because we have to assume
! everything pointed to by escaped points to what global memory can
! point to. */
! lhs.type = DEREF;
! lhs.var = escaped_id;
! lhs.offset = 0;
! rhs.type = SCALAR;
! rhs.var = nonlocal_id;
! rhs.offset = 0;
! process_constraint (new_constraint (lhs, rhs));
!
! /* NONLOCAL = &NONLOCAL, NONLOCAL = &ESCAPED. This is true because
! global memory may point to global memory and escaped memory. */
lhs.type = SCALAR;
lhs.var = nonlocal_id;
lhs.offset = 0;
rhs.type = ADDRESSOF;
+ rhs.var = nonlocal_id;
+ rhs.offset = 0;
+ process_constraint (new_constraint (lhs, rhs));
+ rhs.type = ADDRESSOF;
rhs.var = escaped_id;
rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs));
/* Create the CALLUSED variable, used to represent the set of call-used
memory. */
! callused_tree = create_tmp_var_raw (ptr_type_node, "CALLUSED");
var_callused = new_var_info (callused_tree, callused_id, "CALLUSED");
insert_vi_for_tree (callused_tree, var_callused);
var_callused->is_artificial_var = 1;
*************** init_base_vars (void)
*** 5298,5305 ****
process_constraint (new_constraint (lhs, rhs));
/* Create the INTEGER variable, used to represent that a variable points
! to an INTEGER. */
! integer_tree = create_tmp_var_raw (void_type_node, "INTEGER");
var_integer = new_var_info (integer_tree, integer_id, "INTEGER");
insert_vi_for_tree (integer_tree, var_integer);
var_integer->is_artificial_var = 1;
--- 5365,5372 ----
process_constraint (new_constraint (lhs, rhs));
/* Create the INTEGER variable, used to represent that a variable points
! to what an INTEGER "points to". */
! integer_tree = create_tmp_var_raw (ptr_type_node, "INTEGER");
var_integer = new_var_info (integer_tree, integer_id, "INTEGER");
insert_vi_for_tree (integer_tree, var_integer);
var_integer->is_artificial_var = 1;
*************** init_base_vars (void)
*** 5319,5344 ****
rhs.var = anything_id;
rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs));
-
- /* *ESCAPED = &ESCAPED. This is true because we have to assume
- everything pointed to by escaped can also point to escaped. */
- lhs.type = DEREF;
- lhs.var = escaped_id;
- lhs.offset = 0;
- rhs.type = ADDRESSOF;
- rhs.var = escaped_id;
- rhs.offset = 0;
- process_constraint (new_constraint (lhs, rhs));
-
- /* *ESCAPED = &NONLOCAL. This is true because we have to assume
- everything pointed to by escaped can also point to nonlocal. */
- lhs.type = DEREF;
- lhs.var = escaped_id;
- lhs.offset = 0;
- rhs.type = ADDRESSOF;
- rhs.var = nonlocal_id;
- rhs.offset = 0;
- process_constraint (new_constraint (lhs, rhs));
}
/* Initialize things necessary to perform PTA */
--- 5386,5391 ----
*************** compute_points_to_sets (void)
*** 5693,5698 ****
--- 5740,5746 ----
if (dump_file)
dump_sa_points_to_info (dump_file);
+ /* Compute the points-to sets for pointer SSA_NAMEs. */
for (i = 0; i < num_ssa_names; ++i)
{
tree ptr = ssa_name (i);
*************** compute_points_to_sets (void)
*** 5701,5706 ****
--- 5749,5770 ----
find_what_p_points_to (ptr);
}
+ /* Compute the points-to sets for ESCAPED and CALLUSED used for
+ call-clobber analysis. */
+ find_what_var_points_to (var_escaped, &cfun->gimple_df->escaped, false);
+ find_what_var_points_to (var_callused, &cfun->gimple_df->callused, false);
+ /* If both include each other merge and separate them to avoid running
+ in circles during queries of these placeholder solutions. */
+ if (cfun->gimple_df->escaped.callused
+ && cfun->gimple_df->callused.escaped)
+ {
+ pt_solution_merge_into (&cfun->gimple_df->escaped,
+ &cfun->gimple_df->callused);
+ cfun->gimple_df->callused = cfun->gimple_df->escaped;
+ cfun->gimple_df->escaped.callused = false;
+ cfun->gimple_df->callused.escaped = false;
+ }
+
timevar_pop (TV_TREE_PTA);
have_alias_info = true;
*************** delete_points_to_sets (void)
*** 5741,5808 ****
}
- /* Transfer the call-clobber solutions from the points-to solution
- to the call-clobber state of the variables.
-
- The set of call-clobbered variables is the union of all global
- variables and the set denoted by the gimple_call_clobbered_vars
- bitmap. The maximal set of the gimple_call_clobbered_vars bitmap
- is all local aliased variables (all locals that have their address
- taken).
-
- The set of call-used variables is the union of all call-clobbered
- variables and the set denoted by the gimple_call_used_vars bitmap.
- Call-used variables get added to by escapes through pure functions. */
-
- static void
- compute_call_clobbered (void)
- {
- referenced_var_iterator rvi;
- tree var;
- bool any_pt_anything = false;
- enum escape_type pt_anything_mask = 0;
-
- timevar_push (TV_CALL_CLOBBER);
-
- /* Clear the set of call-clobbered and call-used variables. */
- bitmap_clear (gimple_call_clobbered_vars (cfun));
- bitmap_clear (gimple_call_used_vars (cfun));
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- if (is_global_var (var))
- {
- if (!unmodifiable_var_p (var))
- mark_call_clobbered (var, ESCAPE_IS_GLOBAL);
- }
- }
-
- if (!clobber_what_escaped ())
- {
- any_pt_anything = true;
- pt_anything_mask |= ESCAPE_TO_CALL;
- }
-
- compute_call_used_vars ();
-
- /* If a pt_anything pointer escaped we need to mark all addressable
- variables call clobbered. */
- if (any_pt_anything)
- {
- referenced_var_iterator rvi;
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- if (TREE_ADDRESSABLE (var)
- && !unmodifiable_var_p (var))
- mark_call_clobbered (var, pt_anything_mask);
- }
- }
-
- timevar_pop (TV_CALL_CLOBBER);
- }
-
-
/* Compute points-to information for every SSA_NAME pointer in the
current function and compute the transitive closure of escaped
variables to re-initialize the call-clobber states of local variables. */
--- 5805,5810 ----
*************** compute_may_aliases (void)
*** 5814,5823 ****
point-to. Compute the reachability set of escaped and call-used
variables. */
compute_points_to_sets ();
-
- /* Transfer the points-to solutions of ESCAPED and CALLUSED to the
- call clobbering information. */
- compute_call_clobbered ();
/* Debugging dumps. */
if (dump_file)
--- 5816,5821 ----
Index: alias-improvements/gcc/tree-ssa.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa.c 2009-01-10 20:28:24.000000000 +0100
--- alias-improvements/gcc/tree-ssa.c 2009-01-10 20:28:31.000000000 +0100
*************** error:
*** 511,557 ****
}
- /* Verify the consistency of call clobbering information. */
-
- static void
- verify_call_clobbering (void)
- {
- unsigned int i;
- bitmap_iterator bi;
- tree var;
-
- /* At all times, the result of the call_clobbered flag should
- match the result of the call_clobbered_vars bitmap. Verify both
- that everything in call_clobbered_vars is marked
- call_clobbered, and that everything marked
- call_clobbered is in call_clobbered_vars. */
- EXECUTE_IF_SET_IN_BITMAP (gimple_call_clobbered_vars (cfun), 0, i, bi)
- {
- var = referenced_var (i);
- if (is_global_var (var))
- {
- error ("global variable in call_clobbered_vars");
- debug_variable (var);
- goto err;
- }
- }
-
- return;
-
- err:
- internal_error ("verify_call_clobbering failed");
- }
-
-
- /* Verify the consistency of aliasing information. */
-
- static void
- verify_alias_info (void)
- {
- verify_call_clobbering ();
- }
-
-
/* Verify common invariants in the SSA web.
TODO: verify the variable annotations. */
--- 511,516 ----
*************** verify_ssa (bool check_modified_stmt)
*** 692,700 ****
bitmap_clear (names_defined_in_bb);
}
- /* Finally, verify alias information. */
- verify_alias_info ();
-
free (definition_block);
/* Restore the dominance information to its prior known state, so
--- 651,656 ----
*************** init_tree_ssa (struct function *fn)
*** 777,784 ****
uid_decl_map_eq, NULL);
fn->gimple_df->default_defs = htab_create_ggc (20, uid_ssaname_map_hash,
uid_ssaname_map_eq, NULL);
! fn->gimple_df->call_clobbered_vars = BITMAP_GGC_ALLOC ();
! fn->gimple_df->call_used_vars = BITMAP_GGC_ALLOC ();
init_ssanames (fn, 0);
init_phinodes ();
}
--- 733,740 ----
uid_decl_map_eq, NULL);
fn->gimple_df->default_defs = htab_create_ggc (20, uid_ssaname_map_hash,
uid_ssaname_map_eq, NULL);
! pt_solution_reset (&fn->gimple_df->escaped);
! pt_solution_reset (&fn->gimple_df->callused);
init_ssanames (fn, 0);
init_phinodes ();
}
*************** delete_tree_ssa (void)
*** 860,867 ****
htab_delete (cfun->gimple_df->default_defs);
cfun->gimple_df->default_defs = NULL;
! cfun->gimple_df->call_clobbered_vars = NULL;
! cfun->gimple_df->call_used_vars = NULL;
cfun->gimple_df->modified_noreturn_calls = NULL;
cfun->gimple_df = NULL;
--- 816,823 ----
htab_delete (cfun->gimple_df->default_defs);
cfun->gimple_df->default_defs = NULL;
! pt_solution_reset (&cfun->gimple_df->escaped);
! pt_solution_reset (&cfun->gimple_df->callused);
cfun->gimple_df->modified_noreturn_calls = NULL;
cfun->gimple_df = NULL;
*************** execute_update_addresses_taken (bool do_
*** 1535,1541 ****
if (TREE_ADDRESSABLE (var))
{
- clear_call_clobbered (var);
TREE_ADDRESSABLE (var) = 0;
if (is_gimple_reg (var))
mark_sym_for_renaming (var);
--- 1491,1496 ----
Index: alias-improvements/gcc/testsuite/gcc.dg/torture/ssa-pta-fn-1.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- alias-improvements/gcc/testsuite/gcc.dg/torture/ssa-pta-fn-1.c 2009-01-10 20:28:31.000000000 +0100
***************
*** 0 ****
--- 1,60 ----
+ /* { dg-do run } */
+ /* { dg-options "-O -fdump-tree-alias" } */
+
+ extern void abort (void);
+ int *glob;
+
+ int * __attribute__((noinline,const))
+ foo_const(int *p) { return p; }
+
+ int * __attribute__((noinline,pure))
+ foo_pure(int *p) { return glob; }
+
+ int * __attribute__((noinline))
+ foo_normal(int *p) { glob = p; return p; }
+
+ void test_const(void)
+ {
+ int i;
+ int *p = &i;
+ int *q_const = foo_const(p);
+ *p = 1;
+ *q_const = 2;
+ if (*p != 2)
+ abort ();
+ }
+
+ void test(void)
+ {
+ int i;
+ int *p = &i;
+ int *q_normal = foo_normal(p);
+ *p = 1;
+ *q_normal = 2;
+ if (*p != 2)
+ abort ();
+ }
+
+ void test_pure(void)
+ {
+ int i;
+ int *p = &i;
+ int *q_pure = foo_pure(p);
+ *p = 1;
+ *q_pure = 2;
+ if (*p != 2)
+ abort ();
+ }
+
+ int main()
+ {
+ test_const();
+ test();
+ test_pure();
+ return 0;
+ }
+
+ /* { dg-final { scan-tree-dump "q_const_., is dereferenced, points-to non-local, points-to vars: { i }" "alias" } } */
+ /* { dg-final { scan-tree-dump "q_pure_., is dereferenced, points-to non-local, points-to escaped, points-to call-used, points-to vars: { }" "alias" } } */
+ /* { dg-final { scan-tree-dump "q_normal_., is dereferenced, points-to non-local, points-to escaped, points-to vars: { }" "alias" } } */
+ /* { dg-final { cleanup-tree-dump "alias" } } */