This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH][alias-improvements] "Clean up" call-clobbering


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" } } */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]