This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH][alias-improvements] Documentation for tree-ssa-alias.c, cleanups
- From: Richard Guenther <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 2 Jan 2009 18:02:16 +0100 (CET)
- Subject: [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 ----