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]

[PATCH][alias-improvements] Documentation for tree-ssa-alias.c, cleanups


This moves code and prototypes to where they belong (mainly away from
tree-ssa-alias.c).  It removes obsolete documentation and tries to fill
the hole.  It also removes code that was scheduled for removal and cleans
up some stuff.

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to the
branch.

Richard.

2009-01-02  Richard Guenther  <rguenther@suse.de>

	* tree-ssa-alias.c (struct count_ptr_d, count_ptr_derefs,
	count_uses_and_derefs): Move ...
	* gimple.c: ... here.
	* gimple.h (count_uses_and_derefs): Declare.
	* passes.c (init_optimization_passes): Remove reset_cc_flags pass.
	* tree-pass.h (pass_reset_cc_flags): Remove.
	* tree-flow-inline.h (may_be_aliased): New function, moved from ...
	* tree-ssa-alias.c (may_be_aliased): ... here.
	* tree-flow.h (enum escape_type): Move ...
	* tree-ssa-alias.h: ... here.
	* tree-flow.h (struct ptr_info_def): Remove escape_mask and
	value_escapes_p members.
	* tree-flow.h: Move declarations around to correct places.
	* tree-ssa-alias.c: Rewrite overall documentation.
	(struct alias_stats_d, alias_stats, dump_alias_stats,
	reset_alias_info, reset_cc_flags, pass_reset_cc_flags): Remove.
	(compute_call_clobbered, compute_may_aliases, may_alias_p,
	pass_build_alias): Move ...
	* tree-ssa-structalias.c: ... here.
	(may_alias_p): Simplify, make static.
	(clobber_what_escaped, compute_call_used_vars, compute_points_to_sets,
	init_alias_heapvars): Make static.
	(compute_points_to_sets): Reset is_dereferenced flags.
	* tree-ssa-structalias.h (is_escape_site): Move to tree-ssa-alias.h.
	(compute_points_to_sets, delete_points_to_sets): Remove.

Index: alias-improvements/gcc/gimple.c
===================================================================
*** alias-improvements.orig/gcc/gimple.c	2009-01-02 14:58:15.000000000 +0100
--- alias-improvements/gcc/gimple.c	2009-01-02 14:59:38.000000000 +0100
*************** gimple_call_copy_skip_args (gimple stmt,
*** 3188,3191 ****
--- 3188,3282 ----
    return new_stmt;
  }
  
+ 
+ /* Data structure used to count the number of dereferences to PTR
+    inside an expression.  */
+ struct count_ptr_d
+ {
+   tree ptr;
+   unsigned num_stores;
+   unsigned num_loads;
+ };
+ 
+ /* Helper for count_uses_and_derefs.  Called by walk_tree to look for
+    (ALIGN/MISALIGNED_)INDIRECT_REF nodes for the pointer passed in DATA.  */
+ 
+ static tree
+ count_ptr_derefs (tree *tp, int *walk_subtrees, void *data)
+ {
+   struct walk_stmt_info *wi_p = (struct walk_stmt_info *) data;
+   struct count_ptr_d *count_p = (struct count_ptr_d *) wi_p->info;
+ 
+   /* Do not walk inside ADDR_EXPR nodes.  In the expression &ptr->fld,
+      pointer 'ptr' is *not* dereferenced, it is simply used to compute
+      the address of 'fld' as 'ptr + offsetof(fld)'.  */
+   if (TREE_CODE (*tp) == ADDR_EXPR)
+     {
+       *walk_subtrees = 0;
+       return NULL_TREE;
+     }
+ 
+   if (INDIRECT_REF_P (*tp) && TREE_OPERAND (*tp, 0) == count_p->ptr)
+     {
+       if (wi_p->is_lhs)
+ 	count_p->num_stores++;
+       else
+ 	count_p->num_loads++;
+     }
+ 
+   return NULL_TREE;
+ }
+ 
+ /* Count the number of direct and indirect uses for pointer PTR in
+    statement STMT.  The number of direct uses is stored in
+    *NUM_USES_P.  Indirect references are counted separately depending
+    on whether they are store or load operations.  The counts are
+    stored in *NUM_STORES_P and *NUM_LOADS_P.  */
+ 
+ void
+ count_uses_and_derefs (tree ptr, gimple stmt, unsigned *num_uses_p,
+ 		       unsigned *num_loads_p, unsigned *num_stores_p)
+ {
+   ssa_op_iter i;
+   tree use;
+ 
+   *num_uses_p = 0;
+   *num_loads_p = 0;
+   *num_stores_p = 0;
+ 
+   /* Find out the total number of uses of PTR in STMT.  */
+   FOR_EACH_SSA_TREE_OPERAND (use, stmt, i, SSA_OP_USE)
+     if (use == ptr)
+       (*num_uses_p)++;
+ 
+   /* Now count the number of indirect references to PTR.  This is
+      truly awful, but we don't have much choice.  There are no parent
+      pointers inside INDIRECT_REFs, so an expression like
+      '*x_1 = foo (x_1, *x_1)' needs to be traversed piece by piece to
+      find all the indirect and direct uses of x_1 inside.  The only
+      shortcut we can take is the fact that GIMPLE only allows
+      INDIRECT_REFs inside the expressions below.  */
+   if (is_gimple_assign (stmt)
+       || gimple_code (stmt) == GIMPLE_RETURN
+       || gimple_code (stmt) == GIMPLE_ASM
+       || is_gimple_call (stmt))
+     {
+       struct walk_stmt_info wi;
+       struct count_ptr_d count;
+ 
+       count.ptr = ptr;
+       count.num_stores = 0;
+       count.num_loads = 0;
+ 
+       memset (&wi, 0, sizeof (wi));
+       wi.info = &count;
+       walk_gimple_op (stmt, count_ptr_derefs, &wi);
+ 
+       *num_stores_p = count.num_stores;
+       *num_loads_p = count.num_loads;
+     }
+ 
+   gcc_assert (*num_uses_p >= *num_loads_p + *num_stores_p);
+ }
+ 
  #include "gt-gimple.h"
Index: alias-improvements/gcc/gimple.h
===================================================================
*** alias-improvements.orig/gcc/gimple.h	2009-01-02 15:00:12.000000000 +0100
--- alias-improvements/gcc/gimple.h	2009-01-02 15:01:27.000000000 +0100
*************** extern bool is_gimple_call_addr (tree);
*** 910,915 ****
--- 910,917 ----
  extern tree get_call_expr_in (tree t);
  
  extern void recalculate_side_effects (tree);
+ extern void count_uses_and_derefs (tree, gimple, unsigned *, unsigned *,
+ 				   unsigned *);
  
  /* In gimplify.c  */
  extern tree create_tmp_var_raw (tree, const char *);
Index: alias-improvements/gcc/passes.c
===================================================================
*** alias-improvements.orig/gcc/passes.c	2009-01-02 16:29:20.000000000 +0100
--- alias-improvements/gcc/passes.c	2009-01-02 16:29:25.000000000 +0100
*************** init_optimization_passes (void)
*** 542,548 ****
        NEXT_PASS (pass_expand_omp);
  
        NEXT_PASS (pass_referenced_vars);
-       NEXT_PASS (pass_reset_cc_flags);
        NEXT_PASS (pass_build_ssa);
        NEXT_PASS (pass_early_warn_uninitialized);
        NEXT_PASS (pass_all_early_optimizations);
--- 542,547 ----
Index: alias-improvements/gcc/tree-flow-inline.h
===================================================================
*** alias-improvements.orig/gcc/tree-flow-inline.h	2009-01-02 15:16:04.000000000 +0100
--- alias-improvements/gcc/tree-flow-inline.h	2009-01-02 15:16:45.000000000 +0100
*************** is_global_var (const_tree t)
*** 584,589 ****
--- 584,599 ----
    return (TREE_STATIC (t) || DECL_EXTERNAL (t));
  }
  
+ 
+ /* Return true if VAR may be aliased.  */
+ 
+ static inline bool
+ may_be_aliased (tree var)
+ {
+   return TREE_ADDRESSABLE (var) || is_global_var (var);
+ }
+ 
+ 
  /* PHI nodes should contain only ssa_names and invariants.  A test
     for ssa_name is definitely simpler; don't let invalid contents
     slip in in the meantime.  */
Index: alias-improvements/gcc/tree-flow.h
===================================================================
*** alias-improvements.orig/gcc/tree-flow.h	2009-01-02 15:00:12.000000000 +0100
--- alias-improvements/gcc/tree-flow.h	2009-01-02 16:34:12.000000000 +0100
*************** typedef struct basic_block_def *basic_bl
*** 41,64 ****
  #endif
  struct static_var_ann_d;
  
- /* The reasons a variable may escape a function.  */
- enum escape_type 
- {
-   NO_ESCAPE = 0,			/* Doesn't escape.  */
-   ESCAPE_STORED_IN_GLOBAL = 1 << 0,
-   ESCAPE_TO_ASM = 1 << 1,		/* Passed by address to an assembly
- 					   statement.  */
-   ESCAPE_TO_CALL = 1 << 2,		/* Escapes to a function call.  */
-   ESCAPE_BAD_CAST = 1 << 3,		/* Cast from pointer to integer */
-   ESCAPE_TO_RETURN = 1 << 4,		/* Returned from function.  */
-   ESCAPE_TO_PURE_CONST = 1 << 5,	/* Escapes to a pure or constant
- 					   function call.  */
-   ESCAPE_IS_GLOBAL = 1 << 6,		/* Is a global variable.  */
-   ESCAPE_IS_PARM = 1 << 7,		/* Is an incoming function argument.  */
-   ESCAPE_UNKNOWN = 1 << 8		/* We believe it escapes for
- 					   some reason not enumerated
- 					   above.  */
- };
  
  /* Gimple dataflow datastructure. All publicly available fields shall have
     gimple_ accessor defined in tree-flow-inline.h, all publicly modifiable
--- 41,46 ----
*************** typedef struct
*** 153,164 ****
  /* Aliasing information for SSA_NAMEs representing pointer variables.  */
  struct ptr_info_def GTY(())
  {
-   /* Mask of reasons this pointer's value escapes the function.  */
-   ENUM_BITFIELD (escape_type) escape_mask : 9;
- 
-   /* Nonzero if the value of this pointer escapes the current function.  */
-   unsigned int value_escapes_p : 1;
- 
    /* Nonzero if this pointer is really dereferenced.  */
    unsigned int is_dereferenced : 1;
  
--- 135,140 ----
*************** extern tree make_rename_temp (tree, cons
*** 686,691 ****
--- 662,669 ----
  extern void set_default_def (tree, tree);
  extern tree gimple_default_def (struct function *, tree);
  extern bool stmt_references_abnormal_ssa_name (gimple);
+ extern tree get_ref_base_and_extent (tree, HOST_WIDE_INT *,
+ 				     HOST_WIDE_INT *, HOST_WIDE_INT *);
  
  /* In tree-phinodes.c  */
  extern void reserve_phi_args_for_new_edge (basic_block);
*************** extern bool block_may_fallthru (const_tr
*** 709,739 ****
  extern bool gimple_seq_may_fallthru (gimple_seq);
  extern bool gimple_stmt_may_fallthru (gimple);
  
- /* In tree-ssa-alias.c  */
- extern unsigned int compute_may_aliases (void);
- extern void dump_may_aliases_for (FILE *, tree);
- extern void debug_may_aliases_for (tree);
- extern void dump_alias_info (FILE *);
- extern void debug_alias_info (void);
- extern void dump_points_to_info_for (FILE *, tree);
- extern void debug_points_to_info_for (tree);
- extern bool may_alias_p (tree, alias_set_type, tree, alias_set_type, bool);
- extern struct ptr_info_def *get_ptr_info (tree);
- extern bool may_point_to_global_var (tree);
- extern void count_uses_and_derefs (tree, gimple, unsigned *, unsigned *,
- 				   unsigned *);
- static inline bool ref_contains_array_ref (const_tree);
- static inline bool array_ref_contains_indirect_ref (const_tree);
- extern tree get_ref_base_and_extent (tree, HOST_WIDE_INT *,
- 				     HOST_WIDE_INT *, HOST_WIDE_INT *);
- 
- /* Call-back function for walk_use_def_chains().  At each reaching
-    definition, a function with this prototype is called.  */
- typedef bool (*walk_use_def_chains_fn) (tree, gimple, void *);
- 
- /* In tree-ssa-alias-warnings.c  */
- extern void strict_aliasing_warning_backend (void);
- 
  
  /* In tree-ssa.c  */
  
--- 687,692 ----
*************** extern edge ssa_redirect_edge (edge, bas
*** 762,771 ****
  extern void flush_pending_stmts (edge);
  extern void verify_ssa (bool);
  extern void delete_tree_ssa (void);
- extern void walk_use_def_chains (tree, walk_use_def_chains_fn, void *, bool);
  extern bool ssa_undefined_value_p (tree);
  unsigned int execute_update_addresses_taken (void);
  
  
  /* In tree-into-ssa.c  */
  void update_ssa (unsigned);
--- 715,729 ----
  extern void flush_pending_stmts (edge);
  extern void verify_ssa (bool);
  extern void delete_tree_ssa (void);
  extern bool ssa_undefined_value_p (tree);
  unsigned int execute_update_addresses_taken (void);
  
+ /* Call-back function for walk_use_def_chains().  At each reaching
+    definition, a function with this prototype is called.  */
+ typedef bool (*walk_use_def_chains_fn) (tree, gimple, void *);
+ 
+ extern void walk_use_def_chains (tree, walk_use_def_chains_fn, void *, bool);
+ 
  
  /* In tree-into-ssa.c  */
  void update_ssa (unsigned);
*************** static inline bool is_call_clobbered (co
*** 960,965 ****
--- 918,925 ----
  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);
+ static inline bool array_ref_contains_indirect_ref (const_tree);
  
  /* In tree-eh.c  */
  extern void make_eh_edges (gimple);
*************** tree force_gimple_operand_gsi (gimple_st
*** 1037,1046 ****
  			       bool, enum gsi_iterator_update);
  tree gimple_fold_indirect_ref (tree);
  
- /* In tree-ssa-structalias.c */
- bool clobber_what_escaped (void);
- void compute_call_used_vars (void);
- 
  /* In tree-ssa-live.c */
  extern void remove_unused_locals (void);
  
--- 997,1002 ----
*************** rtx addr_for_mem_ref (struct mem_address
*** 1060,1067 ****
  void get_address_description (tree, struct mem_address *);
  tree maybe_fold_tmr (tree);
  
- void init_alias_heapvars (void);
- void delete_alias_heapvars (void);
  unsigned int execute_fixup_cfg (void);
  
  #include "tree-flow-inline.h"
--- 1016,1021 ----
Index: alias-improvements/gcc/tree-pass.h
===================================================================
*** alias-improvements.orig/gcc/tree-pass.h	2009-01-02 16:29:08.000000000 +0100
--- alias-improvements/gcc/tree-pass.h	2009-01-02 16:29:15.000000000 +0100
*************** extern struct gimple_opt_pass pass_retur
*** 387,393 ****
  extern struct gimple_opt_pass pass_reassoc;
  extern struct gimple_opt_pass pass_rebuild_cgraph_edges;
  extern struct gimple_opt_pass pass_build_cgraph_edges;
- extern struct gimple_opt_pass pass_reset_cc_flags;
  
  /* IPA Passes */
  extern struct ipa_opt_pass pass_ipa_inline;
--- 387,392 ----
Index: alias-improvements/gcc/tree-ssa-alias.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-alias.c	2009-01-02 14:38:16.000000000 +0100
--- alias-improvements/gcc/tree-ssa-alias.c	2009-01-02 16:32:39.000000000 +0100
*************** along with GCC; see the file COPYING3.  
*** 50,672 ****
  #include "alloc-pool.h"
  #include "tree-ssa-alias.h"
  
! /* Broad overview of how aliasing works:
!    
!    First we compute points-to sets, which is done in
!    tree-ssa-structalias.c
!       
!    During points-to set constraint finding, a bunch of little bits of
!    information is collected.
!    This is not done because it is necessary for points-to, but because
!    points-to has to walk every statement anyway.  The function performing
!    this collecting is update_alias_info.
! 
!    Bits update_alias_info collects include:
!    1. Directly escaping variables and variables whose value escapes
!    (using is_escape_site).  This is the set of variables and values that
!    escape prior to transitive closure of the clobbers.
!    2.  The set of variables dereferenced on the LHS (into
!    dereferenced_ptr_stores) 
!    3. The set of variables dereferenced on the RHS (into
!    dereferenced_ptr_loads) 
!    4. The set of all pointers we saw.
!    5. The number of loads and stores for each variable
!    6. The number of statements touching memory
!    7. The set of address taken variables.
!    
!    
!    #1 is computed by a combination of is_escape_site, and counting the
!    number of uses/deref operators.  This function properly accounts for
!    situations like &ptr->field, which is *not* a dereference.
!    
!    After points-to sets are computed, the sets themselves still
!    contain points-to specific variables, such as a variable that says
!    the pointer points to anything, a variable that says the pointer
!    points to readonly memory, etc.
! 
!    These are eliminated in a later phase, as we will see.
! 
!    The rest of the phases are located in tree-ssa-alias.c
! 
!    The next phase after points-to set computation is called
!    "setup_pointers_and_addressables"
! 
!    This pass does 3 main things:
!    
!    1. All variables that can have TREE_ADDRESSABLE removed safely (IE
!    non-globals whose address is not taken), have TREE_ADDRESSABLE
!    removed.
!    2. All variables that may be aliased (which is the set of addressable
!    variables and globals) at all, are marked for renaming, and have
!    symbol memory tags created for them.
!    3. All variables which are stored into have their SMT's added to
!    written vars. 
! 
! 
!    After this function is run, all variables that will ever have an
!    SMT, have one, though its aliases are not filled in.
! 
!    The next phase is to compute flow-insensitive aliasing, which in
!    our case, is a misnomer.  it is really computing aliasing that
!    requires no transitive closure to be correct.  In particular, it
!    uses stack vs non-stack, TBAA, etc, to determine whether two
!    symbols could *ever* alias .  This phase works by going through all
!    the pointers we collected during update_alias_info, and for every
!    addressable variable in the program, seeing if they alias.  If so,
!    the addressable variable is added to the symbol memory tag for the
!    pointer.
! 
!    As part of this, we handle symbol memory tags that conflict but
!    have no aliases in common, by forcing them to have a symbol in
!    common (through unioning alias sets or adding one as an alias of
!    the other), or by adding one as an alias of another.  The case of
!    conflicts with no aliases in common occurs mainly due to aliasing
!    we cannot see.  In particular, it generally means we have a load
!    through a pointer whose value came from outside the function.
!    Without an addressable symbol to point to, they would get the wrong
!    answer.
! 
!    After flow insensitive aliasing is computed, we compute name tags
!    (called compute_flow_sensitive_info).  We walk each pointer we
!    collected and see if it has a usable points-to set.  If so, we
!    generate a name tag using that pointer, and make an alias bitmap for
!    it.  Name tags are shared between all things with the same alias
!    bitmap.  The alias bitmap will be translated from what points-to
!    computed.  In particular, the "anything" variable in points-to will be
!    transformed into a pruned set of SMT's and their aliases that
!    compute_flow_insensitive_aliasing computed.
!    Note that since 4.3, every pointer that points-to computed a solution for
!    will get a name tag (whereas before 4.3, only those whose set did
!    *not* include the anything variable would).  At the point where name
!    tags are all assigned, symbol memory tags are dead, and could be
!    deleted, *except* on global variables.  Global variables still use
!    symbol memory tags as of right now.
! 
!    After name tags are computed, the set of clobbered variables is
!    transitively closed.  In particular, we compute the set of clobbered
!    variables based on the initial set of clobbers, plus the aliases of
!    pointers which either escape, or have their value escape.
! 
!    After this, maybe_create_global_var is run, which handles a corner
!    case where we have no call clobbered variables, but have pure and
!    non-pure functions.
!    
!    Staring at this function, I now remember it is a hack for the fact
!    that we do not mark all globals in the program as call clobbered for a
!    function unless they are actually used in that function.  Instead,  we
!    only mark the set that is actually clobbered.  As a result, you can
!    end up with situations where you have no call clobbered vars set.
!    
!    After maybe_create_global_var, we set pointers with the REF_ALL flag
!    to have alias sets that include all clobbered
!    memory tags and variables.
!    
!    After this, memory partitioning is computed (by the function
!    compute_memory_partitions) and alias sets are reworked accordingly.
! 
!    Lastly, we delete partitions with no symbols, and clean up after
!    ourselves.  */
! 
! 
! /* Counters used to display statistics on alias analysis.  */
! struct alias_stats_d
! {
!   unsigned int alias_queries;
!   unsigned int alias_mayalias;
!   unsigned int alias_noalias;
!   unsigned int simple_queries;
!   unsigned int simple_resolved;
!   unsigned int tbaa_queries;
!   unsigned int tbaa_resolved;
!   unsigned int structnoaddress_queries;
!   unsigned int structnoaddress_resolved;
! };
! 
! 
! /* Local variables.  */
! static struct alias_stats_d alias_stats;
! 
! /* Local functions.  */
! static void dump_alias_stats (FILE *);
! static void reset_alias_info (void);
! 
! 
! /* Transfer the call-clobber solutions from the points-to solution
!    to the call-clobber state of the variables.  */
! 
! 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);
! 
!   FOR_EACH_REFERENCED_VAR (var, rvi)
!     {
!       if (is_global_var (var))
! 	{
! 	  if (!unmodifiable_var_p (var))
! 	    mark_call_clobbered (var, ESCAPE_IS_GLOBAL);
! 	}
!       else if (TREE_CODE (var) == PARM_DECL
! 	       && gimple_default_def (cfun, var)
! 	       && POINTER_TYPE_P (TREE_TYPE (var)))
! 	{
! 	  tree def = gimple_default_def (cfun, var);
! 	  get_ptr_info (def)->value_escapes_p = 1;
! 	  get_ptr_info (def)->escape_mask |= ESCAPE_IS_PARM;	  
! 	}
!     }
! 
!   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)
!     {
!       bitmap_iterator bi;
!       unsigned int j;
! 
!       EXECUTE_IF_SET_IN_BITMAP (gimple_addressable_vars (cfun), 0, j, bi)
! 	{
! 	  tree var = referenced_var (j);
! 	  if (!unmodifiable_var_p (var))
! 	    mark_call_clobbered (var, pt_anything_mask);
! 	}
!     }
! 
!   timevar_pop (TV_CALL_CLOBBER);
! }
! 
! 
! /* Compute may-alias information for every variable referenced in function
!    FNDECL.
! 
!    Alias analysis proceeds in 3 main phases:
! 
!    1- Points-to and escape analysis.
! 
!    This phase walks the use-def chains in the SSA web looking for three
!    things:
! 
! 	* Assignments of the form P_i = &VAR
! 	* Assignments of the form P_i = malloc()
! 	* Pointers and ADDR_EXPR that escape the current function.
! 
!    The concept of 'escaping' is the same one used in the Java world.  When
!    a pointer or an ADDR_EXPR escapes, it means that it has been exposed
!    outside of the current function.  So, assignment to global variables,
!    function arguments and returning a pointer are all escape sites, as are
!    conversions between pointers and integers.
! 
!    This is where we are currently limited.  Since not everything is renamed
!    into SSA, we lose track of escape properties when a pointer is stashed
!    inside a field in a structure, for instance.  In those cases, we are
!    assuming that the pointer does escape.
! 
!    We use escape analysis to determine whether a variable is
!    call-clobbered.  Simply put, if an ADDR_EXPR escapes, then the variable
!    is call-clobbered.  If a pointer P_i escapes, then all the variables
!    pointed-to by P_i (and its memory tag) also escape.
! 
!    2- Compute flow-sensitive aliases
! 
!    We have two classes of memory tags.  Memory tags associated with the
!    pointed-to data type of the pointers in the program.  These tags are
!    called "symbol memory tag" (SMT).  The other class are those associated
!    with SSA_NAMEs, called "name memory tag" (NMT). The basic idea is that
!    when adding operands for an INDIRECT_REF *P_i, we will first check
!    whether P_i has a name tag, if it does we use it, because that will have
!    more precise aliasing information.  Otherwise, we use the standard symbol
!    tag.
! 
!    In this phase, we go through all the pointers we found in points-to
!    analysis and create alias sets for the name memory tags associated with
!    each pointer P_i.  If P_i escapes, we mark call-clobbered the variables
!    it points to and its tag.
! 
! 
!    3- Compute flow-insensitive aliases
! 
!    This pass will compare the alias set of every symbol memory tag and
!    every addressable variable found in the program.  Given a symbol
!    memory tag SMT and an addressable variable V.  If the alias sets of
!    SMT and V conflict (as computed by may_alias_p), then V is marked
!    as an alias tag and added to the alias set of SMT.
! 
!    For instance, consider the following function:
! 
! 	    foo (int i)
! 	    {
! 	      int *p, a, b;
! 	    
! 	      if (i > 10)
! 	        p = &a;
! 	      else
! 	        p = &b;
! 	    
! 	      *p = 3;
! 	      a = b + 2;
! 	      return *p;
! 	    }
! 
!    After aliasing analysis has finished, the symbol memory tag for pointer
!    'p' will have two aliases, namely variables 'a' and 'b'.  Every time
!    pointer 'p' is dereferenced, we want to mark the operation as a
!    potential reference to 'a' and 'b'.
! 
! 	    foo (int i)
! 	    {
! 	      int *p, a, b;
! 
! 	      if (i_2 > 10)
! 		p_4 = &a;
! 	      else
! 		p_6 = &b;
! 	      # p_1 = PHI <p_4(1), p_6(2)>;
! 
! 	      # a_7 = VDEF <a_3>;
! 	      # b_8 = VDEF <b_5>;
! 	      *p_1 = 3;
! 
! 	      # a_9 = VDEF <a_7>
! 	      # VUSE <b_8>
! 	      a_9 = b_8 + 2;
! 
! 	      # VUSE <a_9>;
! 	      # VUSE <b_8>;
! 	      return *p_1;
! 	    }
! 
!    In certain cases, the list of may aliases for a pointer may grow too
!    large.  This may cause an explosion in the number of virtual operands
!    inserted in the code.  Resulting in increased memory consumption and
!    compilation time.
! 
!    When the number of virtual operands needed to represent aliased
!    loads and stores grows too large (configurable with option --param
!    max-aliased-vops and --param avg-aliased-vops), alias sets are
!    grouped to avoid severe compile-time slow downs and memory
!    consumption. See compute_memory_partitions.  */
! 
! unsigned int
! compute_may_aliases (void)
! {
!   timevar_push (TV_TREE_MAY_ALIAS);
!   
!   memset (&alias_stats, 0, sizeof (alias_stats));
! 
!   /* Reset aliasing information.  */
!   reset_alias_info ();
! 
!   /* For each pointer P_i, determine the sets of variables that P_i may
!      point-to.  For every addressable variable V, determine whether the
!      address of V escapes the current function, making V call-clobbered
!      (i.e., whether &V is stored in a global variable or if its passed as a
!      function call argument).  */
!   compute_points_to_sets ();
!   
!   /* Compute call clobbering information.  */
!   compute_call_clobbered ();
! 
!   /* Debugging dumps.  */
!   if (dump_file)
!     {
!       dump_alias_info (dump_file);
! 
!       if (dump_flags & TDF_STATS)
! 	dump_alias_stats (dump_file);
! 
!       if (dump_flags & TDF_DETAILS)
! 	dump_referenced_vars (dump_file);
!     }
! 
!   /* Deallocate memory used by aliasing data structures.  */
!   delete_points_to_sets ();
! 
!   gcc_assert (!need_ssa_update_p ());
! 
!   timevar_pop (TV_TREE_MAY_ALIAS);
!   
!   return 0;
! }
! 
! /* Data structure used to count the number of dereferences to PTR
!    inside an expression.  */
! struct count_ptr_d
! {
!   tree ptr;
!   unsigned num_stores;
!   unsigned num_loads;
! };
! 
! 
! /* Helper for count_uses_and_derefs.  Called by walk_tree to look for
!    (ALIGN/MISALIGNED_)INDIRECT_REF nodes for the pointer passed in DATA.  */
! 
! static tree
! count_ptr_derefs (tree *tp, int *walk_subtrees, void *data)
! {
!   struct walk_stmt_info *wi_p = (struct walk_stmt_info *) data;
!   struct count_ptr_d *count_p = (struct count_ptr_d *) wi_p->info;
! 
!   /* Do not walk inside ADDR_EXPR nodes.  In the expression &ptr->fld,
!      pointer 'ptr' is *not* dereferenced, it is simply used to compute
!      the address of 'fld' as 'ptr + offsetof(fld)'.  */
!   if (TREE_CODE (*tp) == ADDR_EXPR)
!     {
!       *walk_subtrees = 0;
!       return NULL_TREE;
!     }
! 
!   if (INDIRECT_REF_P (*tp) && TREE_OPERAND (*tp, 0) == count_p->ptr)
!     {
!       if (wi_p->is_lhs)
! 	count_p->num_stores++;
!       else
! 	count_p->num_loads++;
!     }
! 
!   return NULL_TREE;
! }
  
  
! /* Count the number of direct and indirect uses for pointer PTR in
!    statement STMT.  The number of direct uses is stored in
!    *NUM_USES_P.  Indirect references are counted separately depending
!    on whether they are store or load operations.  The counts are
!    stored in *NUM_STORES_P and *NUM_LOADS_P.  */
! 
! void
! count_uses_and_derefs (tree ptr, gimple stmt, unsigned *num_uses_p,
! 		       unsigned *num_loads_p, unsigned *num_stores_p)
! {
!   ssa_op_iter i;
!   tree use;
! 
!   *num_uses_p = 0;
!   *num_loads_p = 0;
!   *num_stores_p = 0;
! 
!   /* Find out the total number of uses of PTR in STMT.  */
!   FOR_EACH_SSA_TREE_OPERAND (use, stmt, i, SSA_OP_USE)
!     if (use == ptr)
!       (*num_uses_p)++;
! 
!   /* Now count the number of indirect references to PTR.  This is
!      truly awful, but we don't have much choice.  There are no parent
!      pointers inside INDIRECT_REFs, so an expression like
!      '*x_1 = foo (x_1, *x_1)' needs to be traversed piece by piece to
!      find all the indirect and direct uses of x_1 inside.  The only
!      shortcut we can take is the fact that GIMPLE only allows
!      INDIRECT_REFs inside the expressions below.  */
!   if (is_gimple_assign (stmt)
!       || gimple_code (stmt) == GIMPLE_RETURN
!       || gimple_code (stmt) == GIMPLE_ASM
!       || is_gimple_call (stmt))
!     {
!       struct walk_stmt_info wi;
!       struct count_ptr_d count;
  
-       count.ptr = ptr;
-       count.num_stores = 0;
-       count.num_loads = 0;
- 
-       memset (&wi, 0, sizeof (wi));
-       wi.info = &count;
-       walk_gimple_op (stmt, count_ptr_derefs, &wi);
- 
-       *num_stores_p = count.num_stores;
-       *num_loads_p = count.num_loads;
-     }
- 
-   gcc_assert (*num_uses_p >= *num_loads_p + *num_stores_p);
- }
- 
- /* Helper for init_alias_info.  Reset existing aliasing information.  */
- 
- static void
- reset_alias_info (void)
- {
-   referenced_var_iterator rvi;
-   tree var;
-   unsigned i;
- 
-   /* Since we are about to re-discover call-clobbered
-      variables, clear all the call-clobbered flags.  */
-   FOR_EACH_REFERENCED_VAR (var, rvi)
-     {
-       if (is_gimple_reg (var)
- 	  || is_global_var (var))
- 	continue;
- 
-       clear_call_clobbered (var);
-     }
- 
-   /* There should be no call-clobbered variable left.  */
-   gcc_assert (bitmap_empty_p (gimple_call_clobbered_vars (cfun)));
- 
-   /* Clear the call-used variables.  */
-   bitmap_clear (gimple_call_used_vars (cfun));
- 
-   /* Clear points-to information from each SSA name.  */
-   for (i = 1; i < num_ssa_names; i++)
-     {
-       tree name = ssa_name (i);
- 
-       if (!name || !POINTER_TYPE_P (TREE_TYPE (name)))
- 	continue;
- 
-       if (SSA_NAME_PTR_INFO (name))
- 	{
- 	  struct ptr_info_def *pi = SSA_NAME_PTR_INFO (name);
- 
- 	  /* Clear all the flags and reset the points-to solution.  */
- 	  pi->value_escapes_p = 0;
- 	  pi->is_dereferenced = 0;
- 	  pi->pt.anything = 1;
- 	  pi->pt.nonlocal = 0;
- 	  pi->pt.escaped = 0;
- 	  pi->pt.null = 0;
- 	  pi->pt.vars_contains_global = 0;
- 	  if (pi->pt.vars)
- 	    {
- 	      bitmap_clear (pi->pt.vars);
- 	      pi->pt.vars = NULL;
- 	    }
- 	}
-     }
- }
- 
- 
- /* Return TRUE if pointer PTR may point to variable VAR.
-    
-    MEM_ALIAS_SET is the alias set for the memory location pointed-to by PTR
- 	This is needed because when checking for type conflicts we are
- 	interested in the alias set of the memory location pointed-to by
- 	PTR.  The alias set of PTR itself is irrelevant.
-    
-    VAR_ALIAS_SET is the alias set for VAR.  */
- 
- bool
- may_alias_p (tree ptr, alias_set_type mem_alias_set,
- 	     tree var, alias_set_type var_alias_set,
- 	     bool alias_set_only)
- {
-   alias_stats.alias_queries++;
-   alias_stats.simple_queries++;
- 
-   /* If -fargument-noalias-global is > 2, pointer arguments may
-      not point to anything else.  */
-   if (flag_argument_noalias > 2 && TREE_CODE (ptr) == PARM_DECL)
-     {
-       alias_stats.alias_noalias++;
-       alias_stats.simple_resolved++;
-       return false;
-     }
- 
-   /* If -fargument-noalias-global is > 1, pointer arguments may
-      not point to global variables.  */
-   if (flag_argument_noalias > 1 && is_global_var (var)
-       && TREE_CODE (ptr) == PARM_DECL)
-     {
-       alias_stats.alias_noalias++;
-       alias_stats.simple_resolved++;
-       return false;
-     }
- 
-   /* If the pointed to memory has alias set zero, or the pointer
-      is ref-all, or the pointer decl is marked that no TBAA is to
-      be applied, the MEM can alias VAR.  */
-   if (mem_alias_set == 0
-       || DECL_POINTER_ALIAS_SET (ptr) == 0
-       || TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (ptr))
-       || DECL_NO_TBAA_P (ptr))
-     {
-       alias_stats.alias_mayalias++;
-       alias_stats.simple_resolved++;
-       return true;
-     }
- 
-   alias_stats.tbaa_queries++;
- 
-   /* If the alias sets don't conflict then MEM cannot alias VAR.  */
-   if (mem_alias_set != var_alias_set
-       && !alias_set_subset_of (mem_alias_set, var_alias_set))
-     {
-       alias_stats.alias_noalias++;
-       alias_stats.tbaa_resolved++;
-       return false;
-     }
- 
-   /* If VAR is a record or union type, PTR cannot point into VAR
-      unless there is some explicit address operation in the
-      program that can reference a field of the type pointed-to by
-      PTR.  This also assumes that the types of both VAR and PTR
-      are contained within the compilation unit, and that there is
-      no fancy addressing arithmetic associated with any of the
-      types involved.  */
-   if (mem_alias_set != 0 && var_alias_set != 0)
-     {
-       tree ptr_type = TREE_TYPE (ptr);
-       tree var_type = TREE_TYPE (var);
-       
-       /* The star count is -1 if the type at the end of the
- 	 pointer_to chain is not a record or union type. */ 
-       if (!alias_set_only && 
- 	  0 /* FIXME tuples ipa_type_escape_star_count_of_interesting_type (var_type) >= 0*/)
- 	{
- 	  int ptr_star_count = 0;
- 
- 	  /* ipa_type_escape_star_count_of_interesting_type is a
- 	     little too restrictive for the pointer type, need to
- 	     allow pointers to primitive types as long as those
- 	     types cannot be pointers to everything.  */
- 	  while (POINTER_TYPE_P (ptr_type))
- 	    {
- 	      /* Strip the *s off.  */ 
- 	      ptr_type = TREE_TYPE (ptr_type);
- 	      ptr_star_count++;
- 	    }
- 	  
- 	  /* There does not appear to be a better test to see if
- 	     the pointer type was one of the pointer to everything
- 	     types.  */
- 	  if (ptr_star_count > 0)
- 	    {
- 	      alias_stats.structnoaddress_queries++;
- 	      if (ipa_type_escape_field_does_not_clobber_p (var_type, 
- 							    TREE_TYPE (ptr)))
- 		{
- 		  alias_stats.structnoaddress_resolved++;
- 		  alias_stats.alias_noalias++;
- 		  return false;
- 		}
- 	    }
- 	  else if (ptr_star_count == 0)
- 	    {
- 	      /* If PTR_TYPE was not really a pointer to type, it cannot 
- 		 alias.  */ 
- 	      alias_stats.structnoaddress_queries++;
- 	      alias_stats.structnoaddress_resolved++;
- 	      alias_stats.alias_noalias++;
- 	      return false;
- 	    }
- 	}
-     }
- 
-   alias_stats.alias_mayalias++;
-   return true;
- }
  
  /* Return true, if PTR may point to a global variable.  */
  
--- 50,74 ----
  #include "alloc-pool.h"
  #include "tree-ssa-alias.h"
  
! /* Broad overview of how alias analysis on gimple works:
  
+    Statements clobbering or using memory are linked through the
+    virtual operand factored use-def chain.  The virtual operand
+    is unique per function, its symbol is accessible via gimple_vop (cfun).
+    Virtual operands are used for efficiently walking memory statements
+    in the gimple IL and are useful for things like value-numbering as
+    a generation count for memory references.
+ 
+    SSA_NAME pointers may have associated points-to information
+    accessible via the SSA_NAME_PTR_INFO macro.  Flow-insensitive
+    points-to information is (re-)computed by the TODO_rebuild_alias
+    pass manager todo.  Points-to information is also used for more
+    precise tracking of call-clobbered and call-used variables and
+    related disambiguations.
  
!    This file contains functions for disambiguating memory references
!    and tools for walking of the gimple IL.  */
  
  
  /* Return true, if PTR may point to a global variable.  */
  
*************** may_point_to_decl (tree ptr, tree decl)
*** 709,718 ****
  		  || TREE_CODE (decl) == PARM_DECL
  		  || TREE_CODE (decl) == RESULT_DECL));
  
!   /* Local variables that do not have their address taken
!      can not be pointed to.  */
!   if (!TREE_ADDRESSABLE (decl)
!       && !is_global_var (decl))
      return false;
  
    /* If we do not have useful points-to information for this pointer
--- 111,118 ----
  		  || TREE_CODE (decl) == PARM_DECL
  		  || TREE_CODE (decl) == RESULT_DECL));
  
!   /* Non-aliased variables can not be pointed to.  */
!   if (!may_be_aliased (decl))
      return false;
  
    /* If we do not have useful points-to information for this pointer
*************** is_escape_site (gimple stmt)
*** 811,866 ****
    return NO_ESCAPE;
  }
  
- /* Dump alias statistics on FILE.  */
- 
- static void 
- dump_alias_stats (FILE *file)
- {
-   const char *funcname
-     = lang_hooks.decl_printable_name (current_function_decl, 2);
-   fprintf (file, "\nAlias statistics for %s\n\n", funcname);
-   fprintf (file, "Total alias queries:\t%u\n", alias_stats.alias_queries);
-   fprintf (file, "Total alias mayalias results:\t%u\n", 
- 	   alias_stats.alias_mayalias);
-   fprintf (file, "Total alias noalias results:\t%u\n",
- 	   alias_stats.alias_noalias);
-   fprintf (file, "Total simple queries:\t%u\n",
- 	   alias_stats.simple_queries);
-   fprintf (file, "Total simple resolved:\t%u\n",
- 	   alias_stats.simple_resolved);
-   fprintf (file, "Total TBAA queries:\t%u\n",
- 	   alias_stats.tbaa_queries);
-   fprintf (file, "Total TBAA resolved:\t%u\n",
- 	   alias_stats.tbaa_resolved);
-   fprintf (file, "Total non-addressable structure type queries:\t%u\n",
- 	   alias_stats.structnoaddress_queries);
-   fprintf (file, "Total non-addressable structure type resolved:\t%u\n",
- 	   alias_stats.structnoaddress_resolved);
- }
- 
- 
- /* Return true if VAR may be aliased.  */
- 
- static bool
- may_be_aliased (tree var)
- {
-   /* Obviously.  */
-   if (TREE_ADDRESSABLE (var))
-     return true;
- 
-   /* ???  Why does this differ from is_global_var ()?  */
-   if (DECL_EXTERNAL (var) || TREE_PUBLIC (var))
-     return true;
- 
-   /* Automatic variables can't have their addresses escape any other
-      way.  This must be after the check for global variables, as
-      extern declarations do not have TREE_STATIC set.  */
-   if (!TREE_STATIC (var))
-     return false;
- 
-   return false;
- }
- 
  
  /* Dump alias information on FILE.  */
  
--- 211,216 ----
*************** dump_points_to_info_for (FILE *file, tre
*** 947,955 ****
        if (pi->is_dereferenced)
  	fprintf (file, ", is dereferenced");
  
-       if (pi->value_escapes_p)
- 	fprintf (file, ", its value escapes");
- 
        if (pi->pt.anything)
  	fprintf (file, ", points-to anything");
  
--- 297,302 ----
*************** debug_points_to_info_for (tree var)
*** 984,1050 ****
  }
  
  
- /* ???  Remove me.
-    For now just a quick verification run on sane initial properties.  */
- 
- static unsigned int
- reset_cc_flags (void)
- {
-   tree var;
-   referenced_var_iterator rvi;
- 
-   FOR_EACH_REFERENCED_VAR (var, rvi)
-     if (is_global_var (var)
- 	|| TREE_ADDRESSABLE (var))
-       gcc_assert (is_call_clobbered (var));
-     else
-       gcc_assert (!is_call_clobbered (var));
- 
-   return 0;
- }
- 
- struct gimple_opt_pass pass_reset_cc_flags =
- {
-  {
-   GIMPLE_PASS,
-   NULL,		 /* name */
-   NULL,  	 /* gate */
-   reset_cc_flags, /* execute */
-   NULL,			 /* sub */
-   NULL,			 /* next */
-   0,			 /* static_pass_number */
-   0,			 /* tv_id */
-   PROP_referenced_vars |PROP_cfg, /* properties_required */
-   0,			 /* properties_provided */
-   0,			 /* properties_destroyed */
-   0,			 /* todo_flags_start */
-   0         	         /* todo_flags_finish */
-  }
- };
- 
- 
- /* A dummy pass to cause aliases to be computed via TODO_rebuild_alias.  */
- 
- struct gimple_opt_pass pass_build_alias =
- {
-  {
-   GIMPLE_PASS,
-   "alias",		    /* name */
-   NULL,			    /* gate */
-   NULL,                     /* execute */
-   NULL,                     /* sub */
-   NULL,                     /* next */
-   0,                        /* static_pass_number */
-   0,                        /* tv_id */
-   PROP_cfg | PROP_ssa,      /* properties_required */
-   PROP_alias,               /* properties_provided */
-   0,                        /* properties_destroyed */
-   0,                        /* todo_flags_start */
-   TODO_rebuild_alias | TODO_dump_func  /* todo_flags_finish */
-  }
- };
- 
- 
  /* If the call CALL may use the memory reference REF return true,
     otherwise return false.  */
  
--- 331,336 ----
Index: alias-improvements/gcc/tree-ssa-alias.h
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-alias.h	2009-01-02 15:07:26.000000000 +0100
--- alias-improvements/gcc/tree-ssa-alias.h	2009-01-02 16:34:15.000000000 +0100
***************
*** 23,36 ****
  
  #include "coretypes.h"
  
  /* In tree-ssa-alias.c  */
! bool may_point_to_decl (tree, tree);
! bool ref_may_used_by_stmt_p (gimple, tree);
! bool stmt_may_clobber_ref_p (gimple, tree);
! void *walk_non_aliased_vuses (tree, tree,
! 			      void *(*)(tree, tree, void *), void *);
  
  /* In tree-dfa.c  */
  extern bool refs_may_alias_p (tree, tree);
  
  #endif /* TREE_SSA_ALIAS_H  */
--- 23,70 ----
  
  #include "coretypes.h"
  
+ 
+ /* The reasons a variable may escape a function.  */
+ enum escape_type 
+ {
+   NO_ESCAPE = 0,			/* Doesn't escape.  */
+   ESCAPE_STORED_IN_GLOBAL = 1 << 0,
+   ESCAPE_TO_ASM = 1 << 1,		/* Passed by address to an assembly
+ 					   statement.  */
+   ESCAPE_TO_CALL = 1 << 2,		/* Escapes to a function call.  */
+   ESCAPE_BAD_CAST = 1 << 3,		/* Cast from pointer to integer */
+   ESCAPE_TO_RETURN = 1 << 4,		/* Returned from function.  */
+   ESCAPE_TO_PURE_CONST = 1 << 5,	/* Escapes to a pure or constant
+ 					   function call.  */
+   ESCAPE_IS_GLOBAL = 1 << 6,		/* Is a global variable.  */
+   ESCAPE_IS_PARM = 1 << 7,		/* Is an incoming function argument.  */
+   ESCAPE_UNKNOWN = 1 << 8		/* We believe it escapes for
+ 					   some reason not enumerated
+ 					   above.  */
+ };
+ 
  /* In tree-ssa-alias.c  */
! extern enum escape_type is_escape_site (gimple);
! extern bool may_point_to_global_var (tree);
! extern bool may_point_to_decl (tree, tree);
! extern bool ref_may_used_by_stmt_p (gimple, tree);
! extern bool stmt_may_clobber_ref_p (gimple, tree);
! extern void *walk_non_aliased_vuses (tree, tree,
! 				     void *(*)(tree, tree, void *), void *);
! extern struct ptr_info_def *get_ptr_info (tree);
! extern void dump_alias_info (FILE *);
! extern void debug_alias_info (void);
! extern void dump_points_to_info_for (FILE *, tree);
! extern void debug_points_to_info_for (tree);
! 
! 
! /* In tree-ssa-structalias.c  */
! extern unsigned int compute_may_aliases (void);
! extern void delete_alias_heapvars (void);
! 
  
  /* In tree-dfa.c  */
  extern bool refs_may_alias_p (tree, tree);
  
+ 
  #endif /* TREE_SSA_ALIAS_H  */
Index: alias-improvements/gcc/tree-ssa-structalias.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-structalias.c	2009-01-02 14:50:59.000000000 +0100
--- alias-improvements/gcc/tree-ssa-structalias.c	2009-01-02 16:40:17.000000000 +0100
*************** shared_bitmap_add (bitmap pt_vars)
*** 4635,4640 ****
--- 4635,4682 ----
  }
  
  
+ /* Helper for set_uids_in_ptset to do TBAA pruning of points-to sets.
+    Return TRUE if pointer PTR may point to variable VAR.
+    
+    MEM_ALIAS_SET is the alias set for the memory location pointed-to by PTR
+ 	This is needed because when checking for type conflicts we are
+ 	interested in the alias set of the memory location pointed-to by
+ 	PTR.  The alias set of PTR itself is irrelevant.
+    
+    VAR_ALIAS_SET is the alias set for VAR.  */
+ 
+ static bool
+ may_alias_p (tree ptr, alias_set_type mem_alias_set,
+ 	     tree var, alias_set_type var_alias_set)
+ {
+   /* If -fargument-noalias-global is > 2, pointer arguments may
+      not point to anything else.  */
+   if (flag_argument_noalias > 2 && TREE_CODE (ptr) == PARM_DECL)
+     return false;
+ 
+   /* If -fargument-noalias-global is > 1, pointer arguments may
+      not point to global variables.  */
+   if (flag_argument_noalias > 1 && is_global_var (var)
+       && TREE_CODE (ptr) == PARM_DECL)
+     return false;
+ 
+   /* If the pointed to memory has alias set zero, or the pointer
+      is ref-all, or the pointer decl is marked that no TBAA is to
+      be applied, the MEM can alias VAR.  */
+   if (mem_alias_set == 0
+       || DECL_POINTER_ALIAS_SET (ptr) == 0
+       || TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (ptr))
+       || DECL_NO_TBAA_P (ptr))
+     return true;
+ 
+   /* If the alias sets don't conflict then MEM cannot alias VAR.  */
+   if (mem_alias_set != var_alias_set
+       && !alias_set_subset_of (mem_alias_set, var_alias_set))
+     return false;
+ 
+   return true;
+ }
+ 
  /* Set bits in INTO corresponding to the variable uids in solution set
     FROM, which came from variable PTR.
     For variables that are actually dereferenced, we also use type
*************** set_uids_in_ptset (tree ptr, bitmap into
*** 4677,4683 ****
  	      var_alias_set = get_alias_set (vi->decl);
  	      mem_alias_set = get_alias_set (TREE_TYPE (TREE_TYPE (ptr)));
  	      if (!may_alias_p (SSA_NAME_VAR (ptr), mem_alias_set,
! 				vi->decl, var_alias_set, true))
  		{
  		  ++pruned;
  		  continue;
--- 4719,4725 ----
  	      var_alias_set = get_alias_set (vi->decl);
  	      mem_alias_set = get_alias_set (TREE_TYPE (TREE_TYPE (ptr)));
  	      if (!may_alias_p (SSA_NAME_VAR (ptr), mem_alias_set,
! 				vi->decl, var_alias_set))
  		{
  		  ++pruned;
  		  continue;
*************** find_what_p_points_to (tree p)
*** 4913,4919 ****
     pt_anything escaped which needs all locals that have their address
     taken marked call clobbered as well.  */
  
! bool
  clobber_what_escaped (void)
  {
    varinfo_t vi;
--- 4955,4961 ----
     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;
*************** clobber_what_escaped (void)
*** 4967,4973 ****
  
  /* Compute the call-used variables.  */
  
! void
  compute_call_used_vars (void)
  {
    varinfo_t vi;
--- 5009,5015 ----
  
  /* Compute the call-used variables.  */
  
! static void
  compute_call_used_vars (void)
  {
    varinfo_t vi;
*************** compute_tbaa_pruning (void)
*** 5429,5438 ****
      }
  }
  
  /* Create points-to sets for the current function.  See the comments
     at the start of the file for an algorithmic overview.  */
  
! void
  compute_points_to_sets (void)
  {
    struct scc_info *si;
--- 5471,5500 ----
      }
  }
  
+ /* Initialize the heapvar for statement mapping.  */
+ 
+ static void
+ init_alias_heapvars (void)
+ {
+   if (!heapvar_for_stmt)
+     heapvar_for_stmt = htab_create_ggc (11, tree_map_hash, tree_map_eq,
+ 					NULL);
+ }
+ 
+ /* Delete the heapvar for statement mapping.  */
+ 
+ void
+ delete_alias_heapvars (void)
+ {
+   if (heapvar_for_stmt)
+     htab_delete (heapvar_for_stmt);
+   heapvar_for_stmt = NULL;
+ }
+ 
  /* Create points-to sets for the current function.  See the comments
     at the start of the file for an algorithmic overview.  */
  
! static void
  compute_points_to_sets (void)
  {
    struct scc_info *si;
*************** compute_points_to_sets (void)
*** 5446,5451 ****
--- 5508,5525 ----
  
    intra_create_variable_infos ();
  
+   /* Reset the is_dereferenced flag for all SSA_NAME pointers as we
+      re-compute that in the following.  In theory this information
+      never becomes incorrect semantically, but better play safe.  */
+   for (i = 1; i < num_ssa_names; i++)
+     {
+       tree name = ssa_name (i);
+       if (name
+ 	  && POINTER_TYPE_P (TREE_TYPE (name))
+ 	  && SSA_NAME_PTR_INFO (name))
+ 	SSA_NAME_PTR_INFO (name)->is_dereferenced = 0;
+     }
+ 
    /* Now walk all statements and derive aliases.  */
    FOR_EACH_BB (bb)
      {
*************** compute_points_to_sets (void)
*** 5571,5577 ****
  
  /* Delete created points-to sets.  */
  
! void
  delete_points_to_sets (void)
  {
    unsigned int i;
--- 5645,5651 ----
  
  /* Delete created points-to sets.  */
  
! static void
  delete_points_to_sets (void)
  {
    unsigned int i;
*************** delete_points_to_sets (void)
*** 5602,5607 ****
--- 5676,5838 ----
    have_alias_info = false;
  }
  
+ 
+ /* 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)
+     {
+       bitmap_iterator bi;
+       unsigned int j;
+ 
+       EXECUTE_IF_SET_IN_BITMAP (gimple_addressable_vars (cfun), 0, j, bi)
+ 	{
+ 	  tree var = referenced_var (j);
+ 	  if (!unmodifiable_var_p (var))
+ 	    mark_call_clobbered (var, pt_anything_mask);
+ 	}
+     }
+ 
+   timevar_pop (TV_CALL_CLOBBER);
+ }
+ 
+ /* Reset existing points-to and call-clobber information.  */
+ 
+ static void
+ reset_alias_info (void)
+ {
+   unsigned i;
+ 
+   /* Clear points-to information from each SSA name.  */
+   for (i = 1; i < num_ssa_names; i++)
+     {
+       tree name = ssa_name (i);
+ 
+       if (!name || !POINTER_TYPE_P (TREE_TYPE (name)))
+ 	continue;
+ 
+       if (SSA_NAME_PTR_INFO (name))
+ 	{
+ 	  struct ptr_info_def *pi = SSA_NAME_PTR_INFO (name);
+ 
+ 	  /* Clear all the flags and reset the points-to solution.  */
+ 	  pi->is_dereferenced = 0;
+ 	  pi->pt.anything = 1;
+ 	  pi->pt.nonlocal = 0;
+ 	  pi->pt.escaped = 0;
+ 	  pi->pt.null = 0;
+ 	  pi->pt.vars_contains_global = 0;
+ 	  if (pi->pt.vars)
+ 	    {
+ 	      bitmap_clear (pi->pt.vars);
+ 	      pi->pt.vars = NULL;
+ 	    }
+ 	}
+     }
+ }
+ 
+ 
+ /* 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.  */
+ 
+ unsigned int
+ compute_may_aliases (void)
+ {
+   /* For each pointer P_i, determine the sets of variables that P_i may
+      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)
+     {
+       dump_alias_info (dump_file);
+ 
+       if (dump_flags & TDF_DETAILS)
+ 	dump_referenced_vars (dump_file);
+     }
+ 
+   /* Deallocate memory used by aliasing data structures and the internal
+      points-to solution.  */
+   delete_points_to_sets ();
+ 
+   gcc_assert (!need_ssa_update_p ());
+ 
+   return 0;
+ }
+ 
+ 
+ /* A dummy pass to cause points-to information to be computed via
+    TODO_rebuild_alias.  */
+ 
+ struct gimple_opt_pass pass_build_alias =
+ {
+  {
+   GIMPLE_PASS,
+   "alias",		    /* name */
+   NULL,			    /* gate */
+   NULL,                     /* execute */
+   NULL,                     /* sub */
+   NULL,                     /* next */
+   0,                        /* static_pass_number */
+   0,                        /* tv_id */
+   PROP_cfg | PROP_ssa,      /* properties_required */
+   PROP_alias,               /* properties_provided */
+   0,                        /* properties_destroyed */
+   0,                        /* todo_flags_start */
+   TODO_rebuild_alias | TODO_dump_func  /* todo_flags_finish */
+  }
+ };
+ 
+ 
  /* Return true if we should execute IPA PTA.  */
  static bool
  gate_ipa_pta (void)
*************** struct simple_ipa_opt_pass pass_ipa_pta 
*** 5736,5756 ****
   }
  };
  
- /* Initialize the heapvar for statement mapping.  */
- void
- init_alias_heapvars (void)
- {
-   if (!heapvar_for_stmt)
-     heapvar_for_stmt = htab_create_ggc (11, tree_map_hash, tree_map_eq,
- 					NULL);
- }
- 
- void
- delete_alias_heapvars (void)
- {
-   if (heapvar_for_stmt)
-     htab_delete (heapvar_for_stmt);
-   heapvar_for_stmt = NULL;
- }
  
  #include "gt-tree-ssa-structalias.h"
--- 5967,5971 ----
Index: alias-improvements/gcc/tree-ssa-structalias.h
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-structalias.h	2009-01-02 15:11:16.000000000 +0100
--- alias-improvements/gcc/tree-ssa-structalias.h	2009-01-02 15:12:46.000000000 +0100
***************
*** 24,35 ****
  struct constraint;
  typedef struct constraint *constraint_t;
  
- /* In tree-ssa-alias.c.  */
- enum escape_type is_escape_site (gimple);
- 
  /* In tree-ssa-structalias.c.  */
- extern void compute_points_to_sets (void);
- extern void delete_points_to_sets (void);
  extern void dump_constraint (FILE *, constraint_t);
  extern void dump_constraint_edge (FILE *, constraint_t);
  extern void dump_constraints (FILE *);
--- 24,30 ----


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