This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH][alias-improvements] Get rid of old TBAA aliasing code, fix early call-clobbers
- From: Richard Guenther <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 26 Nov 2008 17:01:52 +0100 (CET)
- Subject: [PATCH][alias-improvements] Get rid of old TBAA aliasing code, fix early call-clobbers
This removes all traces of SMTs, NMTs, MPTs and the code creating or
dealing with them.
It also makes us have correct call-clobber state during early
optimization, possibly refined by points-to analysis when available.
As we glob nonlocals in points-to we can also glob globals for
call clobber purposes and simply only record locals in the call-clobber
bitmap. I dropped the bit in the var annotation because it is tedious
and error-prone to keep them in sync.
I tried to split both patches (after the fact), but it was too difficult.
Bootstrapped and tested on x86_64-unknown-linux-gnu w/o ada (Ada is broken
with that patch, the testsuite is clean but stage3 just complains about
ada.ads:19:01: "end Ada;" expected in column 1
I failed to even start debugging where the error comes from, so be it -
Ada is broken on the branch now). Installed to the branch.
_The_ major cleanup opportunity left is moving the virtual operands
to a more sane representation - now that we have at most one VDEF
and one V{MAY,}USE. A simple idea would be to use the first SSA
operand slot for them. The bitmap of stores can become a single
pointer (we have at most one stored symbol, not counting .MEM, which
I do not record anymore). We can still have many loads in call
arguments though.
Richard.
2008-11-25 Richard Guenther <rguenther@suse.de>
* gimple.c (is_gimple_reg): Do not handle memory tags.
* ipa-cp.c (ipcp_update_callgraph): Fix typo.
* passes.c (init_optimization_passes): Schedule
update_address_taken pass before points-to analysis.
* tree-data-ref.c (dr_analyze_alias): Ignore vops and SMTs.
(free_data_ref): Likewise.
(create_data_ref): Likewise.
(dr_may_alias_p): Likewise.
(analyze_all_data_dependences): Likewise.
* tree-dfa.c (dump_variable): Do not dump SMTs, memory stats,
may-aliases or partitions.
(remove_referenced_var): Do not clear mpt or symbol_mem_tag.
* tree-dump.c (dequeue_and_dump): Do not handle SYMBOL_MEMORY_TAG
or NAME_MEMORY_TAG.
* tree-flow-inline.h (gimple_aliases_computed_p): Remove.
(gimple_global_var): Likewise.
(may_aliases): Likewise.
(is_global_var): Remove MTAG code.
(unmodifiable_var_p): Likewise.
(memory_partition): Remove.
(factoring_name_p): Likewise.
(symbol_mem_tag): Likewise.
(set_symbol_mem_tag): Likewise.
(gimple_mem_ref_stats): Likewise.
* tree-flow.h (struct mem_sym_stats_d): Remove.
(struct mem_ref_stats_d): Likewise.
(struct gimple_df): Remove global_var, aliases_computed_p and
mem_ref_stats fields.
(struct ptr_info_def): Remove memory_tag_needed and name_mem_tag
fields.
(struct var_ann_d): Remove call_clobbered, mpt and symbol_mem_tag
fields.
* tree-into-ssa (mark_sym_for_renaming): Remove memory paritioning
code.
(update_ssa): Likewise.
* tree-outof-ssa.c (create_temp): Do not set SMT.
* tree-predcom.c (set_alias_info): Remove.
(prepare_initializers_chain): Do not call it.
* tree-pretty-print.c (dump_generic_node): Do not handle memory tags.
* tree-sra.c (sra_walk_function): Use gimple_references_memory_p.
* tree-ssa-alias.c (struct alias_info): Remove.
(get_mem_sym_stats_for, mem_sym_stats, set_memory_partition,
mark_non_addressable, sort_tags_by_id, init_transitive_clobber_worklist,
add_to_worklist, mark_aliases_call_clobbered, compute_tag_properties):
Remove.
(set_initial_properties): Rename to compute_call_clobbered.
(dump_memory_partitions, debug_memory_partitions, need_to_partition_p,
mem_sym_score, count_mem_refs, dump_mem_ref_stats, debug_mem_ref_stats,
dump_mem_sym_stats, debug_mem_sym_stats, dump_mem_sym_stats_for_var,
dump_all_mem_sym_stats, debug_all_mem_sym_stats, dump_mp_info,
debug_mp_info, update_mem_sym_stats_from_stmt, compare_mp_info_entries,
mp_info_cmp, sort_mp_info, get_mpt_for, find_partition_for,
rewrite_alias_set_for, estimate_vop_reduction, update_reference_counts,
build_mp_info, compute_memory_partitions): Remove.
(compute_may_aliases): Remove all but points-to analysis code.
(reset_alias_info): Likewise.
(init_alias_info): Likewise.
(compute_flow_sensitive_aliasing): Likewise.
(delete_mem_ref_stats, init_mem_ref_stats, delete_alias_info,
eq_ptr_info, ptr_info_hash, create_name_tags, union_alias_set_into,
have_common_aliases_p, compute_flow_insensitive_aliasing,
create_alias_map_for, update_alias_info_1, update_alias_info,
setup_pointers_and_addressables, maybe_create_global_var): Remove.
(may_alias_p): Remove SMT code.
(may_point_to_global_var): Adjust.
(add_may_alias): Remove.
(set_pt_anything): Adjust.
(create_tag_raw, create_memory_tag, get_nmt_for, get_smt_for,
create_global_var): Remove.
(dump_alias_info): Adjust.
(dump_points_to_info_for): Likewise.
(dump_may_aliases_for, debug_may_aliases_for, add_may_alias_for_new_tag,
new_type_alias): Remove.
* tree-ssa-ccp.c (get_symbol_constant_value): Remove memory-tag
related code.
* tree-ssa-copy.c (may_propagate_copy): Likewise.
(may_propagate_copy_into_stmt): Likewise.
(merge_alias_info): Do nothing for now.
* tree-ssa-copyrename.c (copy_rename_partition_coalesce): Remove
memory-tag related code.
* tree-ssa-live.c (remove_unused_locals): Likewise.
* tree-ssa-loop-ivopts.c (get_ref_tag): Remove.
(copy_ref_info): Remove memory-tag related code.
* tree-ssa-operands.c (init_ssa_operands): Likewise.
(fini_ssa_operands): Likewise.
(get_expr_operands): Likewise.
* tree-ssa-operands.h (struct ssa_operands): Remove mpt_table field.
* tree-ssa-phiprop.c (propagate_with_phi): Remove memory-tag related
code.
* tree-ssa-structalias.c (find_func_aliases): Do not mark stmts
modified.
(var_can_have_subvars): Remove memory-tag related code.
(set_uids_in_ptset): Mark pointer-info as pt_global_mem if the set
contains a global variable.
(delete_alias_heapvars): Allow unconditional call.
* tree-ssa-structalias.h (update_mem_sym_stats_from_stmt): Remove.
* tree-ssa.c (verify_flow_insensitive_alias_info): Remove.
(verify_flow_sensitive_alias_info): Likewise.
(verify_call_clobbering): Adjust.
(verify_memory_partitions): Remove.
(verify_alias_info): Adjust.
(verify_ssa): Likewise.
(delete_tree_ssa): Remove memory-tag related code.
(warn_uninitialized_var): Aliases are always available.
(execute_update_addresses_taken): Update gimple_addressable_vars.
Update call-clobber state.
* tree-tailcall.c (suitable_for_tail_opt_p): Remove memory-tag
related code.
(find_tail_calls): Use gimple_references_memory_p.
* tree-vect-transform.c (vect_create_data_ref_ptr): Remove memory-tag
related code.
* tree.c (init_ttree): Likewise.
(tree_code_size): Likewise.
(tree_node_structure): Likewise.
(build7_stat): Re-write to be build6_stat.
* tree.h (MTAG_P, TREE_MEMORY_TAG_CHECK, TMR_TAG): Remove.
(SSA_VAR_P): Adjust.
(struct tree_memory_tag): Remove.
(struct tree_memory_partition_tag): Likewise.
(union tree_node): Adjust.
(build7): Re-write to be build6.
* treestruct.def (TS_MEMORY_TAG, TS_MEMORY_PARTITION_TAG): Remove.
* tree-ssa-alias-warnings.c (build_reference_table): Remove
memory-tag related code.
(ffan_walker): Likewise.
(detect_strict_aliasing_named): Likewise.
* tree-data-ref.h (struct dr_alias): Remove symbol_tag field.
(DR_SYMBOL_TAG, DR_VOPS): Remove.
* tree-ssa-address.c (create_mem_ref_raw): Use build6.
(get_address_description): Remove memory-tag related code.
* tree-vect-analyze.c (vect_analyze_data_refs): Likewise.
* tree.def (NAME_MEMORY_TAG, SYMBOL_MEMORY_TAG, MEMORY_PARTITION_TAG):
Remove.
(TARGET_MEM_REF): Remove TMR_TAG operand.
* tree-dfa.c (add_referenced_var): Initialize call-clobber state.
* tree-flow-inline.h (is_call_used): Use is_call_clobbered.
(is_call_clobbered): Global variables are always call clobbered,
query the call-clobbers bitmap.
(mark_call_clobbered): Ignore global variables.
(clear_call_clobbered): Likewise.
* tree-ssa-alias.c (reset_cc_flags): Do not clear all
call-clobber flags. Verify initial state instead.
* tree-ssa.c (verify_call_clobbering): Adjust.
Index: alias-improvements/gcc/tree-ssa-alias.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-alias.c 2008-11-26 13:47:33.000000000 +0100
--- alias-improvements/gcc/tree-ssa-alias.c 2008-11-26 16:49:17.000000000 +0100
*************** along with GCC; see the file COPYING3.
*** 167,207 ****
ourselves. */
- /* Alias information used by compute_may_aliases and its helpers. */
- struct alias_info
- {
- /* SSA names visited while collecting points-to information. If bit I
- is set, it means that SSA variable with version I has already been
- visited. */
- sbitmap ssa_names_visited;
-
- /* Array of SSA_NAME pointers processed by the points-to collector. */
- VEC(tree,heap) *processed_ptrs;
-
- /* ADDRESSABLE_VARS contains all the global variables and locals that
- have had their address taken. */
- struct alias_map_d **addressable_vars;
- size_t num_addressable_vars;
-
- /* POINTERS contains all the _DECL pointers with unique memory tags
- that have been referenced in the program. */
- struct alias_map_d **pointers;
- size_t num_pointers;
-
- /* Pointers that have been used in an indirect load/store operation. */
- struct pointer_set_t *dereferenced_ptrs;
- };
-
-
- /* Structure to map a variable to its alias set. */
- struct alias_map_d
- {
- /* Variable and its alias set. */
- tree var;
- alias_set_type set;
- };
-
-
/* Counters used to display statistics on alias analysis. */
struct alias_stats_d
{
--- 167,172 ----
*************** struct alias_stats_d
*** 219,553 ****
/* Local variables. */
static struct alias_stats_d alias_stats;
- static bitmap_obstack alias_bitmap_obstack;
/* Local functions. */
- static void compute_flow_insensitive_aliasing (struct alias_info *);
static void dump_alias_stats (FILE *);
! static tree create_memory_tag (tree type, bool is_type_tag);
! static tree get_smt_for (tree, struct alias_info *);
! static tree get_nmt_for (tree);
! static void add_may_alias (tree, tree);
! static struct alias_info *init_alias_info (void);
! static void delete_alias_info (struct alias_info *);
! static void compute_flow_sensitive_aliasing (struct alias_info *);
! static void setup_pointers_and_addressables (struct alias_info *);
! static void update_alias_info (struct alias_info *);
! static void create_global_var (void);
! static void maybe_create_global_var (void);
static void set_pt_anything (tree);
- void debug_mp_info (VEC(mem_sym_stats_t,heap) *);
-
- static alloc_pool mem_sym_stats_pool;
-
- /* Return memory reference stats for symbol VAR. Create a new slot in
- cfun->gimple_df->mem_sym_stats if needed. */
-
- static struct mem_sym_stats_d *
- get_mem_sym_stats_for (tree var)
- {
- void **slot;
- struct mem_sym_stats_d *stats;
- struct pointer_map_t *map = gimple_mem_ref_stats (cfun)->mem_sym_stats;
-
- gcc_assert (map);
-
- slot = pointer_map_insert (map, var);
- if (*slot == NULL)
- {
- stats = (struct mem_sym_stats_d *) pool_alloc (mem_sym_stats_pool);
- memset (stats, 0, sizeof (*stats));
- stats->var = var;
- *slot = (void *) stats;
- }
- else
- stats = (struct mem_sym_stats_d *) *slot;
-
- return stats;
- }
-
-
- /* Return memory reference statistics for variable VAR in function FN.
- This is computed by alias analysis, but it is not kept
- incrementally up-to-date. So, these stats are only accurate if
- pass_may_alias has been run recently. If no alias information
- exists, this function returns NULL. */
-
- static mem_sym_stats_t
- mem_sym_stats (struct function *fn, tree var)
- {
- void **slot;
- struct pointer_map_t *stats_map = gimple_mem_ref_stats (fn)->mem_sym_stats;
-
- if (stats_map == NULL)
- return NULL;
-
- slot = pointer_map_contains (stats_map, var);
- if (slot == NULL)
- return NULL;
-
- return (mem_sym_stats_t) *slot;
- }
-
-
- /* Set MPT to be the memory partition associated with symbol SYM. */
-
- static inline void
- set_memory_partition (tree sym, tree mpt)
- {
- #if defined ENABLE_CHECKING
- if (mpt)
- gcc_assert (TREE_CODE (mpt) == MEMORY_PARTITION_TAG
- && !is_gimple_reg (sym));
- #endif
-
- var_ann (sym)->mpt = mpt;
- if (mpt)
- {
- if (MPT_SYMBOLS (mpt) == NULL)
- MPT_SYMBOLS (mpt) = BITMAP_ALLOC (&alias_bitmap_obstack);
-
- bitmap_set_bit (MPT_SYMBOLS (mpt), DECL_UID (sym));
-
- /* MPT inherits the call-clobbering attributes from SYM. */
- if (is_call_clobbered (sym))
- {
- MTAG_GLOBAL (mpt) = 1;
- mark_call_clobbered (mpt, ESCAPE_IS_GLOBAL);
- }
- }
- }
-
-
- /* Mark variable VAR as being non-addressable. */
-
- static void
- mark_non_addressable (tree var)
- {
- tree mpt;
-
- if (!TREE_ADDRESSABLE (var))
- return;
-
- mpt = memory_partition (var);
-
- clear_call_clobbered (var);
- TREE_ADDRESSABLE (var) = 0;
-
- if (mpt)
- {
- /* Note that it's possible for a symbol to have an associated
- MPT and the MPT have a NULL empty set. During
- init_alias_info, all MPTs get their sets cleared out, but the
- symbols still point to the old MPTs that used to hold them.
- This is done so that compute_memory_partitions can now which
- symbols are losing or changing partitions and mark them for
- renaming. */
- if (MPT_SYMBOLS (mpt))
- bitmap_clear_bit (MPT_SYMBOLS (mpt), DECL_UID (var));
- set_memory_partition (var, NULL_TREE);
- }
- }
-
-
- /* qsort comparison function to sort type/name tags by DECL_UID. */
-
- static int
- sort_tags_by_id (const void *pa, const void *pb)
- {
- const_tree const a = *(const_tree const *)pa;
- const_tree const b = *(const_tree const *)pb;
-
- return DECL_UID (a) - DECL_UID (b);
- }
-
- /* Initialize WORKLIST to contain those memory tags that are marked call
- clobbered. Initialized WORKLIST2 to contain the reasons these
- memory tags escaped. */
-
- static void
- init_transitive_clobber_worklist (VEC (tree, heap) **worklist,
- VEC (int, heap) **worklist2,
- bitmap on_worklist)
- {
- referenced_var_iterator rvi;
- tree curr;
-
- FOR_EACH_REFERENCED_VAR (curr, rvi)
- {
- if (MTAG_P (curr) && is_call_clobbered (curr))
- {
- VEC_safe_push (tree, heap, *worklist, curr);
- VEC_safe_push (int, heap, *worklist2,
- var_ann (curr)->escape_mask);
- bitmap_set_bit (on_worklist, DECL_UID (curr));
- }
- }
- }
-
- /* Add ALIAS to WORKLIST (and the reason for escaping REASON to WORKLIST2) if
- ALIAS is not already marked call clobbered, and is a memory
- tag. */
-
- static void
- add_to_worklist (tree alias, VEC (tree, heap) **worklist,
- VEC (int, heap) **worklist2, int reason,
- bitmap on_worklist)
- {
- if (MTAG_P (alias) && !is_call_clobbered (alias)
- && !bitmap_bit_p (on_worklist, DECL_UID (alias)))
- {
- VEC_safe_push (tree, heap, *worklist, alias);
- VEC_safe_push (int, heap, *worklist2, reason);
- bitmap_set_bit (on_worklist, DECL_UID (alias));
- }
- }
-
- /* Mark aliases of TAG as call clobbered, and place any tags on the
- alias list that were not already call clobbered on WORKLIST. */
-
- static void
- mark_aliases_call_clobbered (tree tag, VEC (tree, heap) **worklist,
- VEC (int, heap) **worklist2, bitmap on_worklist)
- {
- bitmap aliases;
- bitmap_iterator bi;
- unsigned int i;
- tree entry;
- var_ann_t ta = var_ann (tag);
-
- if (!MTAG_P (tag))
- return;
- aliases = may_aliases (tag);
- if (!aliases)
- return;
-
- EXECUTE_IF_SET_IN_BITMAP (aliases, 0, i, bi)
- {
- entry = referenced_var (i);
- /* If you clobber one part of a structure, you
- clobber the entire thing. While this does not make
- the world a particularly nice place, it is necessary
- in order to allow C/C++ tricks that involve
- pointer arithmetic to work. */
- if (!unmodifiable_var_p (entry))
- {
- add_to_worklist (entry, worklist, worklist2, ta->escape_mask,
- on_worklist);
- mark_call_clobbered (entry, ta->escape_mask);
- }
- }
- }
-
- /* Tags containing global vars need to be marked as global.
- Tags containing call clobbered vars need to be marked as call
- clobbered. */
-
- static void
- compute_tag_properties (void)
- {
- referenced_var_iterator rvi;
- tree tag;
- bool changed = true;
- VEC (tree, heap) *taglist = NULL;
-
- FOR_EACH_REFERENCED_VAR (tag, rvi)
- {
- if (!MTAG_P (tag))
- continue;
- VEC_safe_push (tree, heap, taglist, tag);
- }
-
- /* We sort the taglist by DECL_UID, for two reasons.
- 1. To get a sequential ordering to make the bitmap accesses
- faster.
- 2. Because of the way we compute aliases, it's more likely that
- an earlier tag is included in a later tag, and this will reduce
- the number of iterations.
-
- If we had a real tag graph, we would just topo-order it and be
- done with it. */
- qsort (VEC_address (tree, taglist),
- VEC_length (tree, taglist),
- sizeof (tree),
- sort_tags_by_id);
-
- /* Go through each tag not marked as global, and if it aliases
- global vars, mark it global.
-
- If the tag contains call clobbered vars, mark it call
- clobbered.
-
- This loop iterates because tags may appear in the may-aliases
- list of other tags when we group. */
-
- while (changed)
- {
- unsigned int k;
-
- changed = false;
- for (k = 0; VEC_iterate (tree, taglist, k, tag); k++)
- {
- bitmap ma;
- bitmap_iterator bi;
- unsigned int i;
- tree entry;
- bool tagcc = is_call_clobbered (tag);
- bool tagglobal = MTAG_GLOBAL (tag);
-
- if (tagcc && tagglobal)
- continue;
-
- ma = may_aliases (tag);
- if (!ma)
- continue;
-
- EXECUTE_IF_SET_IN_BITMAP (ma, 0, i, bi)
- {
- entry = referenced_var (i);
- /* Call clobbered entries cause the tag to be marked
- call clobbered. */
- if (!tagcc && is_call_clobbered (entry))
- {
- mark_call_clobbered (tag, var_ann (entry)->escape_mask);
- tagcc = true;
- changed = true;
- }
-
- /* Global vars cause the tag to be marked global. */
- if (!tagglobal && is_global_var (entry))
- {
- MTAG_GLOBAL (tag) = true;
- changed = true;
- tagglobal = true;
- }
-
- /* Early exit once both global and cc are set, since the
- loop can't do any more than that. */
- if (tagcc && tagglobal)
- break;
- }
- }
- }
- VEC_free (tree, heap, taglist);
- }
! /* Set up the initial variable clobbers, call-uses and globalness.
! When this function completes, only tags whose aliases need to be
! clobbered will be set clobbered. Tags clobbered because they
! contain call clobbered vars are handled in compute_tag_properties. */
static void
! set_initial_properties (struct alias_info *ai)
{
- unsigned int i;
referenced_var_iterator rvi;
tree var;
- tree ptr;
bool any_pt_anything = false;
enum escape_type pt_anything_mask = 0;
FOR_EACH_REFERENCED_VAR (var, rvi)
{
if (is_global_var (var))
--- 184,210 ----
/* Local variables. */
static struct alias_stats_d alias_stats;
/* Local functions. */
static void dump_alias_stats (FILE *);
! static void compute_flow_sensitive_aliasing (void);
static void set_pt_anything (tree);
+ 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))
*************** set_initial_properties (struct alias_inf
*** 573,631 ****
compute_call_used_vars ();
- for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
- {
- struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
- tree tag = symbol_mem_tag (SSA_NAME_VAR (ptr));
-
- /* A pointer that only escapes via a function return does not
- add to the call clobber or call used solution.
- To exclude ESCAPE_TO_PURE_CONST we would need to track
- call used variables separately or compute those properly
- in the operand scanner. */
- if (pi->value_escapes_p
- && pi->escape_mask & ~ESCAPE_TO_RETURN)
- {
- /* If PTR escapes then its associated memory tags and
- pointed-to variables are call-clobbered. */
- if (pi->name_mem_tag)
- mark_call_clobbered (pi->name_mem_tag, pi->escape_mask);
-
- if (tag)
- mark_call_clobbered (tag, pi->escape_mask);
- }
-
- /* If the name tag is call clobbered, so is the symbol tag
- associated with the base VAR_DECL. */
- if (pi->name_mem_tag
- && tag
- && is_call_clobbered (pi->name_mem_tag))
- mark_call_clobbered (tag, pi->escape_mask);
-
- /* Name tags and symbol tags that we don't know where they point
- to, might point to global memory, and thus, are clobbered.
-
- FIXME: This is not quite right. They should only be
- clobbered if value_escapes_p is true, regardless of whether
- they point to global memory or not.
- So removing this code and fixing all the bugs would be nice.
- It is the cause of a bunch of clobbering. */
- if ((pi->pt_global_mem || pi->pt_anything)
- && pi->memory_tag_needed && pi->name_mem_tag)
- {
- mark_call_clobbered (pi->name_mem_tag, ESCAPE_IS_GLOBAL);
- MTAG_GLOBAL (pi->name_mem_tag) = true;
- }
-
- if ((pi->pt_global_mem || pi->pt_anything)
- && pi->memory_tag_needed
- && tag)
- {
- mark_call_clobbered (tag, ESCAPE_IS_GLOBAL);
- MTAG_GLOBAL (tag) = true;
- }
- }
-
/* If a pt_anything pointer escaped we need to mark all addressable
variables call clobbered. */
if (any_pt_anything)
--- 230,235 ----
*************** set_initial_properties (struct alias_inf
*** 640,2907 ****
mark_call_clobbered (var, pt_anything_mask);
}
}
- }
- /* Compute which variables need to be marked call clobbered because
- their tag is call clobbered, and which tags need to be marked
- global because they contain global variables. */
-
- static void
- compute_call_clobbered (struct alias_info *ai)
- {
- VEC (tree, heap) *worklist = NULL;
- VEC (int,heap) *worklist2 = NULL;
- bitmap on_worklist;
-
- timevar_push (TV_CALL_CLOBBER);
- on_worklist = BITMAP_ALLOC (NULL);
-
- set_initial_properties (ai);
- init_transitive_clobber_worklist (&worklist, &worklist2, on_worklist);
- while (VEC_length (tree, worklist) != 0)
- {
- tree curr = VEC_pop (tree, worklist);
- int reason = VEC_pop (int, worklist2);
-
- bitmap_clear_bit (on_worklist, DECL_UID (curr));
- mark_call_clobbered (curr, reason);
- mark_aliases_call_clobbered (curr, &worklist, &worklist2, on_worklist);
- }
- VEC_free (tree, heap, worklist);
- VEC_free (int, heap, worklist2);
- BITMAP_FREE (on_worklist);
- compute_tag_properties ();
timevar_pop (TV_CALL_CLOBBER);
}
! /* Dump memory partition information to FILE. */
! static void
! dump_memory_partitions (FILE *file)
! {
! unsigned i, npart;
! unsigned long nsyms;
! tree mpt;
!
! fprintf (file, "\nMemory partitions\n\n");
! for (i = 0, npart = 0, nsyms = 0;
! VEC_iterate (tree, gimple_ssa_operands (cfun)->mpt_table, i, mpt);
! i++)
! {
! if (mpt)
! {
! bitmap syms = MPT_SYMBOLS (mpt);
! unsigned long n = (syms) ? bitmap_count_bits (syms) : 0;
! fprintf (file, "#%u: ", i);
! print_generic_expr (file, mpt, 0);
! fprintf (file, ": %lu elements: ", n);
! dump_decl_set (file, syms);
! npart++;
! nsyms += n;
! }
! }
! fprintf (file, "\n%u memory partitions holding %lu symbols\n", npart, nsyms);
! }
! /* Dump memory partition information to stderr. */
! void
! debug_memory_partitions (void)
! {
! dump_memory_partitions (stderr);
! }
! /* Return true if memory partitioning is required given the memory
! reference estimates in STATS. */
! static inline bool
! need_to_partition_p (struct mem_ref_stats_d *stats)
! {
! long num_vops = stats->num_vuses + stats->num_vdefs;
! long avg_vops = CEIL (num_vops, stats->num_mem_stmts);
! return (num_vops > (long) MAX_ALIASED_VOPS
! && avg_vops > (long) AVG_ALIASED_VOPS);
! }
- /* Count the actual number of virtual operators in CFUN. Note that
- this is only meaningful after virtual operands have been populated,
- so it should be invoked at the end of compute_may_aliases.
-
- The number of virtual operators are stored in *NUM_VDEFS_P and
- *NUM_VUSES_P, the number of partitioned symbols in
- *NUM_PARTITIONED_P and the number of unpartitioned symbols in
- *NUM_UNPARTITIONED_P.
! If any of these pointers is NULL the corresponding count is not
! computed. */
! static void
! count_mem_refs (long *num_vuses_p, long *num_vdefs_p,
! long *num_partitioned_p, long *num_unpartitioned_p)
! {
! gimple_stmt_iterator gsi;
! basic_block bb;
! long num_vdefs, num_vuses, num_partitioned, num_unpartitioned;
! referenced_var_iterator rvi;
! tree sym;
! num_vuses = num_vdefs = num_partitioned = num_unpartitioned = 0;
! if (num_vuses_p || num_vdefs_p)
! FOR_EACH_BB (bb)
! for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
! {
! gimple stmt = gsi_stmt (gsi);
! if (gimple_references_memory_p (stmt))
{
! num_vuses += NUM_SSA_OPERANDS (stmt, SSA_OP_VUSE);
! num_vdefs += NUM_SSA_OPERANDS (stmt, SSA_OP_VDEF);
}
- }
! if (num_partitioned_p || num_unpartitioned_p)
! FOR_EACH_REFERENCED_VAR (sym, rvi)
! {
! if (is_gimple_reg (sym))
! continue;
!
! if (memory_partition (sym))
! num_partitioned++;
! else
! num_unpartitioned++;
! }
!
! if (num_vdefs_p)
! *num_vdefs_p = num_vdefs;
! if (num_vuses_p)
! *num_vuses_p = num_vuses;
! if (num_partitioned_p)
! *num_partitioned_p = num_partitioned;
! if (num_unpartitioned_p)
! *num_unpartitioned_p = num_unpartitioned;
! }
! /* The list is sorted by increasing partitioning score (PSCORE).
! This score is computed such that symbols with high scores are
! those that are least likely to be partitioned. Given a symbol
! MP->VAR, PSCORE(S) is the result of the following weighted sum
!
! PSCORE(S) = FW * 64 + FR * 32
! + DW * 16 + DR * 8
! + IW * 4 + IR * 2
! + NO_ALIAS
!
! where
!
! FW Execution frequency of writes to S
! FR Execution frequency of reads from S
! DW Number of direct writes to S
! DR Number of direct reads from S
! IW Number of indirect writes to S
! IR Number of indirect reads from S
! NO_ALIAS State of the NO_ALIAS* flags
!
! The basic idea here is that symbols that are frequently
! written-to in hot paths of the code are the last to be considered
! for partitioning. */
!
! static inline long
! mem_sym_score (mem_sym_stats_t mp)
! {
! return mp->frequency_writes * 64 + mp->frequency_reads * 32
! + mp->num_direct_writes * 16 + mp->num_direct_reads * 8
! + mp->num_indirect_writes * 4 + mp->num_indirect_reads * 2
! + var_ann (mp->var)->noalias_state;
! }
! /* Dump memory reference stats for function CFUN to FILE. */
! void
! dump_mem_ref_stats (FILE *file)
{
! long actual_num_vuses, actual_num_vdefs;
! long num_partitioned, num_unpartitioned;
! struct mem_ref_stats_d *stats;
! stats = gimple_mem_ref_stats (cfun);
!
! count_mem_refs (&actual_num_vuses, &actual_num_vdefs, &num_partitioned,
! &num_unpartitioned);
! fprintf (file, "\nMemory reference statistics for %s\n\n",
! lang_hooks.decl_printable_name (current_function_decl, 2));
! fprintf (file, "Number of memory statements: %ld\n",
! stats->num_mem_stmts);
! fprintf (file, "Number of call sites: %ld\n",
! stats->num_call_sites);
! fprintf (file, "Number of pure/const call sites: %ld\n",
! stats->num_pure_const_call_sites);
! fprintf (file, "Number of asm sites: %ld\n",
! stats->num_asm_sites);
! fprintf (file, "Estimated number of loads: %ld (%ld/stmt)\n",
! stats->num_vuses,
! (stats->num_mem_stmts)
! ? CEIL (stats->num_vuses, stats->num_mem_stmts)
! : 0);
! fprintf (file, "Actual number of loads: %ld (%ld/stmt)\n",
! actual_num_vuses,
! (stats->num_mem_stmts)
! ? CEIL (actual_num_vuses, stats->num_mem_stmts)
! : 0);
!
! if (actual_num_vuses > stats->num_vuses + (stats->num_vuses / 25))
! fprintf (file, "\t(warning: estimation is lower by more than 25%%)\n");
!
! fprintf (file, "Estimated number of stores: %ld (%ld/stmt)\n",
! stats->num_vdefs,
! (stats->num_mem_stmts)
! ? CEIL (stats->num_vdefs, stats->num_mem_stmts)
! : 0);
! fprintf (file, "Actual number of stores: %ld (%ld/stmt)\n",
! actual_num_vdefs,
! (stats->num_mem_stmts)
! ? CEIL (actual_num_vdefs, stats->num_mem_stmts)
! : 0);
!
! if (actual_num_vdefs > stats->num_vdefs + (stats->num_vdefs / 25))
! fprintf (file, "\t(warning: estimation is lower by more than 25%%)\n");
!
! fprintf (file, "Partitioning thresholds: MAX = %d AVG = %d "
! "(%sNEED TO PARTITION)\n", MAX_ALIASED_VOPS, AVG_ALIASED_VOPS,
! stats->num_mem_stmts && need_to_partition_p (stats) ? "" : "NO ");
! fprintf (file, "Number of partitioned symbols: %ld\n", num_partitioned);
! fprintf (file, "Number of unpartitioned symbols: %ld\n", num_unpartitioned);
! }
! /* Dump memory reference stats for function FN to stderr. */
! void
! debug_mem_ref_stats (void)
! {
! dump_mem_ref_stats (stderr);
! }
!
! /* Dump memory reference stats for variable VAR to FILE. */
!
! static void
! dump_mem_sym_stats (FILE *file, tree var)
! {
! mem_sym_stats_t stats = mem_sym_stats (cfun, var);
!
! if (stats == NULL)
! return;
!
! fprintf (file, "read frequency: %6ld, write frequency: %6ld, "
! "direct reads: %3ld, direct writes: %3ld, "
! "indirect reads: %4ld, indirect writes: %4ld, symbol: ",
! stats->frequency_reads, stats->frequency_writes,
! stats->num_direct_reads, stats->num_direct_writes,
! stats->num_indirect_reads, stats->num_indirect_writes);
! print_generic_expr (file, stats->var, 0);
! fprintf (file, ", tags: ");
! dump_decl_set (file, stats->parent_tags);
! }
!
!
! /* Dump memory reference stats for variable VAR to stderr. */
!
! void
! debug_mem_sym_stats (tree var)
! {
! dump_mem_sym_stats (stderr, var);
! }
!
! /* Dump memory reference stats for variable VAR to FILE. For use
! of tree-dfa.c:dump_variable. */
!
! void
! dump_mem_sym_stats_for_var (FILE *file, tree var)
! {
! mem_sym_stats_t stats = mem_sym_stats (cfun, var);
!
! if (stats == NULL)
! return;
!
! fprintf (file, ", score: %ld", mem_sym_score (stats));
! fprintf (file, ", direct reads: %ld", stats->num_direct_reads);
! fprintf (file, ", direct writes: %ld", stats->num_direct_writes);
! fprintf (file, ", indirect reads: %ld", stats->num_indirect_reads);
! fprintf (file, ", indirect writes: %ld", stats->num_indirect_writes);
! }
!
! /* Dump memory reference stats for all memory symbols to FILE. */
!
! static void
! dump_all_mem_sym_stats (FILE *file)
! {
! referenced_var_iterator rvi;
! tree sym;
!
! FOR_EACH_REFERENCED_VAR (sym, rvi)
! {
! if (is_gimple_reg (sym))
! continue;
!
! dump_mem_sym_stats (file, sym);
! }
! }
!
!
! /* Dump memory reference stats for all memory symbols to stderr. */
!
! void
! debug_all_mem_sym_stats (void)
! {
! dump_all_mem_sym_stats (stderr);
! }
!
!
! /* Dump the MP_INFO array to FILE. */
!
! static void
! dump_mp_info (FILE *file, VEC(mem_sym_stats_t,heap) *mp_info)
! {
! unsigned i;
! mem_sym_stats_t mp_p;
!
! for (i = 0; VEC_iterate (mem_sym_stats_t, mp_info, i, mp_p); i++)
! if (!mp_p->partitioned_p)
! dump_mem_sym_stats (file, mp_p->var);
! }
!
!
! /* Dump the MP_INFO array to stderr. */
!
! void
! debug_mp_info (VEC(mem_sym_stats_t,heap) *mp_info)
! {
! dump_mp_info (stderr, mp_info);
! }
!
!
! /* Update memory reference stats for symbol VAR in statement STMT.
! NUM_DIRECT_READS and NUM_DIRECT_WRITES specify the number of times
! that VAR is read/written in STMT (indirect reads/writes are not
! recorded by this function, see compute_memory_partitions). */
!
! void
! update_mem_sym_stats_from_stmt (tree var, gimple stmt, long num_direct_reads,
! long num_direct_writes)
! {
! mem_sym_stats_t stats;
!
! gcc_assert (num_direct_reads >= 0 && num_direct_writes >= 0);
!
! stats = get_mem_sym_stats_for (var);
!
! stats->num_direct_reads += num_direct_reads;
! stats->frequency_reads += ((long) gimple_bb (stmt)->frequency
! * num_direct_reads);
!
! stats->num_direct_writes += num_direct_writes;
! stats->frequency_writes += ((long) gimple_bb (stmt)->frequency
! * num_direct_writes);
! }
!
!
! /* Given two MP_INFO entries MP1 and MP2, return -1 if MP1->VAR should
! be partitioned before MP2->VAR, 0 if they are the same or 1 if
! MP1->VAR should be partitioned after MP2->VAR. */
!
! static inline int
! compare_mp_info_entries (mem_sym_stats_t mp1, mem_sym_stats_t mp2)
! {
! long pscore1 = mem_sym_score (mp1);
! long pscore2 = mem_sym_score (mp2);
!
! if (pscore1 < pscore2)
! return -1;
! else if (pscore1 > pscore2)
! return 1;
! else
! return DECL_UID (mp1->var) - DECL_UID (mp2->var);
! }
!
!
! /* Comparison routine for qsort. The list is sorted by increasing
! partitioning score (PSCORE). This score is computed such that
! symbols with high scores are those that are least likely to be
! partitioned. */
!
! static int
! mp_info_cmp (const void *p, const void *q)
! {
! mem_sym_stats_t e1 = *((const mem_sym_stats_t *) p);
! mem_sym_stats_t e2 = *((const mem_sym_stats_t *) q);
! return compare_mp_info_entries (e1, e2);
! }
!
!
! /* Sort the array of reference counts used to compute memory partitions.
! Elements are sorted in ascending order of execution frequency and
! descending order of virtual operators needed. */
!
! static inline void
! sort_mp_info (VEC(mem_sym_stats_t,heap) *list)
! {
! unsigned num = VEC_length (mem_sym_stats_t, list);
!
! if (num < 2)
! return;
!
! if (num == 2)
! {
! if (compare_mp_info_entries (VEC_index (mem_sym_stats_t, list, 0),
! VEC_index (mem_sym_stats_t, list, 1)) > 0)
! {
! /* Swap elements if they are in the wrong order. */
! mem_sym_stats_t tmp = VEC_index (mem_sym_stats_t, list, 0);
! VEC_replace (mem_sym_stats_t, list, 0,
! VEC_index (mem_sym_stats_t, list, 1));
! VEC_replace (mem_sym_stats_t, list, 1, tmp);
! }
!
! return;
! }
!
! /* There are 3 or more elements, call qsort. */
! qsort (VEC_address (mem_sym_stats_t, list),
! VEC_length (mem_sym_stats_t, list),
! sizeof (mem_sym_stats_t),
! mp_info_cmp);
! }
!
!
! /* Return the memory partition tag (MPT) associated with memory
! symbol SYM. */
!
! static tree
! get_mpt_for (tree sym)
! {
! tree mpt;
!
! /* Don't create a new tag unnecessarily. */
! mpt = memory_partition (sym);
! if (mpt == NULL_TREE)
! {
! mpt = create_tag_raw (MEMORY_PARTITION_TAG, TREE_TYPE (sym), "MPT");
! TREE_ADDRESSABLE (mpt) = 0;
! add_referenced_var (mpt);
! VEC_safe_push (tree, heap, gimple_ssa_operands (cfun)->mpt_table, mpt);
! gcc_assert (MPT_SYMBOLS (mpt) == NULL);
! set_memory_partition (sym, mpt);
! }
!
! return mpt;
! }
!
!
! /* Add MP_P->VAR to a memory partition and return the partition. */
!
! static tree
! find_partition_for (mem_sym_stats_t mp_p)
! {
! unsigned i;
! VEC(tree,heap) *mpt_table;
! tree mpt;
!
! mpt_table = gimple_ssa_operands (cfun)->mpt_table;
! mpt = NULL_TREE;
!
! /* Find an existing partition for MP_P->VAR. */
! for (i = 0; VEC_iterate (tree, mpt_table, i, mpt); i++)
! {
! mem_sym_stats_t mpt_stats;
!
! /* If MPT does not have any symbols yet, use it. */
! if (MPT_SYMBOLS (mpt) == NULL)
! break;
!
! /* Otherwise, see if MPT has common parent tags with MP_P->VAR,
! but avoid grouping clobbered variables with non-clobbered
! variables (otherwise, this tends to creates a single memory
! partition because other call-clobbered variables may have
! common parent tags with non-clobbered ones). */
! mpt_stats = get_mem_sym_stats_for (mpt);
! if (mp_p->parent_tags
! && mpt_stats->parent_tags
! && is_call_clobbered (mpt) == is_call_clobbered (mp_p->var)
! && bitmap_intersect_p (mpt_stats->parent_tags, mp_p->parent_tags))
! break;
!
! /* If no common parent tags are found, see if both MPT and
! MP_P->VAR are call-clobbered. */
! if (is_call_clobbered (mpt) && is_call_clobbered (mp_p->var))
! break;
! }
!
! if (mpt == NULL_TREE)
! mpt = get_mpt_for (mp_p->var);
! else
! set_memory_partition (mp_p->var, mpt);
!
! mp_p->partitioned_p = true;
!
! mark_sym_for_renaming (mp_p->var);
! mark_sym_for_renaming (mpt);
!
! return mpt;
! }
!
!
! /* Rewrite the alias set for TAG to use the newly created partitions.
! If TAG is NULL, rewrite the set of call-clobbered variables.
! NEW_ALIASES is a scratch bitmap to build the new set of aliases for
! TAG. */
!
! static void
! rewrite_alias_set_for (tree tag, bitmap new_aliases)
! {
! bitmap_iterator bi;
! unsigned i;
! tree mpt, sym;
!
! EXECUTE_IF_SET_IN_BITMAP (MTAG_ALIASES (tag), 0, i, bi)
! {
! sym = referenced_var (i);
! mpt = memory_partition (sym);
! if (mpt)
! bitmap_set_bit (new_aliases, DECL_UID (mpt));
! else
! bitmap_set_bit (new_aliases, DECL_UID (sym));
! }
!
! /* Rebuild the may-alias array for TAG. */
! bitmap_copy (MTAG_ALIASES (tag), new_aliases);
! }
!
!
! /* Determine how many virtual operands can be saved by partitioning
! MP_P->VAR into MPT. When a symbol S is thrown inside a partition
! P, every virtual operand that used to reference S will now
! reference P. Whether it reduces the number of virtual operands
! depends on:
!
! 1- Direct references to S are never saved. Instead of the virtual
! operand to S, we will now have a virtual operand to P.
!
! 2- Indirect references to S are reduced only for those memory tags
! holding S that already had other symbols partitioned into P.
! For instance, if a memory tag T has the alias set { a b S c },
! the first time we partition S into P, the alias set will become
! { a b P c }, so no virtual operands will be saved. However, if
! we now partition symbol 'c' into P, then the alias set for T
! will become { a b P }, so we will be saving one virtual operand
! for every indirect reference to 'c'.
!
! 3- Is S is call-clobbered, we save as many virtual operands as
! call/asm sites exist in the code, but only if other
! call-clobbered symbols have been grouped into P. The first
! call-clobbered symbol that we group does not produce any
! savings.
!
! MEM_REF_STATS points to CFUN's memory reference information. */
!
! static void
! estimate_vop_reduction (struct mem_ref_stats_d *mem_ref_stats,
! mem_sym_stats_t mp_p, tree mpt)
! {
! unsigned i;
! bitmap_iterator bi;
! mem_sym_stats_t mpt_stats;
!
! /* We should only get symbols with indirect references here. */
! gcc_assert (mp_p->num_indirect_reads > 0 || mp_p->num_indirect_writes > 0);
!
! /* Note that the only statistics we keep for MPT is the set of
! parent tags to know which memory tags have had alias members
! partitioned, and the indicator has_call_clobbered_vars.
! Reference counts are not important for MPT. */
! mpt_stats = get_mem_sym_stats_for (mpt);
!
! /* Traverse all the parent tags for MP_P->VAR. For every tag T, if
! partition P is already grouping aliases of T, then reduce the
! number of virtual operands by the number of direct references
! to T. */
! if (mp_p->parent_tags)
! {
! if (mpt_stats->parent_tags == NULL)
! mpt_stats->parent_tags = BITMAP_ALLOC (&alias_bitmap_obstack);
!
! EXECUTE_IF_SET_IN_BITMAP (mp_p->parent_tags, 0, i, bi)
! {
! if (bitmap_bit_p (mpt_stats->parent_tags, i))
! {
! /* Partition MPT is already partitioning symbols in the
! alias set for TAG. This means that we are now saving
! 1 virtual operand for every direct reference to TAG. */
! tree tag = referenced_var (i);
! mem_sym_stats_t tag_stats = mem_sym_stats (cfun, tag);
! mem_ref_stats->num_vuses -= tag_stats->num_direct_reads;
! mem_ref_stats->num_vdefs -= tag_stats->num_direct_writes;
! }
! else
! {
! /* This is the first symbol in tag I's alias set that is
! being grouped under MPT. We will not save any
! virtual operands this time, but record that MPT is
! grouping a symbol from TAG's alias set so that the
! next time we get the savings. */
! bitmap_set_bit (mpt_stats->parent_tags, i);
! }
! }
! }
!
! /* If MP_P->VAR is call-clobbered, and MPT is already grouping
! call-clobbered symbols, then we will save as many virtual
! operands as asm/call sites there are. */
! if (is_call_clobbered (mp_p->var))
! {
! if (mpt_stats->has_call_clobbered_vars)
! mem_ref_stats->num_vdefs -= mem_ref_stats->num_call_sites
! + mem_ref_stats->num_asm_sites;
! else
! mpt_stats->has_call_clobbered_vars = true;
! }
! }
!
!
! /* Helper for compute_memory_partitions. Transfer reference counts
! from pointers to their pointed-to sets. Counters for pointers were
! computed by update_alias_info. MEM_REF_STATS points to CFUN's
! memory reference information. */
!
! static void
! update_reference_counts (struct mem_ref_stats_d *mem_ref_stats)
! {
! unsigned i;
! bitmap_iterator bi;
! mem_sym_stats_t sym_stats;
!
! for (i = 1; i < num_ssa_names; i++)
! {
! tree ptr;
! struct ptr_info_def *pi;
!
! ptr = ssa_name (i);
! if (ptr
! && POINTER_TYPE_P (TREE_TYPE (ptr))
! && (pi = SSA_NAME_PTR_INFO (ptr)) != NULL
! && pi->memory_tag_needed)
! {
! unsigned j;
! bitmap_iterator bj;
! tree tag;
! mem_sym_stats_t ptr_stats, tag_stats;
!
! /* If PTR has flow-sensitive points-to information, use
! PTR's name tag, otherwise use the symbol tag associated
! with PTR's symbol. */
! if (pi->name_mem_tag)
! tag = pi->name_mem_tag;
! else
! tag = symbol_mem_tag (SSA_NAME_VAR (ptr));
!
! ptr_stats = get_mem_sym_stats_for (ptr);
! tag_stats = get_mem_sym_stats_for (tag);
!
! /* TAG has as many direct references as dereferences we
! found for its parent pointer. */
! tag_stats->num_direct_reads += ptr_stats->num_direct_reads;
! tag_stats->num_direct_writes += ptr_stats->num_direct_writes;
!
! /* All the dereferences of pointer PTR are considered direct
! references to PTR's memory tag (TAG). In turn,
! references to TAG will become virtual operands for every
! symbol in TAG's alias set. So, for every symbol ALIAS in
! TAG's alias set, add as many indirect references to ALIAS
! as direct references there are for TAG. */
! if (MTAG_ALIASES (tag))
! EXECUTE_IF_SET_IN_BITMAP (MTAG_ALIASES (tag), 0, j, bj)
! {
! tree alias = referenced_var (j);
! sym_stats = get_mem_sym_stats_for (alias);
!
! /* All the direct references to TAG are indirect references
! to ALIAS. */
! sym_stats->num_indirect_reads += ptr_stats->num_direct_reads;
! sym_stats->num_indirect_writes += ptr_stats->num_direct_writes;
! sym_stats->frequency_reads += ptr_stats->frequency_reads;
! sym_stats->frequency_writes += ptr_stats->frequency_writes;
!
! /* Indicate that TAG is one of ALIAS's parent tags. */
! if (sym_stats->parent_tags == NULL)
! sym_stats->parent_tags = BITMAP_ALLOC (&alias_bitmap_obstack);
! bitmap_set_bit (sym_stats->parent_tags, DECL_UID (tag));
! }
! }
! }
!
! /* Call-clobbered symbols are indirectly written at every
! call/asm site. */
! EXECUTE_IF_SET_IN_BITMAP (gimple_call_clobbered_vars (cfun), 0, i, bi)
! {
! tree sym = referenced_var (i);
! sym_stats = get_mem_sym_stats_for (sym);
! sym_stats->num_indirect_writes += mem_ref_stats->num_call_sites
! + mem_ref_stats->num_asm_sites;
! }
!
! /* Addressable symbols are indirectly written at some ASM sites.
! Since only ASM sites that clobber memory actually affect
! addressable symbols, this is an over-estimation. */
! EXECUTE_IF_SET_IN_BITMAP (gimple_addressable_vars (cfun), 0, i, bi)
! {
! tree sym = referenced_var (i);
! sym_stats = get_mem_sym_stats_for (sym);
! sym_stats->num_indirect_writes += mem_ref_stats->num_asm_sites;
! }
! }
!
!
! /* Helper for compute_memory_partitions. Add all memory symbols to
! *MP_INFO_P and compute the initial estimate for the total number of
! virtual operands needed. MEM_REF_STATS points to CFUN's memory
! reference information. On exit, *TAGS_P will contain the list of
! memory tags whose alias set need to be rewritten after
! partitioning. */
!
! static void
! build_mp_info (struct mem_ref_stats_d *mem_ref_stats,
! VEC(mem_sym_stats_t,heap) **mp_info_p,
! VEC(tree,heap) **tags_p)
! {
! tree var;
! referenced_var_iterator rvi;
!
! FOR_EACH_REFERENCED_VAR (var, rvi)
! {
! mem_sym_stats_t sym_stats;
! tree old_mpt;
!
! /* We are only interested in memory symbols other than MPTs. */
! if (is_gimple_reg (var) || TREE_CODE (var) == MEMORY_PARTITION_TAG)
! continue;
!
! /* Collect memory tags into the TAGS array so that we can
! rewrite their alias sets after partitioning. */
! if (MTAG_P (var) && MTAG_ALIASES (var))
! VEC_safe_push (tree, heap, *tags_p, var);
!
! /* Since we are going to re-compute partitions, any symbols that
! used to belong to a partition must be detached from it and
! marked for renaming. */
! if ((old_mpt = memory_partition (var)) != NULL)
! {
! mark_sym_for_renaming (old_mpt);
! set_memory_partition (var, NULL_TREE);
! mark_sym_for_renaming (var);
! }
!
! sym_stats = get_mem_sym_stats_for (var);
!
! /* Add VAR's reference info to MP_INFO. Note that the only
! symbols that make sense to partition are those that have
! indirect references. If a symbol S is always directly
! referenced, partitioning it will not reduce the number of
! virtual operators. The only symbols that are profitable to
! partition are those that belong to alias sets and/or are
! call-clobbered. */
! if (sym_stats->num_indirect_reads > 0
! || sym_stats->num_indirect_writes > 0)
! VEC_safe_push (mem_sym_stats_t, heap, *mp_info_p, sym_stats);
!
! /* Update the number of estimated VOPS. Note that direct
! references to memory tags are always counted as indirect
! references to their alias set members, so if a memory tag has
! aliases, do not count its direct references to avoid double
! accounting. */
! if (!MTAG_P (var) || !MTAG_ALIASES (var))
! {
! mem_ref_stats->num_vuses += sym_stats->num_direct_reads;
! mem_ref_stats->num_vdefs += sym_stats->num_direct_writes;
! }
!
! mem_ref_stats->num_vuses += sym_stats->num_indirect_reads;
! mem_ref_stats->num_vdefs += sym_stats->num_indirect_writes;
! }
! }
!
!
! /* Compute memory partitions. A memory partition (MPT) is an
! arbitrary grouping of memory symbols, such that references to one
! member of the group is considered a reference to all the members of
! the group.
!
! As opposed to alias sets in memory tags, the grouping into
! partitions is completely arbitrary and only done to reduce the
! number of virtual operands. The only rule that needs to be
! observed when creating memory partitions is that given two memory
! partitions MPT.i and MPT.j, they must not contain symbols in
! common.
!
! Memory partitions are used when putting the program into Memory-SSA
! form. In particular, in Memory-SSA PHI nodes are not computed for
! individual memory symbols. They are computed for memory
! partitions. This reduces the amount of PHI nodes in the SSA graph
! at the expense of precision (i.e., it makes unrelated stores affect
! each other).
!
! However, it is possible to increase precision by changing this
! partitioning scheme. For instance, if the partitioning scheme is
! such that get_mpt_for is the identity function (that is,
! get_mpt_for (s) = s), this will result in ultimate precision at the
! expense of huge SSA webs.
!
! At the other extreme, a partitioning scheme that groups all the
! symbols in the same set results in minimal SSA webs and almost
! total loss of precision.
!
! There partitioning heuristic uses three parameters to decide the
! order in which symbols are processed. The list of symbols is
! sorted so that symbols that are more likely to be partitioned are
! near the top of the list:
!
! - Execution frequency. If a memory references is in a frequently
! executed code path, grouping it into a partition may block useful
! transformations and cause sub-optimal code generation. So, the
! partition heuristic tries to avoid grouping symbols with high
! execution frequency scores. Execution frequency is taken
! directly from the basic blocks where every reference is made (see
! update_mem_sym_stats_from_stmt), which in turn uses the
! profile guided machinery, so if the program is compiled with PGO
! enabled, more accurate partitioning decisions will be made.
!
! - Number of references. Symbols with few references in the code,
! are partitioned before symbols with many references.
!
! - NO_ALIAS attributes. Symbols with any of the NO_ALIAS*
! attributes are partitioned after symbols marked MAY_ALIAS.
!
! Once the list is sorted, the partitioning proceeds as follows:
!
! 1- For every symbol S in MP_INFO, create a new memory partition MP,
! if necessary. To avoid memory partitions that contain symbols
! from non-conflicting alias sets, memory partitions are
! associated to the memory tag that holds S in its alias set. So,
! when looking for a memory partition for S, the memory partition
! associated with one of the memory tags holding S is chosen. If
! none exists, a new one is created.
!
! 2- Add S to memory partition MP.
!
! 3- Reduce by 1 the number of VOPS for every memory tag holding S.
!
! 4- If the total number of VOPS is less than MAX_ALIASED_VOPS or the
! average number of VOPS per statement is less than
! AVG_ALIASED_VOPS, stop. Otherwise, go to the next symbol in the
! list. */
!
! static void
! compute_memory_partitions (void)
! {
! tree tag;
! unsigned i;
! mem_sym_stats_t mp_p;
! VEC(mem_sym_stats_t,heap) *mp_info;
! bitmap new_aliases;
! VEC(tree,heap) *tags;
! struct mem_ref_stats_d *mem_ref_stats;
! int prev_max_aliased_vops;
!
! mem_ref_stats = gimple_mem_ref_stats (cfun);
! gcc_assert (mem_ref_stats->num_vuses == 0 && mem_ref_stats->num_vdefs == 0);
!
! if (mem_ref_stats->num_mem_stmts == 0)
! return;
!
! timevar_push (TV_MEMORY_PARTITIONING);
!
! mp_info = NULL;
! tags = NULL;
! prev_max_aliased_vops = MAX_ALIASED_VOPS;
!
! /* Since we clearly cannot lower the number of virtual operators
! below the total number of memory statements in the function, we
! may need to adjust MAX_ALIASED_VOPS beforehand. */
! if (MAX_ALIASED_VOPS < mem_ref_stats->num_mem_stmts)
! MAX_ALIASED_VOPS = mem_ref_stats->num_mem_stmts;
!
! /* Update reference stats for all the pointed-to variables and
! memory tags. */
! update_reference_counts (mem_ref_stats);
!
! /* Add all the memory symbols to MP_INFO. */
! build_mp_info (mem_ref_stats, &mp_info, &tags);
!
! /* No partitions required if we are below the threshold. */
! if (!need_to_partition_p (mem_ref_stats))
! {
! if (dump_file)
! fprintf (dump_file, "\nMemory partitioning NOT NEEDED for %s\n",
! get_name (current_function_decl));
! goto done;
! }
!
! /* Sort the MP_INFO array so that symbols that should be partitioned
! first are near the top of the list. */
! sort_mp_info (mp_info);
!
! if (dump_file)
! {
! fprintf (dump_file, "\nMemory partitioning NEEDED for %s\n\n",
! get_name (current_function_decl));
! fprintf (dump_file, "Memory symbol references before partitioning:\n");
! dump_mp_info (dump_file, mp_info);
! }
!
! /* Create partitions for variables in MP_INFO until we have enough
! to lower the total number of VOPS below MAX_ALIASED_VOPS or if
! the average number of VOPS per statement is below
! AVG_ALIASED_VOPS. */
! for (i = 0; VEC_iterate (mem_sym_stats_t, mp_info, i, mp_p); i++)
! {
! tree mpt;
!
! /* If we are below the threshold, stop. */
! if (!need_to_partition_p (mem_ref_stats))
! break;
!
! mpt = find_partition_for (mp_p);
! estimate_vop_reduction (mem_ref_stats, mp_p, mpt);
! }
!
! /* After partitions have been created, rewrite alias sets to use
! them instead of the original symbols. This way, if the alias set
! was computed as { a b c d e f }, and the subset { b e f } was
! grouped into partition MPT.3, then the new alias set for the tag
! will be { a c d MPT.3 }.
!
! Note that this is not strictly necessary. The operand scanner
! will always check if a symbol belongs to a partition when adding
! virtual operands. However, by reducing the size of the alias
! sets to be scanned, the work needed inside the operand scanner is
! significantly reduced. */
! new_aliases = BITMAP_ALLOC (&alias_bitmap_obstack);
!
! for (i = 0; VEC_iterate (tree, tags, i, tag); i++)
! {
! rewrite_alias_set_for (tag, new_aliases);
! bitmap_clear (new_aliases);
! }
!
! BITMAP_FREE (new_aliases);
!
! if (dump_file)
! {
! fprintf (dump_file, "\nMemory symbol references after partitioning:\n");
! dump_mp_info (dump_file, mp_info);
! }
!
! done:
! /* Free allocated memory. */
! VEC_free (mem_sym_stats_t, heap, mp_info);
! VEC_free (tree, heap, tags);
!
! MAX_ALIASED_VOPS = prev_max_aliased_vops;
!
! timevar_pop (TV_MEMORY_PARTITIONING);
! }
!
! /* 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)
! {
! struct alias_info *ai;
!
! timevar_push (TV_TREE_MAY_ALIAS);
!
! memset (&alias_stats, 0, sizeof (alias_stats));
!
! /* Initialize aliasing information. */
! ai = init_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 ();
!
! /* Update various related attributes like escaped addresses,
! pointer dereferences for loads and stores. This is used
! when creating name tags and alias sets. */
! update_alias_info (ai);
!
! /* Collect all pointers and addressable variables, compute alias sets,
! create memory tags for pointers and promote variables whose address is
! not needed anymore. */
! setup_pointers_and_addressables (ai);
!
! /* Compute type-based flow-insensitive aliasing for all the type
! memory tags. */
! compute_flow_insensitive_aliasing (ai);
!
! /* Compute flow-sensitive, points-to based aliasing for all the name
! memory tags. */
! compute_flow_sensitive_aliasing (ai);
!
! /* Compute call clobbering information. */
! compute_call_clobbered (ai);
!
! /* If the program makes no reference to global variables, but it
! contains a mixture of pure and non-pure functions, then we need
! to create use-def and def-def links between these functions to
! avoid invalid transformations on them. */
! maybe_create_global_var ();
!
! /* Compute memory partitions for every memory variable. */
! compute_memory_partitions ();
!
! /* Remove partitions with no symbols. Partitions may end up with an
! empty MPT_SYMBOLS set if a previous round of alias analysis
! needed to partition more symbols. Since we don't need those
! partitions anymore, remove them to free up the space. */
! {
! tree mpt;
! unsigned i;
! VEC(tree,heap) *mpt_table;
!
! mpt_table = gimple_ssa_operands (cfun)->mpt_table;
! i = 0;
! while (i < VEC_length (tree, mpt_table))
! {
! mpt = VEC_index (tree, mpt_table, i);
! if (MPT_SYMBOLS (mpt) == NULL)
! VEC_unordered_remove (tree, mpt_table, i);
! else
! i++;
! }
! }
!
! /* Populate all virtual operands and newly promoted register operands. */
! {
! gimple_stmt_iterator gsi;
! basic_block bb;
! FOR_EACH_BB (bb)
! for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
! update_stmt_if_modified (gsi_stmt (gsi));
! }
!
! /* Debugging dumps. */
! if (dump_file)
! {
! dump_mem_ref_stats (dump_file);
! dump_alias_info (dump_file);
! dump_points_to_info (dump_file);
!
! if (dump_flags & TDF_STATS)
! dump_alias_stats (dump_file);
!
! if (dump_flags & TDF_DETAILS)
! dump_referenced_vars (dump_file);
! }
!
! /* Report strict aliasing violations. */
! strict_aliasing_warning_backend ();
!
! /* Deallocate memory used by aliasing data structures. */
! delete_alias_info (ai);
!
! if (need_ssa_update_p ())
! update_ssa (TODO_update_ssa);
!
! 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);
! }
!
! /* Remove memory references stats for function FN. */
!
! void
! delete_mem_ref_stats (struct function *fn)
! {
! if (gimple_mem_ref_stats (fn)->mem_sym_stats)
! {
! free_alloc_pool (mem_sym_stats_pool);
! pointer_map_destroy (gimple_mem_ref_stats (fn)->mem_sym_stats);
! }
! gimple_mem_ref_stats (fn)->mem_sym_stats = NULL;
! }
!
!
! /* Initialize memory reference stats. */
!
! static void
! init_mem_ref_stats (void)
! {
! struct mem_ref_stats_d *mem_ref_stats = gimple_mem_ref_stats (cfun);
!
! mem_sym_stats_pool = create_alloc_pool ("Mem sym stats",
! sizeof (struct mem_sym_stats_d),
! 100);
! memset (mem_ref_stats, 0, sizeof (struct mem_ref_stats_d));
! mem_ref_stats->mem_sym_stats = pointer_map_create ();
! }
!
!
! /* Helper for init_alias_info. Reset existing aliasing information. */
!
! static void
! reset_alias_info (void)
! {
! referenced_var_iterator rvi;
! tree var;
! unsigned i;
! bitmap active_nmts, all_nmts;
!
! /* Clear the set of addressable variables. We do not need to clear
! the TREE_ADDRESSABLE bit on every symbol because we are going to
! re-compute addressability here. */
! bitmap_clear (gimple_addressable_vars (cfun));
!
! active_nmts = BITMAP_ALLOC (&alias_bitmap_obstack);
! all_nmts = BITMAP_ALLOC (&alias_bitmap_obstack);
!
! /* Clear flow-insensitive alias information from each symbol. */
! FOR_EACH_REFERENCED_VAR (var, rvi)
! {
! if (is_gimple_reg (var))
! continue;
!
! if (MTAG_P (var))
! MTAG_ALIASES (var) = NULL;
!
! /* Memory partition information will be computed from scratch. */
! if (TREE_CODE (var) == MEMORY_PARTITION_TAG)
! MPT_SYMBOLS (var) = NULL;
!
! /* Collect all the name tags to determine if we have any
! orphaned that need to be removed from the IL. A name tag
! will be orphaned if it is not associated with any active SSA
! name. */
! if (TREE_CODE (var) == NAME_MEMORY_TAG)
! bitmap_set_bit (all_nmts, DECL_UID (var));
!
! /* Since we are about to re-discover call-clobbered
! variables, clear the call-clobbered flag. */
! 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 flow-sensitive 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 but keep the name tag to
! avoid creating new temporaries unnecessarily. If
! this pointer is found to point to a subset or
! superset of its former points-to set, then a new
! tag will need to be created in create_name_tags. */
! pi->pt_anything = 0;
! pi->pt_null = 0;
! pi->value_escapes_p = 0;
! pi->memory_tag_needed = 0;
! pi->is_dereferenced = 0;
! if (pi->pt_vars)
! bitmap_clear (pi->pt_vars);
!
! /* Add NAME's name tag to the set of active tags. */
! if (pi->name_mem_tag)
! bitmap_set_bit (active_nmts, DECL_UID (pi->name_mem_tag));
! }
}
! /* Name memory tags that are no longer associated with an SSA name
! are considered stale and should be removed from the IL. All the
! name tags that are in the set ALL_NMTS but not in ACTIVE_NMTS are
! considered stale and marked for renaming. */
! bitmap_and_compl_into (all_nmts, active_nmts);
! mark_set_for_renaming (all_nmts);
!
! BITMAP_FREE (all_nmts);
! BITMAP_FREE (active_nmts);
! }
!
!
! /* Initialize the data structures used for alias analysis. */
!
! static struct alias_info *
! init_alias_info (void)
! {
! struct alias_info *ai;
! referenced_var_iterator rvi;
! tree var;
! static bool alias_bitmap_obstack_initialized;
!
! ai = XCNEW (struct alias_info);
! ai->ssa_names_visited = sbitmap_alloc (num_ssa_names);
! sbitmap_zero (ai->ssa_names_visited);
! ai->processed_ptrs = VEC_alloc (tree, heap, 50);
! ai->dereferenced_ptrs = pointer_set_create ();
!
! /* Clear out all memory reference stats. */
! init_mem_ref_stats ();
!
! /* If aliases have been computed before, clear existing information. */
! if (gimple_aliases_computed_p (cfun))
! reset_alias_info ();
! else
! {
! /* If this is the first time we compute aliasing information,
! every non-register symbol will need to be put into SSA form
! (the initial SSA form only operates on GIMPLE registers). */
! FOR_EACH_REFERENCED_VAR (var, rvi)
! if (!is_gimple_reg (var))
! mark_sym_for_renaming (var);
! }
!
! /* Next time, we will need to reset alias information. */
! cfun->gimple_df->aliases_computed_p = true;
! if (alias_bitmap_obstack_initialized)
! bitmap_obstack_release (&alias_bitmap_obstack);
! bitmap_obstack_initialize (&alias_bitmap_obstack);
! alias_bitmap_obstack_initialized = true;
!
! return ai;
! }
!
!
! /* Deallocate memory used by alias analysis. */
!
! static void
! delete_alias_info (struct alias_info *ai)
! {
! size_t i;
!
! sbitmap_free (ai->ssa_names_visited);
!
! VEC_free (tree, heap, ai->processed_ptrs);
!
! for (i = 0; i < ai->num_addressable_vars; i++)
! free (ai->addressable_vars[i]);
! free (ai->addressable_vars);
!
! for (i = 0; i < ai->num_pointers; i++)
! free (ai->pointers[i]);
! free (ai->pointers);
!
! pointer_set_destroy (ai->dereferenced_ptrs);
! free (ai);
! delete_mem_ref_stats (cfun);
delete_points_to_sets ();
- }
-
-
- /* Used for hashing to identify pointer infos with identical
- pt_vars bitmaps. */
-
- static int
- eq_ptr_info (const void *p1, const void *p2)
- {
- const struct ptr_info_def *n1 = (const struct ptr_info_def *) p1;
- const struct ptr_info_def *n2 = (const struct ptr_info_def *) p2;
- return bitmap_equal_p (n1->pt_vars, n2->pt_vars);
- }
-
- static hashval_t
- ptr_info_hash (const void *p)
- {
- const struct ptr_info_def *n = (const struct ptr_info_def *) p;
- return bitmap_hash (n->pt_vars);
- }
-
-
- /* Create name tags for all the pointers that have been dereferenced.
- We only create a name tag for a pointer P if P is found to point to
- a set of variables (so that we can alias them to *P) or if it is
- the result of a call to malloc (which means that P cannot point to
- anything else nor alias any other variable).
-
- If two pointers P and Q point to the same set of variables, they
- are assigned the same name tag. */
-
- static void
- create_name_tags (void)
- {
- size_t i;
- VEC (tree, heap) *with_ptvars = NULL;
- tree ptr;
- htab_t ptr_hash;
-
- /* Collect the list of pointers with a non-empty points to set. */
- for (i = 1; i < num_ssa_names; i++)
- {
- tree ptr = ssa_name (i);
- struct ptr_info_def *pi;
-
- if (!ptr
- || !POINTER_TYPE_P (TREE_TYPE (ptr))
- || !SSA_NAME_PTR_INFO (ptr))
- continue;
-
- pi = SSA_NAME_PTR_INFO (ptr);
-
- if (pi->pt_anything || !pi->memory_tag_needed)
- {
- /* No name tags for pointers that have not been
- dereferenced or point to an arbitrary location. */
- pi->name_mem_tag = NULL_TREE;
- continue;
- }
-
- /* Set pt_anything on the pointers without pt_vars filled in so
- that they are assigned a symbol tag. */
- if (pi->pt_vars && !bitmap_empty_p (pi->pt_vars))
- VEC_safe_push (tree, heap, with_ptvars, ptr);
- else
- set_pt_anything (ptr);
- }
-
- /* If we didn't find any pointers with pt_vars set, we're done. */
- if (!with_ptvars)
- return;
-
- ptr_hash = htab_create (10, ptr_info_hash, eq_ptr_info, NULL);
-
- /* Now go through the pointers with pt_vars, and find a name tag
- with the same pt_vars as this pointer, or create one if one
- doesn't exist. */
- for (i = 0; VEC_iterate (tree, with_ptvars, i, ptr); i++)
- {
- struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
- tree old_name_tag = pi->name_mem_tag;
- struct ptr_info_def **slot;
-
- /* If PTR points to a set of variables, check if we don't
- have another pointer Q with the same points-to set before
- creating a tag. If so, use Q's tag instead of creating a
- new one.
-
- This is important for not creating unnecessary symbols
- and also for copy propagation. If we ever need to
- propagate PTR into Q or vice-versa, we would run into
- problems if they both had different name tags because
- they would have different SSA version numbers (which
- would force us to take the name tags in and out of SSA). */
- slot = (struct ptr_info_def **) htab_find_slot (ptr_hash, pi, INSERT);
- if (*slot)
- pi->name_mem_tag = (*slot)->name_mem_tag;
- else
- {
- *slot = pi;
-
- /* If we didn't find a pointer with the same points-to set
- as PTR, create a new name tag if needed. */
- if (pi->name_mem_tag == NULL_TREE)
- pi->name_mem_tag = get_nmt_for (ptr);
- }
-
- /* If the new name tag computed for PTR is different than
- the old name tag that it used to have, then the old tag
- needs to be removed from the IL, so we mark it for
- renaming. */
- if (old_name_tag && old_name_tag != pi->name_mem_tag)
- mark_sym_for_renaming (old_name_tag);
-
- /* Inherit volatility from the pointed-to type. */
- TREE_THIS_VOLATILE (pi->name_mem_tag)
- |= TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (ptr)));
-
- /* Mark the new name tag for renaming. */
- mark_sym_for_renaming (pi->name_mem_tag);
- }
-
- htab_delete (ptr_hash);
-
- VEC_free (tree, heap, with_ptvars);
- }
-
! /* Union the alias set SET into the may-aliases for TAG. */
! static void
! union_alias_set_into (tree tag, bitmap set)
! {
! bitmap ma = MTAG_ALIASES (tag);
!
! if (bitmap_empty_p (set))
! return;
! if (!ma)
! ma = MTAG_ALIASES (tag) = BITMAP_ALLOC (&alias_bitmap_obstack);
! bitmap_ior_into (ma, set);
}
!
! /* For every pointer P_i in AI->PROCESSED_PTRS, create may-alias sets for
! the name memory tag (NMT) associated with P_i. If P_i escapes, then its
! name tag and the variables it points-to are call-clobbered. Finally, if
! P_i escapes and we could not determine where it points to, then all the
! variables in the same alias set as *P_i are marked call-clobbered. This
! is necessary because we must assume that P_i may take the address of any
! variable in the same alias set. */
!
! static void
! compute_flow_sensitive_aliasing (struct alias_info *ai)
{
- size_t i;
tree ptr;
!
! timevar_push (TV_FLOW_SENSITIVE);
!
! for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
! {
! if (!find_what_p_points_to (ptr))
! set_pt_anything (ptr);
! }
!
! create_name_tags ();
!
! for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
! {
! struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
!
! /* Set up aliasing information for PTR's name memory tag (if it has
! one). Note that only pointers that have been dereferenced will
! have a name memory tag. */
! if (pi->name_mem_tag && pi->pt_vars)
! {
! if (!bitmap_empty_p (pi->pt_vars))
! union_alias_set_into (pi->name_mem_tag, pi->pt_vars);
! }
! }
! timevar_pop (TV_FLOW_SENSITIVE);
! }
!
!
! /* Return TRUE if at least one symbol in TAG2's alias set is also
! present in TAG1's alias set. */
!
! static bool
! have_common_aliases_p (bitmap tag1aliases, bitmap tag2aliases)
! {
!
! /* This is the old behavior of have_common_aliases_p, which is to
! return false if both sets are empty, or one set is and the other
! isn't. */
! if (tag1aliases == NULL || tag2aliases == NULL)
! return false;
- return bitmap_intersect_p (tag1aliases, tag2aliases);
- }
! /* Compute type-based alias sets. Traverse all the pointers and
! addressable variables found in setup_pointers_and_addressables.
!
! For every pointer P in AI->POINTERS and addressable variable V in
! AI->ADDRESSABLE_VARS, add V to the may-alias sets of P's symbol
! memory tag (SMT) if their alias sets conflict. V is then marked as
! an aliased symbol so that the operand scanner knows that statements
! containing V have aliased operands. */
! static void
! compute_flow_insensitive_aliasing (struct alias_info *ai)
{
! referenced_var_iterator rvi;
! tree var;
! size_t i;
!
! timevar_push (TV_FLOW_INSENSITIVE);
! /* For every pointer P, determine which addressable variables may alias
! with P's symbol memory tag. */
! for (i = 0; i < ai->num_pointers; i++)
! {
! size_t j;
! struct alias_map_d *p_map = ai->pointers[i];
! tree tag = symbol_mem_tag (p_map->var);
! tree var;
!
! for (j = 0; j < ai->num_addressable_vars; j++)
! {
! struct alias_map_d *v_map;
! var_ann_t v_ann;
!
! v_map = ai->addressable_vars[j];
! var = v_map->var;
! v_ann = var_ann (var);
!
! /* We used to skip variables that have never been written to
! if the memory tag has been never written to directly (or
! either of them were call clobbered). This is not enough
! though, as this misses writes through the tags aliases.
! So, for correctness we need to include any aliased
! variable here. */
!
! if (may_alias_p (p_map->var, p_map->set, var, v_map->set, false))
! {
! /* Add VAR to TAG's may-aliases set. */
! add_may_alias (tag, var);
! }
! }
! }
!
! /* Since this analysis is based exclusively on symbols, it fails to
! handle cases where two pointers P and Q have different memory
! tags with conflicting alias set numbers but no aliased symbols in
! common.
!
! For example, suppose that we have two memory tags SMT.1 and SMT.2
! such that
!
! may-aliases (SMT.1) = { a }
! may-aliases (SMT.2) = { b }
!
! and the alias set number of SMT.1 conflicts with that of SMT.2.
! Since they don't have symbols in common, loads and stores from
! SMT.1 and SMT.2 will seem independent of each other, which will
! lead to the optimizers making invalid transformations (see
! testsuite/gcc.c-torture/execute/pr15262-[12].c).
!
! To avoid this problem, we do a final traversal of AI->POINTERS
! looking for pairs of pointers that have no aliased symbols in
! common and yet have conflicting alias set numbers. */
! for (i = 0; i < ai->num_pointers; i++)
! {
! size_t j;
! struct alias_map_d *p_map1 = ai->pointers[i];
! tree tag1 = symbol_mem_tag (p_map1->var);
! bitmap may_aliases1 = MTAG_ALIASES (tag1);
!
! for (j = 0; j < ai->num_pointers; j++)
! {
! struct alias_map_d *p_map2 = ai->pointers[j];
! tree tag2 = symbol_mem_tag (p_map2->var);
! bitmap may_aliases2 = may_aliases (tag2);
!
! /* By convention tags don't alias themselves. */
! if (tag1 == tag2)
! continue;
!
! /* If the pointers may not point to each other, do nothing. */
! if (!may_alias_p (p_map1->var, p_map1->set, tag2, p_map2->set, true))
! continue;
!
! /* The two pointers may alias each other. If they already have
! symbols in common, do nothing. */
! if (have_common_aliases_p (may_aliases1, may_aliases2))
! continue;
! add_may_alias (tag1, tag2);
! }
}
! /* We have to add all HEAP variables to all SMTs aliases bitmaps.
! As we don't know which effective type the HEAP will have we cannot
! do better here and we need the conflicts with obfuscated pointers
! (a simple (*(int[n] *)ptr)[i] will do, with ptr from a VLA array
! allocation). */
! for (i = 0; i < ai->num_pointers; i++)
{
! struct alias_map_d *p_map = ai->pointers[i];
! tree tag = symbol_mem_tag (p_map->var);
!
! FOR_EACH_REFERENCED_VAR (var, rvi)
! {
! if (var_ann (var)->is_heapvar)
! add_may_alias (tag, var);
! }
}
! timevar_pop (TV_FLOW_INSENSITIVE);
! }
!
!
! /* Create a new alias set entry for VAR in AI->ADDRESSABLE_VARS. */
!
! static void
! create_alias_map_for (tree var, struct alias_info *ai)
! {
! struct alias_map_d *alias_map;
! alias_map = XCNEW (struct alias_map_d);
! alias_map->var = var;
! alias_map->set = get_alias_set (var);
! ai->addressable_vars[ai->num_addressable_vars++] = alias_map;
}
! /* Update related alias information kept in AI. This is used when
! building name tags, alias sets and deciding grouping heuristics.
! STMT is the statement to process. This function also updates
! ADDRESSABLE_VARS. */
! static void
! update_alias_info_1 (gimple stmt, struct alias_info *ai)
{
! bitmap addr_taken;
! use_operand_p use_p;
! ssa_op_iter iter;
! bool stmt_dereferences_ptr_p;
! enum escape_type stmt_escape_type = is_escape_site (stmt);
! struct mem_ref_stats_d *mem_ref_stats = gimple_mem_ref_stats (cfun);
!
! stmt_dereferences_ptr_p = false;
!
! if (stmt_escape_type == ESCAPE_TO_CALL
! || stmt_escape_type == ESCAPE_TO_PURE_CONST)
! {
! mem_ref_stats->num_call_sites++;
! if (stmt_escape_type == ESCAPE_TO_PURE_CONST)
! mem_ref_stats->num_pure_const_call_sites++;
! }
! else if (stmt_escape_type == ESCAPE_TO_ASM)
! mem_ref_stats->num_asm_sites++;
!
! /* Mark all the variables whose address are taken by the statement. */
! addr_taken = gimple_addresses_taken (stmt);
! if (addr_taken)
! bitmap_ior_into (gimple_addressable_vars (cfun), addr_taken);
!
! /* Process each operand use. For pointers, determine whether they
! are dereferenced by the statement, or whether their value
! escapes, etc. */
! FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
! {
! tree op, var;
! var_ann_t v_ann;
! struct ptr_info_def *pi;
! unsigned num_uses, num_loads, num_stores;
!
! op = USE_FROM_PTR (use_p);
!
! /* If STMT is a PHI node, OP may be an ADDR_EXPR. If so, add it
! to the set of addressable variables. */
! if (TREE_CODE (op) == ADDR_EXPR)
! {
! bitmap addressable_vars = gimple_addressable_vars (cfun);
!
! gcc_assert (gimple_code (stmt) == GIMPLE_PHI);
! gcc_assert (addressable_vars);
!
! /* PHI nodes don't have annotations for pinning the set
! of addresses taken, so we collect them here.
!
! FIXME, should we allow PHI nodes to have annotations
! so that they can be treated like regular statements?
! Currently, they are treated as second-class
! statements. */
! add_to_addressable_set (TREE_OPERAND (op, 0), &addressable_vars);
! continue;
! }
!
! /* Ignore constants (they may occur in PHI node arguments). */
! if (TREE_CODE (op) != SSA_NAME)
! continue;
!
! var = SSA_NAME_VAR (op);
! v_ann = var_ann (var);
!
! /* The base variable of an SSA name must be a GIMPLE register, and thus
! it cannot be aliased. */
! gcc_assert (!may_be_aliased (var));
!
! /* We are only interested in pointers. */
! if (!POINTER_TYPE_P (TREE_TYPE (op)))
! continue;
!
! pi = get_ptr_info (op);
!
! /* Add OP to AI->PROCESSED_PTRS, if it's not there already. */
! if (!TEST_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (op)))
! {
! SET_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (op));
! VEC_safe_push (tree, heap, ai->processed_ptrs, op);
! }
!
! /* If STMT is a PHI node, then it will not have pointer
! dereferences and it will not be an escape point. */
! if (gimple_code (stmt) == GIMPLE_PHI)
! continue;
!
! /* Determine whether OP is a dereferenced pointer, and if STMT
! is an escape point, whether OP escapes. */
! count_uses_and_derefs (op, stmt, &num_uses, &num_loads, &num_stores);
!
! /* For directly dereferenced pointers we can apply
! TBAA-pruning to their points-to set. We may not count the
! implicit dereferences &PTR->FLD here. */
! if (num_loads + num_stores > 0)
! pi->is_dereferenced = 1;
!
! /* Handle a corner case involving address expressions of the
! form '&PTR->FLD'. The problem with these expressions is that
! they do not represent a dereference of PTR. However, if some
! other transformation propagates them into an INDIRECT_REF
! expression, we end up with '*(&PTR->FLD)' which is folded
! into 'PTR->FLD'.
!
! So, if the original code had no other dereferences of PTR,
! the aliaser will not create memory tags for it, and when
! &PTR->FLD gets propagated to INDIRECT_REF expressions, the
! memory operations will receive no VDEF/VUSE operands.
!
! One solution would be to have count_uses_and_derefs consider
! &PTR->FLD a dereference of PTR. But that is wrong, since it
! is not really a dereference but an offset calculation.
!
! What we do here is to recognize these special ADDR_EXPR
! nodes. Since these expressions are never GIMPLE values (they
! are not GIMPLE invariants), they can only appear on the RHS
! of an assignment and their base address is always an
! INDIRECT_REF expression. */
! if (is_gimple_assign (stmt)
! && gimple_assign_rhs_code (stmt) == ADDR_EXPR
! && !is_gimple_val (gimple_assign_rhs1 (stmt)))
! {
! /* If the RHS if of the form &PTR->FLD and PTR == OP, then
! this represents a potential dereference of PTR. */
! tree rhs = gimple_assign_rhs1 (stmt);
! tree base = get_base_address (TREE_OPERAND (rhs, 0));
! if (TREE_CODE (base) == INDIRECT_REF
! && TREE_OPERAND (base, 0) == op)
! num_loads++;
! }
!
! if (num_loads + num_stores > 0)
! {
! /* Mark OP as dereferenced. In a subsequent pass,
! dereferenced pointers that point to a set of
! variables will be assigned a name tag to alias
! all the variables OP points to. */
! pi->memory_tag_needed = 1;
!
! /* ??? For always executed direct dereferences we can
! apply TBAA-pruning to their escape set. */
!
! /* Mark OP as being dereferenced. */
! pointer_set_insert (ai->dereferenced_ptrs, var);
!
! /* Update the frequency estimate for all the dereferences of
! pointer OP. */
! update_mem_sym_stats_from_stmt (op, stmt, num_loads, num_stores);
!
! /* Indicate that STMT contains pointer dereferences. */
! stmt_dereferences_ptr_p = true;
! }
!
! if (stmt_escape_type != NO_ESCAPE && num_loads + num_stores < num_uses)
! {
! /* If STMT is an escape point and STMT contains at
! least one direct use of OP, then the value of OP
! escapes and so the pointed-to variables need to
! be marked call-clobbered. */
! pi->value_escapes_p = 1;
! pi->escape_mask |= stmt_escape_type;
!
! /* If the statement makes a function call, assume
! that pointer OP will be dereferenced in a store
! operation inside the called function. */
! if (is_gimple_call (stmt)
! || stmt_escape_type == ESCAPE_STORED_IN_GLOBAL)
! {
! pointer_set_insert (ai->dereferenced_ptrs, var);
! pi->memory_tag_needed = 1;
! }
! }
! }
!
! if (gimple_code (stmt) == GIMPLE_PHI)
! return;
!
! /* Mark stored variables in STMT as being written to and update the
! memory reference stats for all memory symbols referenced by STMT. */
! if (gimple_references_memory_p (stmt))
! {
! unsigned i;
! bitmap_iterator bi;
!
! mem_ref_stats->num_mem_stmts++;
!
! /* Notice that we only update memory reference stats for symbols
! loaded and stored by the statement if the statement does not
! contain pointer dereferences and it is not a call/asm site.
! This is to avoid double accounting problems when creating
! memory partitions. After computing points-to information,
! pointer dereference statistics are used to update the
! reference stats of the pointed-to variables, so here we
! should only update direct references to symbols.
!
! Indirect references are not updated here for two reasons: (1)
! The first time we compute alias information, the sets
! LOADED/STORED are empty for pointer dereferences, (2) After
! partitioning, LOADED/STORED may have references to
! partitions, not the original pointed-to variables. So, if we
! always counted LOADED/STORED here and during partitioning, we
! would count many symbols more than once.
!
! This does cause some imprecision when a statement has a
! combination of direct symbol references and pointer
! dereferences (e.g., MEMORY_VAR = *PTR) or if a call site has
! memory symbols in its argument list, but these cases do not
! occur so frequently as to constitute a serious problem. */
! if (!stmt_dereferences_ptr_p
! && stmt_escape_type != ESCAPE_TO_CALL
! && stmt_escape_type != ESCAPE_TO_PURE_CONST
! && stmt_escape_type != ESCAPE_TO_ASM)
! {
! if (gimple_stored_syms (stmt))
! EXECUTE_IF_SET_IN_BITMAP (gimple_stored_syms (stmt), 0, i, bi)
! update_mem_sym_stats_from_stmt (referenced_var (i), stmt, 0, 1);
!
! if (gimple_loaded_syms (stmt))
! EXECUTE_IF_SET_IN_BITMAP (gimple_loaded_syms (stmt), 0, i, bi)
! update_mem_sym_stats_from_stmt (referenced_var (i), stmt, 1, 0);
! }
! }
! }
! /* Update various related attributes like escaped addresses,
! pointer dereferences for loads and stores. This is used
! when creating name tags and alias sets. */
! static void
! update_alias_info (struct alias_info *ai)
! {
! basic_block bb;
! FOR_EACH_BB (bb)
{
! gimple_stmt_iterator gsi;
! gimple phi;
! for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
! {
! phi = gsi_stmt (gsi);
! if (is_gimple_reg (PHI_RESULT (phi)))
! update_alias_info_1 (phi, ai);
! }
! for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
! update_alias_info_1 (gsi_stmt (gsi), ai);
}
}
! /* Create memory tags for all the dereferenced pointers and build the
! ADDRESSABLE_VARS and POINTERS arrays used for building the may-alias
! sets. Based on the address escape and points-to information collected
! earlier, this pass will also clear the TREE_ADDRESSABLE flag from those
! variables whose address is not needed anymore. */
static void
! setup_pointers_and_addressables (struct alias_info *ai)
{
- size_t num_addressable_vars, num_pointers;
referenced_var_iterator rvi;
tree var;
! VEC (tree, heap) *varvec = NULL;
! safe_referenced_var_iterator srvi;
! /* Size up the arrays ADDRESSABLE_VARS and POINTERS. */
! num_addressable_vars = num_pointers = 0;
!
FOR_EACH_REFERENCED_VAR (var, rvi)
{
! if (may_be_aliased (var))
! num_addressable_vars++;
!
! if (POINTER_TYPE_P (TREE_TYPE (var)))
! {
! /* Since we don't keep track of volatile variables, assume that
! these pointers are used in indirect store operations. */
! if (TREE_THIS_VOLATILE (var))
! pointer_set_insert (ai->dereferenced_ptrs, var);
! num_pointers++;
! }
}
! /* Create ADDRESSABLE_VARS and POINTERS. Note that these arrays are
! always going to be slightly bigger than we actually need them
! because some TREE_ADDRESSABLE variables will be marked
! non-addressable below and only pointers with unique symbol tags are
! going to be added to POINTERS. */
! ai->addressable_vars = XCNEWVEC (struct alias_map_d *, num_addressable_vars);
! ai->pointers = XCNEWVEC (struct alias_map_d *, num_pointers);
! ai->num_addressable_vars = 0;
! ai->num_pointers = 0;
!
! FOR_EACH_REFERENCED_VAR_SAFE (var, varvec, srvi)
! {
! /* Name memory tags already have flow-sensitive aliasing
! information, so they need not be processed by
! compute_flow_insensitive_aliasing. Similarly, symbol memory
! tags are already accounted for when we process their
! associated pointer.
!
! Structure fields, on the other hand, have to have some of this
! information processed for them, but it's pointless to mark them
! non-addressable (since they are fake variables anyway). */
! if (MTAG_P (var))
! continue;
!
! /* Remove the ADDRESSABLE flag from every addressable variable whose
! address is not needed anymore. This is caused by the propagation
! of ADDR_EXPR constants into INDIRECT_REF expressions and the
! removal of dead pointer assignments done by the early scalar
! cleanup passes. */
! if (TREE_ADDRESSABLE (var))
! {
! if (!bitmap_bit_p (gimple_addressable_vars (cfun), DECL_UID (var))
! && TREE_CODE (var) != RESULT_DECL
! && !is_global_var (var))
! {
! bool okay_to_mark = true;
! /* Since VAR is now a regular GIMPLE register, we will need
! to rename VAR into SSA afterwards. */
! mark_sym_for_renaming (var);
!
! /* The address of VAR is not needed, remove the
! addressable bit, so that it can be optimized as a
! regular variable. */
! if (okay_to_mark)
! {
! /* The memory partition holding VAR will no longer
! contain VAR, and statements referencing it will need
! to be updated. */
! if (memory_partition (var))
! mark_sym_for_renaming (memory_partition (var));
! mark_non_addressable (var);
! }
! }
! }
! /* Global variables and addressable locals may be aliased. Create an
! entry in ADDRESSABLE_VARS for VAR. */
! if (may_be_aliased (var))
! {
! create_alias_map_for (var, ai);
! mark_sym_for_renaming (var);
! }
! /* Add pointer variables that have been dereferenced to the POINTERS
! array and create a symbol memory tag for them. */
! if (POINTER_TYPE_P (TREE_TYPE (var)))
{
! if (pointer_set_contains (ai->dereferenced_ptrs, var))
! {
! tree tag, old_tag;
! var_ann_t t_ann;
!
! /* If pointer VAR still doesn't have a memory tag
! associated with it, create it now or re-use an
! existing one. */
! tag = get_smt_for (var, ai);
! t_ann = var_ann (tag);
!
! /* The symbol tag will need to be renamed into SSA
! afterwards. Note that we cannot do this inside
! get_smt_for because aliasing may run multiple times
! and we only create symbol tags the first time. */
! mark_sym_for_renaming (tag);
!
! /* Similarly, if pointer VAR used to have another type
! tag, we will need to process it in the renamer to
! remove the stale virtual operands. */
! old_tag = symbol_mem_tag (var);
! if (old_tag)
! mark_sym_for_renaming (old_tag);
! /* Associate the tag with pointer VAR. */
! set_symbol_mem_tag (var, tag);
! }
! else
! {
! /* The pointer has not been dereferenced. If it had a
! symbol memory tag, remove it and mark the old tag for
! renaming to remove it out of the IL. */
! tree tag = symbol_mem_tag (var);
! if (tag)
! {
! mark_sym_for_renaming (tag);
! set_symbol_mem_tag (var, NULL_TREE);
! }
! }
}
}
-
- VEC_free (tree, heap, varvec);
}
! /* Determine whether to use .GLOBAL_VAR to model call clobbering
! semantics. If the function makes no references to global
! variables and contains at least one call to a non-pure function,
! then we need to mark the side-effects of the call using .GLOBAL_VAR
! to represent all possible global memory referenced by the callee. */
static void
! maybe_create_global_var (void)
{
! /* No need to create it, if we have one already. */
! if (gimple_global_var (cfun) == NULL_TREE)
! {
! struct mem_ref_stats_d *stats = gimple_mem_ref_stats (cfun);
! /* Create .GLOBAL_VAR if there are no call-clobbered
! variables and the program contains a mixture of pure/const
! and regular function calls. This is to avoid the problem
! described in PR 20115:
!
! int X;
! int func_pure (void) { return X; }
! int func_non_pure (int a) { X += a; }
! int foo ()
! {
! int a = func_pure ();
! func_non_pure (a);
! a = func_pure ();
! return a;
! }
!
! Since foo() has no call-clobbered variables, there is
! no relationship between the calls to func_pure and
! func_non_pure. Since func_pure has no side-effects, value
! numbering optimizations elide the second call to func_pure.
! So, if we have some pure/const and some regular calls in the
! program we create .GLOBAL_VAR to avoid missing these
! relations. */
! if (bitmap_empty_p (gimple_call_clobbered_vars (cfun))
! && stats->num_call_sites > 0
! && stats->num_pure_const_call_sites > 0
! && stats->num_call_sites > stats->num_pure_const_call_sites)
! create_global_var ();
}
}
--- 244,586 ----
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 flow-sensitive, points-to based aliasing for all the name
+ memory tags. */
+ compute_flow_sensitive_aliasing ();
+
+ /* Compute call clobbering information. */
+ compute_call_clobbered ();
! /* Debugging dumps. */
! if (dump_file)
! {
! dump_alias_info (dump_file);
! dump_points_to_info (dump_file);
! if (dump_flags & TDF_STATS)
! dump_alias_stats (dump_file);
! if (dump_flags & TDF_DETAILS)
! dump_referenced_vars (dump_file);
}
! /* Report strict aliasing violations. */
! strict_aliasing_warning_backend ();
! /* 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 but keep the name tag to
! avoid creating new temporaries unnecessarily. If
! this pointer is found to point to a subset or
! superset of its former points-to set, then a new
! tag will need to be created in create_name_tags. */
! pi->pt_anything = 0;
! pi->pt_null = 0;
! pi->value_escapes_p = 0;
! pi->is_dereferenced = 0;
! if (pi->pt_vars)
! bitmap_clear (pi->pt_vars);
}
}
}
!
! /* For every pointer P_i in AI->PROCESSED_PTRS, create may-alias sets for
! the name memory tag (NMT) associated with P_i. If P_i escapes, then its
! name tag and the variables it points-to are call-clobbered. Finally, if
! P_i escapes and we could not determine where it points to, then all the
! variables in the same alias set as *P_i are marked call-clobbered. This
! is necessary because we must assume that P_i may take the address of any
! variable in the same alias set. */
static void
! compute_flow_sensitive_aliasing (void)
{
! unsigned i;
!
! timevar_push (TV_FLOW_SENSITIVE);
! for (i = 0; i < num_ssa_names; ++i)
! {
! tree ptr = ssa_name (i);
! if (ptr
! && POINTER_TYPE_P (TREE_TYPE (ptr)))
! if (!find_what_p_points_to (ptr))
! set_pt_anything (ptr);
}
+
+ timevar_pop (TV_FLOW_SENSITIVE);
}
*************** may_alias_p (tree ptr, alias_set_type me
*** 2919,2938 ****
tree var, alias_set_type var_alias_set,
bool alias_set_only)
{
- tree mem;
-
alias_stats.alias_queries++;
alias_stats.simple_queries++;
- /* By convention, a variable cannot alias itself. */
- mem = symbol_mem_tag (ptr);
- if (mem == var)
- {
- alias_stats.alias_noalias++;
- alias_stats.simple_resolved++;
- return false;
- }
-
/* If -fargument-noalias-global is > 2, pointer arguments may
not point to anything else. */
if (flag_argument_noalias > 2 && TREE_CODE (ptr) == PARM_DECL)
--- 598,606 ----
*************** may_alias_p (tree ptr, alias_set_type me
*** 2965,2972 ****
return true;
}
- gcc_assert (TREE_CODE (mem) == SYMBOL_MEMORY_TAG);
-
alias_stats.tbaa_queries++;
/* If the alias sets don't conflict then MEM cannot alias VAR. */
--- 633,638 ----
*************** may_point_to_global_var (tree ptr)
*** 3054,3091 ****
/* If we do not have points-to information for this variable,
we have to punt. */
! if (!pi
! || !pi->name_mem_tag)
return true;
! /* The name memory tag is marked as global variable if the points-to
! set contains a global variable. */
! return is_global_var (pi->name_mem_tag);
! }
!
! /* Add ALIAS to the set of variables that may alias VAR. */
!
! static void
! add_may_alias (tree var, tree alias)
! {
! /* Don't allow self-referential aliases. */
! gcc_assert (var != alias);
!
! /* ALIAS must be addressable if it's being added to an alias set. */
! #if 1
! TREE_ADDRESSABLE (alias) = 1;
! #else
! gcc_assert (may_be_aliased (alias));
! #endif
!
! /* VAR must be a symbol or a name tag. */
! gcc_assert (TREE_CODE (var) == SYMBOL_MEMORY_TAG
! || TREE_CODE (var) == NAME_MEMORY_TAG);
!
! if (MTAG_ALIASES (var) == NULL)
! MTAG_ALIASES (var) = BITMAP_ALLOC (&alias_bitmap_obstack);
!
! bitmap_set_bit (MTAG_ALIASES (var), DECL_UID (alias));
}
--- 720,729 ----
/* If we do not have points-to information for this variable,
we have to punt. */
! if (!pi)
return true;
! return pi->pt_global_mem;
}
*************** set_pt_anything (tree ptr)
*** 3100,3114 ****
/* Anything includes global memory. */
pi->pt_global_mem = 1;
pi->pt_vars = NULL;
-
- /* The pointer used to have a name tag, but we now found it pointing
- to an arbitrary location. The name tag needs to be renamed and
- disassociated from PTR. */
- if (pi->name_mem_tag)
- {
- mark_sym_for_renaming (pi->name_mem_tag);
- pi->name_mem_tag = NULL_TREE;
- }
}
--- 738,743 ----
*************** is_escape_site (gimple stmt)
*** 3188,3371 ****
return NO_ESCAPE;
}
- /* Create a new memory tag of type TYPE.
- Does NOT push it into the current binding. */
-
- tree
- create_tag_raw (enum tree_code code, tree type, const char *prefix)
- {
- tree tmp_var;
-
- tmp_var = build_decl (code, create_tmp_var_name (prefix), type);
-
- /* Memory tags are always writable and non-static. */
- TREE_READONLY (tmp_var) = 0;
- TREE_STATIC (tmp_var) = 0;
-
- /* It doesn't start out global. */
- MTAG_GLOBAL (tmp_var) = 0;
- TREE_USED (tmp_var) = 1;
-
- return tmp_var;
- }
-
- /* Create a new memory tag of type TYPE. If IS_TYPE_TAG is true, the tag
- is considered to represent all the pointers whose pointed-to types are
- in the same alias set class. Otherwise, the tag represents a single
- SSA_NAME pointer variable. */
-
- static tree
- create_memory_tag (tree type, bool is_type_tag)
- {
- tree tag = create_tag_raw (is_type_tag ? SYMBOL_MEMORY_TAG : NAME_MEMORY_TAG,
- type, (is_type_tag) ? "SMT" : "NMT");
-
- /* By default, memory tags are local variables. Alias analysis will
- determine whether they should be considered globals. */
- DECL_CONTEXT (tag) = current_function_decl;
-
- /* Memory tags are by definition addressable. */
- TREE_ADDRESSABLE (tag) = 1;
-
- set_symbol_mem_tag (tag, NULL_TREE);
-
- /* Add the tag to the symbol table. */
- add_referenced_var (tag);
-
- return tag;
- }
-
-
- /* Create a name memory tag to represent a specific SSA_NAME pointer P_i.
- This is used if P_i has been found to point to a specific set of
- variables or to a non-aliased memory location like the address returned
- by malloc functions. */
-
- static tree
- get_nmt_for (tree ptr)
- {
- struct ptr_info_def *pi = get_ptr_info (ptr);
- tree tag = pi->name_mem_tag;
-
- if (tag == NULL_TREE)
- tag = create_memory_tag (TREE_TYPE (TREE_TYPE (ptr)), false);
- return tag;
- }
-
-
- /* Return the symbol memory tag associated to pointer PTR. A memory
- tag is an artificial variable that represents the memory location
- pointed-to by PTR. It is used to model the effects of pointer
- de-references on addressable variables.
-
- AI points to the data gathered during alias analysis. This
- function populates the array AI->POINTERS. */
-
- static tree
- get_smt_for (tree ptr, struct alias_info *ai)
- {
- size_t i;
- tree tag;
- tree tag_type = TREE_TYPE (TREE_TYPE (ptr));
- alias_set_type tag_set;
-
- /* Get the alias set to be used for the pointed-to memory. If that
- differs from what we would get from looking at the type adjust
- the tag_type to void to make sure we get a proper alias set from
- just looking at the SMT we create. */
- tag_set = get_alias_set (tag_type);
- if (TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (ptr))
- /* This is overly conservative but we do not want to assign
- restrict alias sets here (which if they are not assigned
- are -2 but still "known"). */
- || DECL_POINTER_ALIAS_SET_KNOWN_P (ptr))
- {
- tag_set = 0;
- tag_type = void_type_node;
- }
-
- /* To avoid creating unnecessary memory tags, only create one memory tag
- per alias set class. Note that it may be tempting to group
- memory tags based on conflicting alias sets instead of
- equivalence. That would be wrong because alias sets are not
- necessarily transitive (as demonstrated by the libstdc++ test
- 23_containers/vector/cons/4.cc). Given three alias sets A, B, C
- such that conflicts (A, B) == true and conflicts (A, C) == true,
- it does not necessarily follow that conflicts (B, C) == true. */
- for (i = 0, tag = NULL_TREE; i < ai->num_pointers; i++)
- {
- struct alias_map_d *curr = ai->pointers[i];
- tree curr_tag = symbol_mem_tag (curr->var);
- if (tag_set == curr->set)
- {
- tag = curr_tag;
- break;
- }
- }
-
- /* If VAR cannot alias with any of the existing memory tags, create a new
- tag for PTR and add it to the POINTERS array. */
- if (tag == NULL_TREE)
- {
- struct alias_map_d *alias_map;
-
- /* If PTR did not have a symbol tag already, create a new SMT.*
- artificial variable representing the memory location
- pointed-to by PTR. */
- tag = symbol_mem_tag (ptr);
- if (tag == NULL_TREE
- || tag_set != get_alias_set (tag))
- tag = create_memory_tag (tag_type, true);
-
- /* Add PTR to the POINTERS array. Note that we are not interested in
- PTR's alias set. Instead, we cache the alias set for the memory that
- PTR points to. */
- alias_map = XCNEW (struct alias_map_d);
- alias_map->var = ptr;
- alias_map->set = tag_set;
- ai->pointers[ai->num_pointers++] = alias_map;
- }
-
- /* If the pointed-to type is volatile, so is the tag. */
- TREE_THIS_VOLATILE (tag) |= TREE_THIS_VOLATILE (tag_type);
-
- /* Make sure that the symbol tag has the same alias set as the
- pointed-to type or at least accesses through the pointer will
- alias that set. The latter can happen after the vectorizer
- created pointers of vector type. */
- gcc_assert (tag_set == get_alias_set (tag)
- || alias_set_subset_of (tag_set, get_alias_set (tag)));
-
- return tag;
- }
-
-
- /* Create GLOBAL_VAR, an artificial global variable to act as a
- representative of all the variables that may be clobbered by function
- calls. */
-
- static void
- create_global_var (void)
- {
- tree global_var = build_decl (VAR_DECL, get_identifier (".GLOBAL_VAR"),
- void_type_node);
- DECL_ARTIFICIAL (global_var) = 1;
- TREE_READONLY (global_var) = 0;
- DECL_EXTERNAL (global_var) = 1;
- TREE_STATIC (global_var) = 1;
- TREE_USED (global_var) = 1;
- DECL_CONTEXT (global_var) = NULL_TREE;
- TREE_THIS_VOLATILE (global_var) = 0;
- TREE_ADDRESSABLE (global_var) = 0;
-
- create_var_ann (global_var);
- mark_call_clobbered (global_var, ESCAPE_UNKNOWN);
- add_referenced_var (global_var);
- mark_sym_for_renaming (global_var);
- cfun->gimple_df->global_var = global_var;
- }
-
-
/* Dump alias statistics on FILE. */
static void
--- 817,822 ----
*************** dump_alias_stats (FILE *file)
*** 3392,3398 ****
fprintf (file, "Total non-addressable structure type resolved:\t%u\n",
alias_stats.structnoaddress_resolved);
}
!
/* Dump alias information on FILE. */
--- 843,872 ----
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. */
*************** dump_alias_info (FILE *file)
*** 3407,3416 ****
fprintf (file, "\nAlias information for %s\n\n", funcname);
- dump_memory_partitions (file);
-
- fprintf (file, "\nFlow-insensitive alias information for %s\n\n", funcname);
-
fprintf (file, "Aliased symbols\n\n");
FOR_EACH_REFERENCED_VAR (var, rvi)
--- 881,886 ----
*************** dump_alias_info (FILE *file)
*** 3421,3438 ****
fprintf (file, "\nDereferenced pointers\n\n");
- FOR_EACH_REFERENCED_VAR (var, rvi)
- if (symbol_mem_tag (var))
- dump_variable (file, var);
-
- fprintf (file, "\nSymbol memory tags\n\n");
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- if (TREE_CODE (var) == SYMBOL_MEMORY_TAG)
- dump_variable (file, var);
- }
-
fprintf (file, "\n\nFlow-sensitive alias information for %s\n\n", funcname);
fprintf (file, "SSA_NAME pointers\n\n");
--- 891,896 ----
*************** dump_alias_info (FILE *file)
*** 3441,3464 ****
tree ptr = ssa_name (i);
struct ptr_info_def *pi;
! if (ptr == NULL_TREE)
continue;
pi = SSA_NAME_PTR_INFO (ptr);
! if (!SSA_NAME_IN_FREE_LIST (ptr)
! && pi
! && pi->name_mem_tag)
dump_points_to_info_for (file, ptr);
}
- fprintf (file, "\nName memory tags\n\n");
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- if (TREE_CODE (var) == NAME_MEMORY_TAG)
- dump_variable (file, var);
- }
-
fprintf (file, "\n");
}
--- 899,913 ----
tree ptr = ssa_name (i);
struct ptr_info_def *pi;
! if (ptr == NULL_TREE
! || SSA_NAME_IN_FREE_LIST (ptr))
continue;
pi = SSA_NAME_PTR_INFO (ptr);
! if (pi)
dump_points_to_info_for (file, ptr);
}
fprintf (file, "\n");
}
*************** dump_points_to_info_for (FILE *file, tre
*** 3503,3518 ****
if (pi)
{
- if (pi->name_mem_tag)
- {
- fprintf (file, ", name memory tag: ");
- print_generic_expr (file, pi->name_mem_tag, dump_flags);
- }
-
if (pi->is_dereferenced)
fprintf (file, ", is dereferenced");
- else if (pi->memory_tag_needed)
- fprintf (file, ", is dereferenced in call");
if (pi->value_escapes_p)
fprintf (file, ", its value escapes");
--- 952,959 ----
*************** debug_points_to_info (void)
*** 3606,3741 ****
dump_points_to_info (stderr);
}
- /* Dump to FILE the list of variables that may be aliasing VAR. */
-
- void
- dump_may_aliases_for (FILE *file, tree var)
- {
- bitmap aliases;
-
- aliases = MTAG_ALIASES (var);
- if (aliases)
- {
- bitmap_iterator bi;
- unsigned int i;
- tree al;
-
- fprintf (file, "{ ");
- EXECUTE_IF_SET_IN_BITMAP (aliases, 0, i, bi)
- {
- al = referenced_var (i);
- print_generic_expr (file, al, dump_flags);
- fprintf (file, " ");
- }
- fprintf (file, "}");
- }
- }
-
-
- /* Dump to stderr the list of variables that may be aliasing VAR. */
-
- void
- debug_may_aliases_for (tree var)
- {
- dump_may_aliases_for (stderr, var);
- }
-
- /* Return true if VAR may be aliased. */
-
- bool
- may_be_aliased (tree var)
- {
- /* Obviously. */
- if (TREE_ADDRESSABLE (var))
- return true;
-
- /* Globally visible variables can have their addresses taken by other
- translation units. */
- if (MTAG_P (var)
- && MTAG_GLOBAL (var))
- return true;
- else if (!MTAG_P (var)
- && (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;
- }
-
- /* The following is based on code in add_stmt_operand to ensure that the
- same defs/uses/vdefs/vuses will be found after replacing a reference
- to var (or ARRAY_REF to var) with an INDIRECT_REF to ptr whose value
- is the address of var. Return a memtag for the ptr, after adding the
- proper may_aliases to it (which are the aliases of var, if it has any,
- or var itself). */
-
- static tree
- add_may_alias_for_new_tag (tree tag, tree var)
- {
- bitmap aliases = NULL;
-
- if (MTAG_P (var))
- aliases = may_aliases (var);
-
- /* Case 1: |aliases| == 1 */
- if (aliases
- && bitmap_single_bit_set_p (aliases))
- {
- tree ali = referenced_var (bitmap_first_set_bit (aliases));
- if (TREE_CODE (ali) == SYMBOL_MEMORY_TAG)
- return ali;
- }
-
- /* Case 2: |aliases| == 0 */
- if (aliases == NULL)
- add_may_alias (tag, var);
- else
- {
- /* Case 3: |aliases| > 1 */
- union_alias_set_into (tag, aliases);
- }
- return tag;
- }
-
- /* Create a new symbol tag for PTR. Construct the may-alias list of
- this type tag so that it has the aliasing of VAR according to the
- location accessed by EXPR.
-
- Note, the set of aliases represented by the new symbol tag are not
- marked for renaming. */
-
- void
- new_type_alias (tree ptr, tree var, tree expr)
- {
- tree tag_type = TREE_TYPE (TREE_TYPE (ptr));
- tree tag;
- tree ali = NULL_TREE;
- HOST_WIDE_INT offset, size, maxsize;
- tree ref;
-
- gcc_assert (symbol_mem_tag (ptr) == NULL_TREE);
- gcc_assert (!MTAG_P (var));
-
- ref = get_ref_base_and_extent (expr, &offset, &size, &maxsize);
- gcc_assert (ref);
-
- tag = create_memory_tag (tag_type, true);
- set_symbol_mem_tag (ptr, tag);
-
- ali = add_may_alias_for_new_tag (tag, var);
-
- set_symbol_mem_tag (ptr, ali);
- MTAG_GLOBAL (tag) = is_global_var (var);
- }
-
! /* Reset the call_clobbered flags on our referenced vars. In
! theory, this only needs to be done for globals. */
static unsigned int
reset_cc_flags (void)
--- 1047,1055 ----
dump_points_to_info (stderr);
}
! /* ??? Remove me.
! For now just a quick verification run on sane initial properties. */
static unsigned int
reset_cc_flags (void)
*************** reset_cc_flags (void)
*** 3744,3750 ****
referenced_var_iterator rvi;
FOR_EACH_REFERENCED_VAR (var, rvi)
! var_ann (var)->call_clobbered = false;
return 0;
}
--- 1058,1069 ----
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;
}
Index: alias-improvements/gcc/gimple.c
===================================================================
*** alias-improvements.orig/gcc/gimple.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/gimple.c 2008-11-26 13:48:08.000000000 +0100
*************** is_gimple_reg (tree t)
*** 2889,2897 ****
if (TREE_CODE (t) == SSA_NAME)
t = SSA_NAME_VAR (t);
- if (MTAG_P (t))
- return false;
-
if (!is_gimple_variable (t))
return false;
--- 2889,2894 ----
Index: alias-improvements/gcc/ipa-cp.c
===================================================================
*** alias-improvements.orig/gcc/ipa-cp.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/ipa-cp.c 2008-11-26 13:48:08.000000000 +0100
*************** ipcp_update_callgraph (void)
*** 972,978 ****
gsi = gsi_for_stmt (cs->call_stmt);
gsi_replace (&gsi, new_stmt, true);
cgraph_set_call_stmt (cs, new_stmt);
! /* ??? We loose pure/const or clobber information during
cloning so we may end up with different VOPs for
the call. See gcc.c-torture/execute/20000113-1.c. */
update_ssa (TODO_update_ssa);
--- 972,978 ----
gsi = gsi_for_stmt (cs->call_stmt);
gsi_replace (&gsi, new_stmt, true);
cgraph_set_call_stmt (cs, new_stmt);
! /* ??? We lose pure/const or clobber information during
cloning so we may end up with different VOPs for
the call. See gcc.c-torture/execute/20000113-1.c. */
update_ssa (TODO_update_ssa);
Index: alias-improvements/gcc/passes.c
===================================================================
*** alias-improvements.orig/gcc/passes.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/passes.c 2008-11-26 13:48:08.000000000 +0100
*************** init_optimization_passes (void)
*** 600,605 ****
--- 600,606 ----
calls, it is better to do the transformation
here where memory SSA is not built yet. */
NEXT_PASS (pass_call_cdce);
+ NEXT_PASS (pass_update_address_taken);
/* pass_build_alias is a dummy pass that ensures that we
execute TODO_rebuild_alias at this point. Re-building
alias information also rewrites no longer addressed
Index: alias-improvements/gcc/tree-data-ref.c
===================================================================
*** alias-improvements.orig/gcc/tree-data-ref.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-data-ref.c 2008-11-26 13:48:08.000000000 +0100
*************** dr_analyze_indices (struct data_referenc
*** 788,821 ****
static void
dr_analyze_alias (struct data_reference *dr)
{
- gimple stmt = DR_STMT (dr);
tree ref = DR_REF (dr);
! tree base = get_base_address (ref), addr, smt = NULL_TREE;
! ssa_op_iter it;
! tree op;
! bitmap vops;
!
! if (DECL_P (base))
! smt = base;
! else if (INDIRECT_REF_P (base))
{
addr = TREE_OPERAND (base, 0);
if (TREE_CODE (addr) == SSA_NAME)
! {
! smt = symbol_mem_tag (SSA_NAME_VAR (addr));
! DR_PTR_INFO (dr) = SSA_NAME_PTR_INFO (addr);
! }
! }
!
! DR_SYMBOL_TAG (dr) = smt;
!
! vops = BITMAP_ALLOC (NULL);
! FOR_EACH_SSA_TREE_OPERAND (op, stmt, it, SSA_OP_VIRTUAL_USES)
! {
! bitmap_set_bit (vops, DECL_UID (SSA_NAME_VAR (op)));
}
-
- DR_VOPS (dr) = vops;
}
/* Returns true if the address of DR is invariant. */
--- 788,802 ----
static void
dr_analyze_alias (struct data_reference *dr)
{
tree ref = DR_REF (dr);
! tree base = get_base_address (ref), addr;
!
! if (INDIRECT_REF_P (base))
{
addr = TREE_OPERAND (base, 0);
if (TREE_CODE (addr) == SSA_NAME)
! DR_PTR_INFO (dr) = SSA_NAME_PTR_INFO (addr);
}
}
/* Returns true if the address of DR is invariant. */
*************** dr_address_invariant_p (struct data_refe
*** 838,844 ****
void
free_data_ref (data_reference_p dr)
{
- BITMAP_FREE (DR_VOPS (dr));
VEC_free (tree, heap, DR_ACCESS_FNS (dr));
free (dr);
}
--- 819,824 ----
*************** create_data_ref (struct loop *nest, tree
*** 883,890 ****
print_generic_expr (dump_file, DR_ALIGNED_TO (dr), TDF_SLIM);
fprintf (dump_file, "\n\tbase_object: ");
print_generic_expr (dump_file, DR_BASE_OBJECT (dr), TDF_SLIM);
- fprintf (dump_file, "\n\tsymbol tag: ");
- print_generic_expr (dump_file, DR_SYMBOL_TAG (dr), TDF_SLIM);
fprintf (dump_file, "\n");
}
--- 863,868 ----
*************** dr_may_alias_p (const struct data_refere
*** 1234,1244 ****
const_tree type_a, type_b;
const_tree decl_a = NULL_TREE, decl_b = NULL_TREE;
- /* If the sets of virtual operands are disjoint, the memory references do not
- alias. */
- if (!bitmap_intersect_p (DR_VOPS (a), DR_VOPS (b)))
- return false;
-
/* If the accessed objects are disjoint, the memory references do not
alias. */
if (disjoint_objects_p (DR_BASE_OBJECT (a), DR_BASE_OBJECT (b)))
--- 1212,1217 ----
*************** analyze_all_data_dependences (struct loo
*** 4349,4355 ****
{
unsigned nb_top_relations = 0;
unsigned nb_bot_relations = 0;
- unsigned nb_basename_differ = 0;
unsigned nb_chrec_relations = 0;
struct data_dependence_relation *ddr;
--- 4322,4327 ----
*************** analyze_all_data_dependences (struct loo
*** 4359,4373 ****
nb_top_relations++;
else if (DDR_ARE_DEPENDENT (ddr) == chrec_known)
! {
! struct data_reference *a = DDR_A (ddr);
! struct data_reference *b = DDR_B (ddr);
!
! if (!bitmap_intersect_p (DR_VOPS (a), DR_VOPS (b)))
! nb_basename_differ++;
! else
! nb_bot_relations++;
! }
else
nb_chrec_relations++;
--- 4331,4337 ----
nb_top_relations++;
else if (DDR_ARE_DEPENDENT (ddr) == chrec_known)
! nb_bot_relations++;
else
nb_chrec_relations++;
Index: alias-improvements/gcc/tree-dfa.c
===================================================================
*** alias-improvements.orig/gcc/tree-dfa.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-dfa.c 2008-11-26 13:48:08.000000000 +0100
*************** dump_variable (FILE *file, tree var)
*** 297,308 ****
fprintf (file, ", ");
print_generic_expr (file, TREE_TYPE (var), dump_flags);
- if (ann && ann->symbol_mem_tag)
- {
- fprintf (file, ", symbol memory tag: ");
- print_generic_expr (file, ann->symbol_mem_tag, dump_flags);
- }
-
if (TREE_ADDRESSABLE (var))
fprintf (file, ", is addressable");
--- 297,302 ----
*************** dump_variable (FILE *file, tree var)
*** 312,319 ****
if (TREE_THIS_VOLATILE (var))
fprintf (file, ", is volatile");
- dump_mem_sym_stats_for_var (file, var);
-
if (is_call_clobbered (var))
{
const char *s = "";
--- 306,311 ----
*************** dump_variable (FILE *file, tree var)
*** 357,383 ****
print_generic_expr (file, gimple_default_def (cfun, var), dump_flags);
}
- if (MTAG_P (var) && may_aliases (var))
- {
- fprintf (file, ", may aliases: ");
- dump_may_aliases_for (file, var);
- }
-
- if (!is_gimple_reg (var))
- {
- if (memory_partition (var))
- {
- fprintf (file, ", belongs to partition: ");
- print_generic_expr (file, memory_partition (var), dump_flags);
- }
-
- if (TREE_CODE (var) == MEMORY_PARTITION_TAG)
- {
- fprintf (file, ", partition symbols: ");
- dump_decl_set (file, MPT_SYMBOLS (var));
- }
- }
-
fprintf (file, "\n");
}
--- 349,354 ----
*************** add_referenced_var (tree var)
*** 650,661 ****
/* Insert VAR into the referenced_vars has table if it isn't present. */
if (referenced_var_check_and_insert (var))
{
! /* This is the first time we found this variable, annotate it with
! attributes that are intrinsic to the variable. */
!
! /* Tag's don't have DECL_INITIAL. */
! if (MTAG_P (var))
! return;
/* Scan DECL_INITIAL for pointer variables as they may contain
address arithmetic referencing the address of other
--- 621,634 ----
/* Insert VAR into the referenced_vars has table if it isn't present. */
if (referenced_var_check_and_insert (var))
{
! /* If this is a new global or addressable variable conservatively
! initialize its call-clobber state. */
! if (is_global_var (var))
! mark_call_clobbered (var, ESCAPE_IS_GLOBAL);
! else if (TREE_ADDRESSABLE (var))
! mark_call_clobbered (var, ESCAPE_UNKNOWN);
! else
! clear_call_clobbered (var);
/* Scan DECL_INITIAL for pointer variables as they may contain
address arithmetic referencing the address of other
*************** remove_referenced_var (tree var)
*** 682,701 ****
clear_call_clobbered (var);
bitmap_clear_bit (gimple_call_used_vars (cfun), uid);
! if ((v_ann = var_ann (var)))
{
! /* Preserve var_anns of globals, but clear their alias info. */
! if (MTAG_P (var)
! || (!TREE_STATIC (var) && !DECL_EXTERNAL (var)))
! {
! ggc_free (v_ann);
! var->base.ann = NULL;
! }
! else
! {
! v_ann->mpt = NULL_TREE;
! v_ann->symbol_mem_tag = NULL_TREE;
! }
}
gcc_assert (DECL_P (var));
in.uid = uid;
--- 655,666 ----
clear_call_clobbered (var);
bitmap_clear_bit (gimple_call_used_vars (cfun), uid);
! /* Preserve var_anns of globals. */
! if (!is_global_var (var)
! && (v_ann = var_ann (var)))
{
! ggc_free (v_ann);
! var->base.ann = NULL;
}
gcc_assert (DECL_P (var));
in.uid = uid;
Index: alias-improvements/gcc/tree-dump.c
===================================================================
*** alias-improvements.orig/gcc/tree-dump.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-dump.c 2008-11-26 13:48:08.000000000 +0100
*************** dequeue_and_dump (dump_info_p di)
*** 510,519 ****
case CONST_DECL:
dump_child ("cnst", DECL_INITIAL (t));
break;
-
- case SYMBOL_MEMORY_TAG:
- case NAME_MEMORY_TAG:
- break;
case VAR_DECL:
case PARM_DECL:
--- 510,515 ----
Index: alias-improvements/gcc/tree-flow-inline.h
===================================================================
*** alias-improvements.orig/gcc/tree-flow-inline.h 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-flow-inline.h 2008-11-26 13:48:08.000000000 +0100
*************** gimple_in_ssa_p (const struct function *
*** 35,48 ****
return fun && fun->gimple_df && fun->gimple_df->in_ssa_p;
}
- /* 'true' after aliases have been computed (see compute_may_aliases). */
- static inline bool
- gimple_aliases_computed_p (const struct function *fun)
- {
- gcc_assert (fun && fun->gimple_df);
- return fun->gimple_df->aliases_computed_p;
- }
-
/* Addressable variables in the function. If bit I is set, then
REFERENCED_VARS (I) has had its address taken. Note that
CALL_CLOBBERED_VARS and ADDRESSABLE_VARS are not related. An
--- 35,40 ----
*************** gimple_referenced_vars (const struct fun
*** 84,97 ****
return fun->gimple_df->referenced_vars;
}
- /* Artificial variable used to model the effects of function calls. */
- static inline tree
- gimple_global_var (const struct function *fun)
- {
- gcc_assert (fun && fun->gimple_df);
- return fun->gimple_df->global_var;
- }
-
/* Artificial variable used to model the effects of nonlocal
variables. */
static inline tree
--- 76,81 ----
*************** ann_type (tree_ann_t ann)
*** 271,284 ****
return ann->common.type;
}
- /* Return the may_aliases bitmap for variable VAR, or NULL if it has
- no may aliases. */
- static inline bitmap
- may_aliases (const_tree var)
- {
- return MTAG_ALIASES (var);
- }
-
/* Return the line number for EXPR, or return -1 if we have no line
number information for it. */
static inline int
--- 255,260 ----
*************** set_is_used (tree var)
*** 605,614 ****
static inline bool
is_global_var (const_tree t)
{
! if (MTAG_P (t))
! return MTAG_GLOBAL (t);
! else
! return (TREE_STATIC (t) || DECL_EXTERNAL (t));
}
/* PHI nodes should contain only ssa_names and invariants. A test
--- 581,587 ----
static inline bool
is_global_var (const_tree t)
{
! return (TREE_STATIC (t) || DECL_EXTERNAL (t));
}
/* PHI nodes should contain only ssa_names and invariants. A test
*************** loop_containing_stmt (gimple stmt)
*** 640,703 ****
}
! /* Return the memory partition tag associated with symbol SYM. */
!
! static inline tree
! memory_partition (tree sym)
! {
! tree tag;
!
! /* MPTs belong to their own partition. */
! if (TREE_CODE (sym) == MEMORY_PARTITION_TAG)
! return sym;
!
! gcc_assert (!is_gimple_reg (sym));
! /* Autoparallelization moves statements from the original function (which has
! aliases computed) to the new one (which does not). When rebuilding
! operands for the statement in the new function, we do not want to
! record the memory partition tags of the original function. */
! if (!gimple_aliases_computed_p (cfun))
! return NULL_TREE;
! tag = get_var_ann (sym)->mpt;
!
! #if defined ENABLE_CHECKING
! if (tag)
! gcc_assert (TREE_CODE (tag) == MEMORY_PARTITION_TAG);
! #endif
!
! return tag;
! }
!
! /* Return true if NAME is a memory factoring SSA name (i.e., an SSA
! name for a memory partition. */
!
static inline bool
! factoring_name_p (const_tree name)
{
! return TREE_CODE (SSA_NAME_VAR (name)) == MEMORY_PARTITION_TAG;
}
/* Return true if VAR is used by function calls. */
static inline bool
is_call_used (const_tree var)
{
! return (var_ann (var)->call_clobbered
|| bitmap_bit_p (gimple_call_used_vars (cfun), DECL_UID (var)));
}
- /* Return true if VAR is clobbered by function calls. */
- static inline bool
- is_call_clobbered (const_tree var)
- {
- return var_ann (var)->call_clobbered;
- }
-
/* Mark variable VAR as being clobbered by function calls. */
static inline void
mark_call_clobbered (tree var, unsigned int escape_type)
{
var_ann (var)->escape_mask |= escape_type;
- var_ann (var)->call_clobbered = true;
bitmap_set_bit (gimple_call_clobbered_vars (cfun), DECL_UID (var));
}
--- 613,641 ----
}
! /* Return true if VAR is clobbered by function calls. */
static inline bool
! is_call_clobbered (const_tree var)
{
! return (is_global_var (var)
! || bitmap_bit_p (gimple_call_clobbered_vars (cfun), DECL_UID (var)));
}
/* Return true if VAR is used by function calls. */
static inline bool
is_call_used (const_tree var)
{
! return (is_call_clobbered (var)
|| bitmap_bit_p (gimple_call_used_vars (cfun), DECL_UID (var)));
}
/* Mark variable VAR as being clobbered by function calls. */
static inline void
mark_call_clobbered (tree var, unsigned int escape_type)
{
+ if (is_global_var (var))
+ return;
var_ann (var)->escape_mask |= escape_type;
bitmap_set_bit (gimple_call_clobbered_vars (cfun), DECL_UID (var));
}
*************** mark_call_clobbered (tree var, unsigned
*** 705,715 ****
static inline void
clear_call_clobbered (tree var)
{
! var_ann_t ann = var_ann (var);
! ann->escape_mask = 0;
! if (MTAG_P (var))
! MTAG_GLOBAL (var) = 0;
! var_ann (var)->call_clobbered = false;
bitmap_clear_bit (gimple_call_clobbered_vars (cfun), DECL_UID (var));
}
--- 643,651 ----
static inline void
clear_call_clobbered (tree var)
{
! if (is_global_var (var))
! return;
! var_ann (var)->escape_mask = 0;
bitmap_clear_bit (gimple_call_clobbered_vars (cfun), DECL_UID (var));
}
*************** unmodifiable_var_p (const_tree var)
*** 1363,1371 ****
if (TREE_CODE (var) == SSA_NAME)
var = SSA_NAME_VAR (var);
- if (MTAG_P (var))
- return false;
-
return TREE_READONLY (var) && (TREE_STATIC (var) || DECL_EXTERNAL (var));
}
--- 1299,1304 ----
*************** ranges_overlap_p (unsigned HOST_WIDE_INT
*** 1422,1456 ****
return false;
}
- /* Return the memory tag associated with symbol SYM. */
-
- static inline tree
- symbol_mem_tag (tree sym)
- {
- tree tag = get_var_ann (sym)->symbol_mem_tag;
-
- #if defined ENABLE_CHECKING
- if (tag)
- gcc_assert (TREE_CODE (tag) == SYMBOL_MEMORY_TAG);
- #endif
-
- return tag;
- }
-
-
- /* Set the memory tag associated with symbol SYM. */
-
- static inline void
- set_symbol_mem_tag (tree sym, tree tag)
- {
- #if defined ENABLE_CHECKING
- if (tag)
- gcc_assert (TREE_CODE (tag) == SYMBOL_MEMORY_TAG);
- #endif
-
- get_var_ann (sym)->symbol_mem_tag = tag;
- }
-
/* Accessor to tree-ssa-operands.c caches. */
static inline struct ssa_operands *
gimple_ssa_operands (const struct function *fun)
--- 1355,1360 ----
*************** gimple_ssa_operands (const struct functi
*** 1458,1470 ****
return &fun->gimple_df->ssa_operands;
}
- /* Map describing reference statistics for function FN. */
- static inline struct mem_ref_stats_d *
- gimple_mem_ref_stats (const struct function *fn)
- {
- return &fn->gimple_df->mem_ref_stats;
- }
-
/* Given an edge_var_map V, return the PHI arg definition. */
static inline tree
--- 1362,1367 ----
Index: alias-improvements/gcc/tree-flow.h
===================================================================
*** alias-improvements.orig/gcc/tree-flow.h 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-flow.h 2008-11-26 13:48:08.000000000 +0100
*************** enum escape_type
*** 59,138 ****
above. */
};
- /* Memory reference statistics for individual memory symbols,
- collected during alias analysis. */
- struct mem_sym_stats_d GTY(())
- {
- /* Memory symbol. */
- tree var;
-
- /* Nonzero if this entry has been assigned a partition. */
- unsigned int partitioned_p : 1;
-
- /* Nonzero if VAR is a memory partition tag that already contains
- call-clobbered variables in its partition set. */
- unsigned int has_call_clobbered_vars : 1;
-
- /* Number of direct reference sites. A direct reference to VAR is any
- reference of the form 'VAR = ' or ' = VAR'. For GIMPLE reg
- pointers, this is the number of sites where the pointer is
- dereferenced. */
- long num_direct_writes;
- long num_direct_reads;
-
- /* Number of indirect reference sites. An indirect reference to VAR
- is any reference via a pointer that contains VAR in its points-to
- set or, in the case of call-clobbered symbols, a function call. */
- long num_indirect_writes;
- long num_indirect_reads;
-
- /* Execution frequency. This is the sum of the execution
- frequencies of all the statements that reference this object
- weighted by the number of references in each statement. This is
- the main key used to sort the list of symbols to partition.
- Symbols with high execution frequencies are put at the bottom of
- the work list (ie, they are partitioned last).
- Execution frequencies are taken directly from each basic block,
- so compiling with PGO enabled will increase the precision of this
- estimate. */
- long frequency_reads;
- long frequency_writes;
-
- /* Set of memory tags that contain VAR in their alias set. */
- bitmap parent_tags;
- };
-
- typedef struct mem_sym_stats_d *mem_sym_stats_t;
- DEF_VEC_P(mem_sym_stats_t);
- DEF_VEC_ALLOC_P(mem_sym_stats_t, heap);
-
- /* Memory reference statistics collected during alias analysis. */
- struct mem_ref_stats_d GTY(())
- {
- /* Number of statements that make memory references. */
- long num_mem_stmts;
-
- /* Number of statements that make function calls. */
- long num_call_sites;
-
- /* Number of statements that make calls to pure/const functions. */
- long num_pure_const_call_sites;
-
- /* Number of ASM statements. */
- long num_asm_sites;
-
- /* Estimated number of virtual operands needed as computed by
- compute_memory_partitions. */
- long num_vuses;
- long num_vdefs;
-
- /* This maps every symbol used to make "memory" references
- (pointers, arrays, structures, etc) to an instance of struct
- mem_sym_stats_d describing reference statistics for the symbol. */
- struct pointer_map_t * GTY((skip)) mem_sym_stats;
- };
-
-
/* Gimple dataflow datastructure. All publicly available fields shall have
gimple_ accessor defined in tree-flow-inline.h, all publicly modifiable
fields should have gimple_set accessor. */
--- 59,64 ----
*************** struct gimple_df GTY(())
*** 154,162 ****
/* Artificial variable used for the virtual operand FUD chain. */
tree vop;
- /* Artificial variable used to model the effects of function calls. */
- tree global_var;
-
/* Artificial variable used to model the effects of nonlocal
variables. */
tree nonlocal_all;
--- 80,85 ----
*************** struct gimple_df GTY(())
*** 187,195 ****
for this variable with an empty defining statement. */
htab_t GTY((param_is (union tree_node))) default_defs;
- /* 'true' after aliases have been computed (see compute_may_aliases). */
- unsigned int aliases_computed_p : 1;
-
/* True if the code is in ssa form. */
unsigned int in_ssa_p : 1;
--- 110,115 ----
*************** struct gimple_df GTY(())
*** 197,207 ****
unsigned int vop_needs_renaming : 1;
struct ssa_operands ssa_operands;
-
- /* Memory reference statistics collected during alias analysis.
- This information is used to drive the memory partitioning
- heuristics in compute_memory_partitions. */
- struct mem_ref_stats_d mem_ref_stats;
};
/* Accessors for internal use only. Generic code should use abstraction
--- 117,122 ----
*************** struct ptr_info_def GTY(())
*** 247,256 ****
/* Nonzero if the value of this pointer escapes the current function. */
unsigned int value_escapes_p : 1;
- /* Nonzero if a memory tag is needed for this pointer. This is
- true if this pointer is eventually dereferenced. */
- unsigned int memory_tag_needed : 1;
-
/* Nonzero if this pointer is really dereferenced. */
unsigned int is_dereferenced : 1;
--- 162,167 ----
*************** struct ptr_info_def GTY(())
*** 262,273 ****
/* Set of variables that this pointer may point to. */
bitmap pt_vars;
-
- /* If this pointer has been dereferenced, and points-to information is
- more precise than type-based aliasing, indirect references to this
- pointer will be represented by this memory tag, instead of the type
- tag computed by TBAA. */
- tree name_mem_tag;
};
--- 173,178 ----
*************** struct var_ann_d GTY(())
*** 377,385 ****
the memory area allocated by a call to malloc. */
unsigned is_heapvar : 1;
- /* True if the variable is call clobbered. */
- unsigned call_clobbered : 1;
-
/* This field describes several "no alias" attributes that some
symbols are known to have. See the enum's definition for more
information on each attribute. */
--- 282,287 ----
*************** struct var_ann_d GTY(())
*** 389,406 ****
the function. */
ENUM_BITFIELD (escape_type) escape_mask : 9;
- /* Memory partition tag assigned to this symbol. */
- tree mpt;
-
- /* If this variable is a pointer P that has been dereferenced, this
- field is an artificial variable that represents the memory
- location *P. Every other pointer Q that is type-compatible with
- P will also have the same memory tag. If the variable is not a
- pointer or if it is never dereferenced, this must be NULL.
- FIXME, do we really need this here? How much slower would it be
- to convert to hash table? */
- tree symbol_mem_tag;
-
/* Used when going out of SSA form to indicate which partition this
variable represents storage for. */
unsigned partition;
--- 291,296 ----
*************** static inline function_ann_t function_an
*** 541,547 ****
static inline function_ann_t get_function_ann (tree);
static inline enum tree_ann_type ann_type (tree_ann_t);
static inline void update_stmt (gimple);
- static inline bitmap may_aliases (const_tree);
static inline int get_lineno (const_gimple);
/*---------------------------------------------------------------------------
--- 431,436 ----
*************** extern void dump_points_to_info (FILE *)
*** 817,841 ****
extern void debug_points_to_info (void);
extern void dump_points_to_info_for (FILE *, tree);
extern void debug_points_to_info_for (tree);
- extern bool may_be_aliased (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 new_type_alias (tree, tree, 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 *);
- extern tree create_tag_raw (enum tree_code, tree, const char *);
- extern void delete_mem_ref_stats (struct function *);
- extern void dump_mem_ref_stats (FILE *);
- extern void debug_mem_ref_stats (void);
- extern void debug_memory_partitions (void);
- extern void debug_mem_sym_stats (tree var);
- extern void dump_mem_sym_stats_for_var (FILE *, tree);
- extern void debug_all_mem_sym_stats (void);
/* Call-back function for walk_use_def_chains(). At each reaching
definition, a function with this prototype is called. */
--- 706,720 ----
Index: alias-improvements/gcc/tree-into-ssa.c
===================================================================
*** alias-improvements.orig/gcc/tree-into-ssa.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-into-ssa.c 2008-11-26 13:48:08.000000000 +0100
*************** mark_sym_for_renaming (tree sym)
*** 2796,2806 ****
bitmap_set_bit (syms_to_rename, DECL_UID (sym));
if (!is_gimple_reg (sym))
! {
! need_to_update_vops_p = true;
! if (memory_partition (sym))
! bitmap_set_bit (syms_to_rename, DECL_UID (memory_partition (sym)));
! }
}
--- 2796,2802 ----
bitmap_set_bit (syms_to_rename, DECL_UID (sym));
if (!is_gimple_reg (sym))
! need_to_update_vops_p = true;
}
*************** update_ssa (unsigned update_flags)
*** 3217,3232 ****
tree sym = referenced_var (i);
if (is_gimple_reg (sym))
bitmap_set_bit (regs_to_rename, i);
- else
- {
- /* Memory partitioning information may have been
- computed after the symbol was marked for renaming,
- if SYM is inside a partition also mark the partition
- for renaming. */
- tree mpt = memory_partition (sym);
- if (mpt)
- bitmap_set_bit (syms_to_rename, DECL_UID (mpt));
- }
}
/* Memory symbols are those not in REGS_TO_RENAME. */
--- 3213,3218 ----
Index: alias-improvements/gcc/tree-outof-ssa.c
===================================================================
*** alias-improvements.orig/gcc/tree-outof-ssa.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-outof-ssa.c 2008-11-26 13:48:08.000000000 +0100
*************** create_temp (tree t)
*** 125,131 ****
/* add_referenced_var will create the annotation and set up some
of the flags in the annotation. However, some flags we need to
inherit from our original variable. */
- set_symbol_mem_tag (tmp, symbol_mem_tag (t));
if (is_call_clobbered (t))
mark_call_clobbered (tmp, var_ann (t)->escape_mask);
if (bitmap_bit_p (gimple_call_used_vars (cfun), DECL_UID (t)))
--- 125,130 ----
Index: alias-improvements/gcc/tree-predcom.c
===================================================================
*** alias-improvements.orig/gcc/tree-predcom.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-predcom.c 2008-11-26 13:48:08.000000000 +0100
*************** try_combine_chains (VEC (chain_p, heap)
*** 2423,2453 ****
}
}
- /* Sets alias information based on data reference DR for REF,
- if necessary. */
-
- static void
- set_alias_info (tree ref, struct data_reference *dr)
- {
- tree var;
- tree tag = DR_SYMBOL_TAG (dr);
-
- gcc_assert (tag != NULL_TREE);
-
- ref = get_base_address (ref);
- if (!ref || !INDIRECT_REF_P (ref))
- return;
-
- var = SSA_NAME_VAR (TREE_OPERAND (ref, 0));
- if (var_ann (var)->symbol_mem_tag)
- return;
-
- if (!MTAG_P (tag))
- new_type_alias (var, tag, ref);
- else
- var_ann (var)->symbol_mem_tag = tag;
- }
-
/* Prepare initializers for CHAIN in LOOP. Returns false if this is
impossible because one of these initializers may trap, true otherwise. */
--- 2423,2428 ----
*************** prepare_initializers_chain (struct loop
*** 2497,2503 ****
mark_virtual_ops_for_renaming_list (stmts);
gsi_insert_seq_on_edge_immediate (entry, stmts);
}
- set_alias_info (init, dr);
VEC_replace (tree, chain->inits, i, init);
}
--- 2472,2477 ----
Index: alias-improvements/gcc/tree-pretty-print.c
===================================================================
*** alias-improvements.orig/gcc/tree-pretty-print.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-pretty-print.c 2008-11-26 13:48:08.000000000 +0100
*************** dump_generic_node (pretty_printer *buffe
*** 882,894 ****
}
break;
- case SYMBOL_MEMORY_TAG:
- case NAME_MEMORY_TAG:
case VAR_DECL:
case PARM_DECL:
case FIELD_DECL:
case NAMESPACE_DECL:
- case MEMORY_PARTITION_TAG:
dump_decl_name (buffer, node, flags);
break;
--- 882,891 ----
Index: alias-improvements/gcc/tree-sra.c
===================================================================
*** alias-improvements.orig/gcc/tree-sra.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-sra.c 2008-11-26 13:48:08.000000000 +0100
*************** sra_walk_function (const struct sra_walk
*** 1056,1066 ****
ni = si;
gsi_next (&ni);
! /* If the statement has no virtual operands, then it doesn't
make any structure references that we care about. */
! if (gimple_aliases_computed_p (cfun)
! && ZERO_SSA_OPERANDS (stmt, (SSA_OP_VIRTUAL_DEFS | SSA_OP_VUSE)))
! continue;
switch (gimple_code (stmt))
{
--- 1056,1065 ----
ni = si;
gsi_next (&ni);
! /* If the statement does not reference memory, then it doesn't
make any structure references that we care about. */
! if (!gimple_references_memory_p (stmt))
! continue;
switch (gimple_code (stmt))
{
Index: alias-improvements/gcc/tree-ssa-ccp.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-ccp.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-ssa-ccp.c 2008-11-26 13:48:08.000000000 +0100
*************** tree
*** 273,280 ****
get_symbol_constant_value (tree sym)
{
if (TREE_STATIC (sym)
! && TREE_READONLY (sym)
! && !MTAG_P (sym))
{
tree val = DECL_INITIAL (sym);
if (val)
--- 273,279 ----
get_symbol_constant_value (tree sym)
{
if (TREE_STATIC (sym)
! && TREE_READONLY (sym))
{
tree val = DECL_INITIAL (sym);
if (val)
Index: alias-improvements/gcc/tree-ssa-copy.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-copy.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-ssa-copy.c 2008-11-26 13:48:08.000000000 +0100
*************** may_propagate_copy (tree dest, tree orig
*** 72,95 ****
if (TREE_CODE (dest) == SSA_NAME
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (dest))
return false;
-
- /* For memory partitions, copies are OK as long as the memory symbol
- belongs to the partition. */
- if (TREE_CODE (dest) == SSA_NAME
- && TREE_CODE (SSA_NAME_VAR (dest)) == MEMORY_PARTITION_TAG)
- return (TREE_CODE (orig) == SSA_NAME
- && !is_gimple_reg (orig)
- && (SSA_NAME_VAR (dest) == SSA_NAME_VAR (orig)
- || bitmap_bit_p (MPT_SYMBOLS (SSA_NAME_VAR (dest)),
- DECL_UID (SSA_NAME_VAR (orig)))));
-
- if (TREE_CODE (orig) == SSA_NAME
- && TREE_CODE (SSA_NAME_VAR (orig)) == MEMORY_PARTITION_TAG)
- return (TREE_CODE (dest) == SSA_NAME
- && !is_gimple_reg (dest)
- && (SSA_NAME_VAR (dest) == SSA_NAME_VAR (orig)
- || bitmap_bit_p (MPT_SYMBOLS (SSA_NAME_VAR (orig)),
- DECL_UID (SSA_NAME_VAR (dest)))));
/* Do not copy between types for which we *do* need a conversion. */
if (!useless_type_conversion_p (type_d, type_o))
--- 72,77 ----
*************** may_propagate_copy (tree dest, tree orig
*** 136,168 ****
&& POINTER_TYPE_P (type_d)
&& POINTER_TYPE_P (type_o))
{
! tree mt_dest = symbol_mem_tag (SSA_NAME_VAR (dest));
! tree mt_orig = symbol_mem_tag (SSA_NAME_VAR (orig));
! if (mt_dest && mt_orig && mt_dest != mt_orig)
! return false;
! else if (get_alias_set (TREE_TYPE (type_d)) !=
! get_alias_set (TREE_TYPE (type_o)))
return false;
! else if (!MTAG_P (SSA_NAME_VAR (dest))
! && !MTAG_P (SSA_NAME_VAR (orig))
! && (DECL_NO_TBAA_P (SSA_NAME_VAR (dest))
! != DECL_NO_TBAA_P (SSA_NAME_VAR (orig))))
return false;
-
- /* Also verify flow-sensitive information is compatible. */
- if (SSA_NAME_PTR_INFO (orig) && SSA_NAME_PTR_INFO (dest))
- {
- struct ptr_info_def *orig_ptr_info = SSA_NAME_PTR_INFO (orig);
- struct ptr_info_def *dest_ptr_info = SSA_NAME_PTR_INFO (dest);
-
- if (orig_ptr_info->name_mem_tag
- && dest_ptr_info->name_mem_tag
- && orig_ptr_info->pt_vars
- && dest_ptr_info->pt_vars
- && !bitmap_intersect_p (dest_ptr_info->pt_vars,
- orig_ptr_info->pt_vars))
- return false;
- }
}
/* If the destination is a SSA_NAME for a virtual operand, then we have
--- 118,129 ----
&& POINTER_TYPE_P (type_d)
&& POINTER_TYPE_P (type_o))
{
! if (get_alias_set (TREE_TYPE (type_d))
! != get_alias_set (TREE_TYPE (type_o)))
return false;
! else if (DECL_NO_TBAA_P (SSA_NAME_VAR (dest))
! != DECL_NO_TBAA_P (SSA_NAME_VAR (orig)))
return false;
}
/* If the destination is a SSA_NAME for a virtual operand, then we have
*************** may_propagate_copy (tree dest, tree orig
*** 176,183 ****
return true;
/* We have a "copy" from something like a constant into a virtual
! operand. Reject these. */
! return false;
}
/* Anything else is OK. */
--- 137,145 ----
return true;
/* We have a "copy" from something like a constant into a virtual
! operand. Reject these.
! ??? Funny. We should really never come along here. */
! gcc_unreachable ();
}
/* Anything else is OK. */
*************** may_propagate_copy_into_stmt (gimple des
*** 211,218 ****
is much simpler. */
if (TREE_CODE (orig) == SSA_NAME
! && (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (orig)
! || TREE_CODE (SSA_NAME_VAR (orig)) == MEMORY_PARTITION_TAG))
return false;
if (is_gimple_assign (dest))
--- 173,179 ----
is much simpler. */
if (TREE_CODE (orig) == SSA_NAME
! && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (orig))
return false;
if (is_gimple_assign (dest))
*************** may_propagate_copy_into_asm (tree dest)
*** 252,280 ****
void
merge_alias_info (tree orig_name, tree new_name)
{
- tree new_sym = SSA_NAME_VAR (new_name);
- tree orig_sym = SSA_NAME_VAR (orig_name);
- var_ann_t new_ann = var_ann (new_sym);
- var_ann_t orig_ann = var_ann (orig_sym);
-
- /* No merging necessary when memory partitions are involved. */
- if (factoring_name_p (new_name))
- {
- gcc_assert (!is_gimple_reg (orig_sym));
- return;
- }
- else if (factoring_name_p (orig_name))
- {
- gcc_assert (!is_gimple_reg (new_sym));
- return;
- }
-
gcc_assert (POINTER_TYPE_P (TREE_TYPE (orig_name))
&& POINTER_TYPE_P (TREE_TYPE (new_name)));
#if defined ENABLE_CHECKING
gcc_assert (useless_type_conversion_p (TREE_TYPE (orig_name),
! TREE_TYPE (new_name)));
/* Check that flow-sensitive information is compatible. Notice that
we may not merge flow-sensitive information here. This function
--- 213,225 ----
void
merge_alias_info (tree orig_name, tree new_name)
{
gcc_assert (POINTER_TYPE_P (TREE_TYPE (orig_name))
&& POINTER_TYPE_P (TREE_TYPE (new_name)));
#if defined ENABLE_CHECKING
gcc_assert (useless_type_conversion_p (TREE_TYPE (orig_name),
! TREE_TYPE (new_name)));
! #endif
/* Check that flow-sensitive information is compatible. Notice that
we may not merge flow-sensitive information here. This function
*************** merge_alias_info (tree orig_name, tree n
*** 290,347 ****
same in every block dominated by the predicate.
Since we cannot distinguish one case from another in this
! function, we can only make sure that if P_i and Q_j have
! flow-sensitive information, they should be compatible.
! As callers of merge_alias_info are supposed to call may_propagate_copy
! first, the following check is redundant. Thus, only do it if checking
! is enabled. */
! if (SSA_NAME_PTR_INFO (orig_name) && SSA_NAME_PTR_INFO (new_name))
! {
! struct ptr_info_def *orig_ptr_info = SSA_NAME_PTR_INFO (orig_name);
! struct ptr_info_def *new_ptr_info = SSA_NAME_PTR_INFO (new_name);
!
! /* Note that pointer NEW and ORIG may actually have different
! pointed-to variables (e.g., PR 18291 represented in
! testsuite/gcc.c-torture/compile/pr18291.c). However, since
! NEW is being copy-propagated into ORIG, it must always be
! true that the pointed-to set for pointer NEW is the same, or
! a subset, of the pointed-to set for pointer ORIG. If this
! isn't the case, we shouldn't have been able to do the
! propagation of NEW into ORIG. */
! if (orig_ptr_info->name_mem_tag
! && new_ptr_info->name_mem_tag
! && orig_ptr_info->pt_vars
! && new_ptr_info->pt_vars)
! gcc_assert (bitmap_intersect_p (new_ptr_info->pt_vars,
! orig_ptr_info->pt_vars));
! }
! #endif
!
! /* Synchronize the symbol tags. If both pointers had a tag and they
! are different, then something has gone wrong. Symbol tags can
! always be merged because they are flow insensitive, all the SSA
! names of the same base DECL share the same symbol tag. */
! if (new_ann->symbol_mem_tag == NULL_TREE)
! new_ann->symbol_mem_tag = orig_ann->symbol_mem_tag;
! else if (orig_ann->symbol_mem_tag == NULL_TREE)
! orig_ann->symbol_mem_tag = new_ann->symbol_mem_tag;
! else
! gcc_assert (new_ann->symbol_mem_tag == orig_ann->symbol_mem_tag);
!
! /* Copy flow-sensitive alias information in case that NEW_NAME
! didn't get a NMT but was set to pt_anything for optimization
! purposes. In case ORIG_NAME has a NMT we can safely use its
! flow-sensitive alias information as a conservative estimate. */
! if (SSA_NAME_PTR_INFO (orig_name)
! && SSA_NAME_PTR_INFO (orig_name)->name_mem_tag
! && (!SSA_NAME_PTR_INFO (new_name)
! || !SSA_NAME_PTR_INFO (new_name)->name_mem_tag))
! {
! struct ptr_info_def *orig_ptr_info = SSA_NAME_PTR_INFO (orig_name);
! struct ptr_info_def *new_ptr_info = get_ptr_info (new_name);
! memcpy (new_ptr_info, orig_ptr_info, sizeof (struct ptr_info_def));
! }
}
--- 235,246 ----
same in every block dominated by the predicate.
Since we cannot distinguish one case from another in this
! function, we cannot merge flow-sensitive information by
! intersecting. Instead the only thing we can do is to _not_
! merge flow-sensitive information.
! ??? At some point we should enhance this machinery to distinguish
! both cases in the caller. */
}
*************** copy_prop_visit_phi_node (gimple phi)
*** 864,871 ****
Otherwise, this may move loop variant variables outside of
their loops and prevent coalescing opportunities. If the
value was loop invariant, it will be hoisted by LICM and
! exposed for copy propagation. */
! if (loop_depth_of_name (arg) > loop_depth_of_name (lhs))
{
phi_val.value = lhs;
break;
--- 763,772 ----
Otherwise, this may move loop variant variables outside of
their loops and prevent coalescing opportunities. If the
value was loop invariant, it will be hoisted by LICM and
! exposed for copy propagation. Not a problem for virtual
! operands though. */
! if (is_gimple_reg (lhs)
! && loop_depth_of_name (arg) > loop_depth_of_name (lhs))
{
phi_val.value = lhs;
break;
Index: alias-improvements/gcc/tree-ssa-copyrename.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-copyrename.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-ssa-copyrename.c 2008-11-26 13:48:08.000000000 +0100
*************** copy_rename_partition_coalesce (var_map
*** 115,121 ****
int p1, p2, p3;
tree root1, root2;
tree rep1, rep2;
- var_ann_t ann1, ann2, ann3;
bool ign1, ign2, abnorm;
gcc_assert (TREE_CODE (var1) == SSA_NAME);
--- 115,120 ----
*************** copy_rename_partition_coalesce (var_map
*** 144,152 ****
root1 = SSA_NAME_VAR (rep1);
root2 = SSA_NAME_VAR (rep2);
- ann1 = var_ann (root1);
- ann2 = var_ann (root2);
-
if (p1 == p2)
{
if (debug)
--- 143,148 ----
*************** copy_rename_partition_coalesce (var_map
*** 207,222 ****
}
}
- /* Don't coalesce if there are two different memory tags. */
- if (ann1->symbol_mem_tag
- && ann2->symbol_mem_tag
- && ann1->symbol_mem_tag != ann2->symbol_mem_tag)
- {
- if (debug)
- fprintf (debug, " : 2 memory tags. No coalesce.\n");
- return false;
- }
-
/* If both values have default defs, we can't coalesce. If only one has a
tag, make sure that variable is the new root partition. */
if (gimple_default_def (cfun, root1))
--- 203,208 ----
*************** copy_rename_partition_coalesce (var_map
*** 252,259 ****
&& POINTER_TYPE_P (TREE_TYPE (root2))
&& ((get_alias_set (TREE_TYPE (TREE_TYPE (root1)))
!= get_alias_set (TREE_TYPE (TREE_TYPE (root2))))
! || ((DECL_P (root1) && !MTAG_P (root1))
! && (DECL_P (root2) && !MTAG_P (root2))
&& DECL_NO_TBAA_P (root1) != DECL_NO_TBAA_P (root2))))
{
if (debug)
--- 238,244 ----
&& POINTER_TYPE_P (TREE_TYPE (root2))
&& ((get_alias_set (TREE_TYPE (TREE_TYPE (root1)))
!= get_alias_set (TREE_TYPE (TREE_TYPE (root2))))
! || (DECL_P (root1) && DECL_P (root2)
&& DECL_NO_TBAA_P (root1) != DECL_NO_TBAA_P (root2))))
{
if (debug)
*************** copy_rename_partition_coalesce (var_map
*** 272,284 ****
else if (!ign1)
replace_ssa_name_symbol (partition_to_var (map, p3), root1);
- /* Update the various flag widgitry of the current base representative. */
- ann3 = var_ann (SSA_NAME_VAR (partition_to_var (map, p3)));
- if (ann1->symbol_mem_tag)
- ann3->symbol_mem_tag = ann1->symbol_mem_tag;
- else
- ann3->symbol_mem_tag = ann2->symbol_mem_tag;
-
if (debug)
{
fprintf (debug, " --> P%d ", p3);
--- 257,262 ----
Index: alias-improvements/gcc/tree-ssa-live.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-live.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-ssa-live.c 2008-11-26 13:48:08.000000000 +0100
*************** remove_unused_locals (void)
*** 702,712 ****
pass is performed. */
FOR_EACH_REFERENCED_VAR (t, rvi)
if (!is_global_var (t)
- && !MTAG_P (t)
&& TREE_CODE (t) != PARM_DECL
&& TREE_CODE (t) != RESULT_DECL
&& !(ann = var_ann (t))->used
- && !ann->symbol_mem_tag
&& !TREE_ADDRESSABLE (t)
&& (optimize || DECL_ARTIFICIAL (t)))
remove_referenced_var (t);
--- 702,710 ----
Index: alias-improvements/gcc/tree-ssa-loop-ivopts.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-loop-ivopts.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-ssa-loop-ivopts.c 2008-11-26 13:48:08.000000000 +0100
*************** unshare_and_remove_ssa_names (tree ref)
*** 5214,5276 ****
return ref;
}
- /* Extract the alias analysis info for the memory reference REF. There are
- several ways how this information may be stored and what precisely is
- its semantics depending on the type of the reference, but there always is
- somewhere hidden one _DECL node that is used to determine the set of
- virtual operands for the reference. The code below deciphers this jungle
- and extracts this single useful piece of information. */
-
- static tree
- get_ref_tag (tree ref, tree orig)
- {
- tree var = get_base_address (ref);
- tree aref = NULL_TREE, tag, sv;
- HOST_WIDE_INT offset, size, maxsize;
-
- for (sv = orig; handled_component_p (sv); sv = TREE_OPERAND (sv, 0))
- {
- aref = get_ref_base_and_extent (sv, &offset, &size, &maxsize);
- if (ref)
- break;
- }
-
- if (!var)
- return NULL_TREE;
-
- if (TREE_CODE (var) == INDIRECT_REF)
- {
- /* If the base is a dereference of a pointer, first check its name memory
- tag. If it does not have one, use its symbol memory tag. */
- var = TREE_OPERAND (var, 0);
- if (TREE_CODE (var) != SSA_NAME)
- return NULL_TREE;
-
- if (SSA_NAME_PTR_INFO (var))
- {
- tag = SSA_NAME_PTR_INFO (var)->name_mem_tag;
- if (tag)
- return tag;
- }
-
- var = SSA_NAME_VAR (var);
- tag = symbol_mem_tag (var);
- gcc_assert (tag != NULL_TREE);
- return tag;
- }
- else
- {
- if (!DECL_P (var))
- return NULL_TREE;
-
- tag = symbol_mem_tag (var);
- if (tag)
- return tag;
-
- return var;
- }
- }
-
/* Copies the reference information from OLD_REF to NEW_REF. */
static void
--- 5214,5219 ----
*************** copy_ref_info (tree new_ref, tree old_re
*** 5279,5288 ****
if (TREE_CODE (old_ref) == TARGET_MEM_REF)
copy_mem_ref_info (new_ref, old_ref);
else
! {
! TMR_ORIGINAL (new_ref) = unshare_and_remove_ssa_names (old_ref);
! TMR_TAG (new_ref) = get_ref_tag (old_ref, TMR_ORIGINAL (new_ref));
! }
}
/* Rewrites USE (address that is an iv) using candidate CAND. */
--- 5222,5228 ----
if (TREE_CODE (old_ref) == TARGET_MEM_REF)
copy_mem_ref_info (new_ref, old_ref);
else
! TMR_ORIGINAL (new_ref) = unshare_and_remove_ssa_names (old_ref);
}
/* Rewrites USE (address that is an iv) using candidate CAND. */
Index: alias-improvements/gcc/tree-ssa-operands.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-operands.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-ssa-operands.c 2008-11-26 13:48:08.000000000 +0100
*************** init_ssa_operands (void)
*** 408,414 ****
}
gcc_assert (gimple_ssa_operands (cfun)->operand_memory == NULL);
- gcc_assert (gimple_ssa_operands (cfun)->mpt_table == NULL);
gimple_ssa_operands (cfun)->operand_memory_index
= gimple_ssa_operands (cfun)->ssa_operand_mem_size;
gimple_ssa_operands (cfun)->ops_active = true;
--- 408,413 ----
*************** void
*** 425,432 ****
fini_ssa_operands (void)
{
struct ssa_operand_memory_d *ptr;
- unsigned ix;
- tree mpt;
if (!--n_initialized)
{
--- 424,429 ----
*************** fini_ssa_operands (void)
*** 453,468 ****
ggc_free (ptr);
}
- for (ix = 0;
- VEC_iterate (tree, gimple_ssa_operands (cfun)->mpt_table, ix, mpt);
- ix++)
- {
- if (mpt)
- BITMAP_FREE (MPT_SYMBOLS (mpt));
- }
-
- VEC_free (tree, heap, gimple_ssa_operands (cfun)->mpt_table);
-
gimple_ssa_operands (cfun)->ops_active = false;
if (!n_initialized)
--- 450,455 ----
*************** get_expr_operands (gimple stmt, tree *ex
*** 1419,1426 ****
return;
case SSA_NAME:
- case SYMBOL_MEMORY_TAG:
- case NAME_MEMORY_TAG:
add_stmt_operand (expr_p, stmt, flags);
return;
--- 1406,1411 ----
Index: alias-improvements/gcc/tree-ssa-operands.h
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-operands.h 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-ssa-operands.h 2008-11-26 13:48:08.000000000 +0100
*************** struct ssa_operands GTY(()) {
*** 131,137 ****
struct def_optype_d * GTY ((skip (""))) free_defs;
struct use_optype_d * GTY ((skip (""))) free_uses;
struct voptype_d * GTY ((skip (""))) vop_free_buckets[NUM_VOP_FREE_BUCKETS];
- VEC(tree,heap) * GTY ((skip (""))) mpt_table;
};
/* This represents the operand cache for a stmt. */
--- 131,136 ----
Index: alias-improvements/gcc/tree-ssa-phiprop.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-phiprop.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-ssa-phiprop.c 2008-11-26 13:48:08.000000000 +0100
*************** propagate_with_phi (basic_block bb, gimp
*** 229,236 ****
ssa_op_iter i;
bool phi_inserted;
! if (MTAG_P (SSA_NAME_VAR (ptr))
! || !POINTER_TYPE_P (TREE_TYPE (ptr))
|| !is_gimple_reg_type (TREE_TYPE (TREE_TYPE (ptr))))
return false;
--- 229,235 ----
ssa_op_iter i;
bool phi_inserted;
! if (!POINTER_TYPE_P (TREE_TYPE (ptr))
|| !is_gimple_reg_type (TREE_TYPE (TREE_TYPE (ptr))))
return false;
Index: alias-improvements/gcc/tree-ssa-structalias.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-structalias.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-ssa-structalias.c 2008-11-26 13:48:08.000000000 +0100
*************** find_func_aliases (gimple origt)
*** 3645,3650 ****
--- 3645,3652 ----
struct constraint_expr *c;
enum escape_type stmt_escape_type;
+ /* ??? Initialize pi->is_dereferenced here. */
+
/* Now build constraints expressions. */
if (gimple_code (t) == GIMPLE_PHI)
{
*************** find_func_aliases (gimple origt)
*** 3899,3910 ****
}
}
- /* After promoting variables and computing aliasing we will
- need to re-scan most statements. FIXME: Try to minimize the
- number of statements re-scanned. It's not really necessary to
- re-scan *all* statements. */
- if (!in_ipa_mode)
- gimple_set_modified (origt, true);
VEC_free (ce_s, heap, rhsc);
VEC_free (ce_s, heap, lhsc);
}
--- 3901,3906 ----
*************** var_can_have_subvars (const_tree v)
*** 4042,4048 ****
return false;
/* Non decls or memory tags can never have subvars. */
! if (!DECL_P (v) || MTAG_P (v))
return false;
/* Aggregates without overlapping fields can have subvars. */
--- 4038,4044 ----
return false;
/* Non decls or memory tags can never have subvars. */
! if (!DECL_P (v))
return false;
/* Aggregates without overlapping fields can have subvars. */
*************** shared_bitmap_add (bitmap pt_vars)
*** 4642,4648 ****
the from set. */
static void
! set_uids_in_ptset (tree ptr, bitmap into, bitmap from, bool is_derefed,
bool no_tbaa_pruning)
{
unsigned int i;
--- 4638,4645 ----
the from set. */
static void
! set_uids_in_ptset (tree ptr, bitmap into, bitmap from,
! struct ptr_info_def *pi,
bool no_tbaa_pruning)
{
unsigned int i;
*************** set_uids_in_ptset (tree ptr, bitmap into
*** 4663,4685 ****
|| TREE_CODE (vi->decl) == PARM_DECL
|| TREE_CODE (vi->decl) == RESULT_DECL)
{
! /* Just add VI->DECL to the alias set.
! Don't type prune artificial vars or points-to sets
for pointers that have not been dereferenced or with
type-based pruning disabled. */
! if (vi->is_artificial_var
! || !is_derefed
! || no_tbaa_pruning)
! bitmap_set_bit (into, DECL_UID (vi->decl));
! else
{
alias_set_type var_alias_set, mem_alias_set;
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))
! bitmap_set_bit (into, DECL_UID (vi->decl));
}
}
}
}
--- 4660,4685 ----
|| TREE_CODE (vi->decl) == PARM_DECL
|| TREE_CODE (vi->decl) == RESULT_DECL)
{
! /* Don't type prune artificial vars or points-to sets
for pointers that have not been dereferenced or with
type-based pruning disabled. */
! if (!vi->is_artificial_var
! && pi->is_dereferenced
! && !no_tbaa_pruning)
{
alias_set_type var_alias_set, mem_alias_set;
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))
! continue;
}
+
+ /* Add the decl to the points-to set. Note that the points-to
+ set contains global variables. */
+ bitmap_set_bit (into, DECL_UID (vi->decl));
+ if (is_global_var (vi->decl))
+ pi->pt_global_mem = true;
}
}
}
*************** find_what_p_points_to (tree p)
*** 4737,4745 ****
bitmap finished_solution;
bitmap result;
- if (!pi->memory_tag_needed)
- return false;
-
/* This variable may have been collapsed, let's get the real
variable. */
vi = get_varinfo (find (vi->id));
--- 4737,4742 ----
*************** find_what_p_points_to (tree p)
*** 4784,4790 ****
stats.points_to_sets_created++;
set_uids_in_ptset (p, finished_solution, vi->solution,
! pi->is_dereferenced,
vi->no_tbaa_pruning);
result = shared_bitmap_lookup (finished_solution);
--- 4781,4787 ----
stats.points_to_sets_created++;
set_uids_in_ptset (p, finished_solution, vi->solution,
! pi,
vi->no_tbaa_pruning);
result = shared_bitmap_lookup (finished_solution);
*************** init_alias_heapvars (void)
*** 5617,5623 ****
void
delete_alias_heapvars (void)
{
! htab_delete (heapvar_for_stmt);
heapvar_for_stmt = NULL;
}
--- 5614,5621 ----
void
delete_alias_heapvars (void)
{
! if (heapvar_for_stmt)
! htab_delete (heapvar_for_stmt);
heapvar_for_stmt = NULL;
}
Index: alias-improvements/gcc/tree-ssa-structalias.h
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-structalias.h 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-ssa-structalias.h 2008-11-26 13:48:08.000000000 +0100
*************** typedef struct constraint *constraint_t;
*** 26,32 ****
/* In tree-ssa-alias.c. */
enum escape_type is_escape_site (gimple);
- void update_mem_sym_stats_from_stmt (tree, gimple, long, long);
/* In tree-ssa-structalias.c. */
extern void compute_points_to_sets (void);
--- 26,31 ----
Index: alias-improvements/gcc/tree-ssa.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-ssa.c 2008-11-26 13:48:08.000000000 +0100
*************** error:
*** 511,629 ****
}
- static void
- verify_flow_insensitive_alias_info (void)
- {
- tree var;
- referenced_var_iterator rvi;
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- unsigned int j;
- bitmap aliases;
- tree alias;
- bitmap_iterator bi;
-
- if (!MTAG_P (var) || !MTAG_ALIASES (var))
- continue;
-
- aliases = MTAG_ALIASES (var);
-
- EXECUTE_IF_SET_IN_BITMAP (aliases, 0, j, bi)
- {
- alias = referenced_var (j);
-
- if (TREE_CODE (alias) != MEMORY_PARTITION_TAG
- && !may_be_aliased (alias))
- {
- error ("non-addressable variable inside an alias set");
- debug_variable (alias);
- goto err;
- }
- }
- }
-
- return;
-
- err:
- debug_variable (var);
- internal_error ("verify_flow_insensitive_alias_info failed");
- }
-
-
- static void
- verify_flow_sensitive_alias_info (void)
- {
- size_t i;
- tree ptr;
-
- for (i = 1; i < num_ssa_names; i++)
- {
- tree var;
- var_ann_t ann;
- struct ptr_info_def *pi;
-
-
- ptr = ssa_name (i);
- if (!ptr)
- continue;
-
- /* We only care for pointers that are actually referenced in the
- program. */
- if (!POINTER_TYPE_P (TREE_TYPE (ptr)) || !TREE_VISITED (ptr))
- continue;
-
- /* RESULT_DECL is special. If it's a GIMPLE register, then it
- is only written-to only once in the return statement.
- Otherwise, aggregate RESULT_DECLs may be written-to more than
- once in virtual operands. */
- var = SSA_NAME_VAR (ptr);
- if (TREE_CODE (var) == RESULT_DECL
- && is_gimple_reg (ptr))
- continue;
-
- pi = SSA_NAME_PTR_INFO (ptr);
- if (pi == NULL)
- continue;
-
- ann = var_ann (var);
- if (pi->memory_tag_needed && !pi->name_mem_tag && !ann->symbol_mem_tag)
- {
- error ("dereferenced pointers should have a name or a symbol tag");
- goto err;
- }
-
- if (pi->name_mem_tag
- && (pi->pt_vars == NULL || bitmap_empty_p (pi->pt_vars)))
- {
- error ("pointers with a memory tag, should have points-to sets");
- goto err;
- }
-
- if (pi->value_escapes_p
- && pi->escape_mask & ~ESCAPE_TO_RETURN
- && pi->name_mem_tag)
- {
- tree t = memory_partition (pi->name_mem_tag);
- if (t == NULL_TREE)
- t = pi->name_mem_tag;
-
- if (!is_call_clobbered (t))
- {
- error ("pointer escapes but its name tag is not call-clobbered");
- goto err;
- }
- }
- }
-
- return;
-
- err:
- debug_variable (ptr);
- internal_error ("verify_flow_sensitive_alias_info failed");
- }
-
-
/* Verify the consistency of call clobbering information. */
static void
--- 511,516 ----
*************** verify_call_clobbering (void)
*** 632,638 ****
unsigned int i;
bitmap_iterator bi;
tree var;
- referenced_var_iterator rvi;
/* At all times, the result of the call_clobbered flag should
match the result of the call_clobbered_vars bitmap. Verify both
--- 519,524 ----
*************** verify_call_clobbering (void)
*** 642,674 ****
EXECUTE_IF_SET_IN_BITMAP (gimple_call_clobbered_vars (cfun), 0, i, bi)
{
var = referenced_var (i);
!
! if (memory_partition (var))
! var = memory_partition (var);
!
! if (!MTAG_P (var) && !var_ann (var)->call_clobbered)
! {
! error ("variable in call_clobbered_vars but not marked "
! "call_clobbered");
! debug_variable (var);
! goto err;
! }
! }
!
! FOR_EACH_REFERENCED_VAR (var, rvi)
! {
! if (is_gimple_reg (var))
! continue;
!
! if (memory_partition (var))
! var = memory_partition (var);
!
! if (!MTAG_P (var)
! && var_ann (var)->call_clobbered
! && !bitmap_bit_p (gimple_call_clobbered_vars (cfun), DECL_UID (var)))
{
! error ("variable marked call_clobbered but not in "
! "call_clobbered_vars bitmap.");
debug_variable (var);
goto err;
}
--- 528,536 ----
EXECUTE_IF_SET_IN_BITMAP (gimple_call_clobbered_vars (cfun), 0, i, bi)
{
var = referenced_var (i);
! if (is_global_var (var))
{
! error ("global variable in call_clobbered_vars");
debug_variable (var);
goto err;
}
*************** verify_call_clobbering (void)
*** 681,739 ****
}
- /* Verify invariants in memory partitions. */
-
- static void
- verify_memory_partitions (void)
- {
- unsigned i;
- tree mpt;
- VEC(tree,heap) *mpt_table = gimple_ssa_operands (cfun)->mpt_table;
- struct pointer_set_t *partitioned_syms = pointer_set_create ();
-
- for (i = 0; VEC_iterate (tree, mpt_table, i, mpt); i++)
- {
- unsigned j;
- bitmap_iterator bj;
-
- if (MPT_SYMBOLS (mpt) == NULL)
- {
- error ("Memory partitions should have at least one symbol");
- debug_variable (mpt);
- goto err;
- }
-
- EXECUTE_IF_SET_IN_BITMAP (MPT_SYMBOLS (mpt), 0, j, bj)
- {
- tree var = referenced_var (j);
- if (pointer_set_insert (partitioned_syms, var))
- {
- error ("Partitioned symbols should belong to exactly one "
- "partition");
- debug_variable (var);
- goto err;
- }
- }
- }
-
- pointer_set_destroy (partitioned_syms);
-
- return;
-
- err:
- internal_error ("verify_memory_partitions failed");
- }
-
-
/* Verify the consistency of aliasing information. */
static void
verify_alias_info (void)
{
- verify_flow_sensitive_alias_info ();
verify_call_clobbering ();
- verify_flow_insensitive_alias_info ();
- verify_memory_partitions ();
}
--- 543,554 ----
*************** verify_ssa (bool check_modified_stmt)
*** 833,841 ****
base_address = get_base_address (lhs);
if (base_address
- && gimple_aliases_computed_p (cfun)
&& SSA_VAR_P (base_address)
- && !gimple_has_volatile_ops (stmt)
&& ZERO_SSA_OPERANDS (stmt, SSA_OP_VDEF))
{
error ("statement makes a memory store, but has no VDEFS");
--- 648,654 ----
*************** verify_ssa (bool check_modified_stmt)
*** 880,887 ****
}
/* Finally, verify alias information. */
! if (gimple_aliases_computed_p (cfun))
! verify_alias_info ();
free (definition_block);
--- 693,699 ----
}
/* Finally, verify alias information. */
! verify_alias_info ();
free (definition_block);
*************** delete_tree_ssa (void)
*** 1029,1041 ****
/* Remove annotations from every referenced local variable. */
FOR_EACH_REFERENCED_VAR (var, rvi)
{
! if (!MTAG_P (var)
! && (TREE_STATIC (var) || DECL_EXTERNAL (var)))
! {
! var_ann (var)->mpt = NULL_TREE;
! var_ann (var)->symbol_mem_tag = NULL_TREE;
! continue;
! }
if (var->base.ann)
ggc_free (var->base.ann);
var->base.ann = NULL;
--- 841,848 ----
/* Remove annotations from every referenced local variable. */
FOR_EACH_REFERENCED_VAR (var, rvi)
{
! if (is_global_var (var))
! continue;
if (var->base.ann)
ggc_free (var->base.ann);
var->base.ann = NULL;
*************** delete_tree_ssa (void)
*** 1050,1071 ****
if (ssa_operands_active ())
fini_ssa_operands ();
! cfun->gimple_df->global_var = NULL_TREE;
!
htab_delete (cfun->gimple_df->default_defs);
cfun->gimple_df->default_defs = NULL;
cfun->gimple_df->call_clobbered_vars = NULL;
cfun->gimple_df->call_used_vars = NULL;
cfun->gimple_df->addressable_vars = NULL;
cfun->gimple_df->modified_noreturn_calls = NULL;
- if (gimple_aliases_computed_p (cfun))
- {
- delete_alias_heapvars ();
- gcc_assert (!need_ssa_update_p ());
- }
- cfun->gimple_df->aliases_computed_p = false;
- delete_mem_ref_stats (cfun);
-
cfun->gimple_df = NULL;
/* We no longer need the edge variable maps. */
--- 857,870 ----
if (ssa_operands_active ())
fini_ssa_operands ();
! delete_alias_heapvars ();
!
htab_delete (cfun->gimple_df->default_defs);
cfun->gimple_df->default_defs = NULL;
cfun->gimple_df->call_clobbered_vars = NULL;
cfun->gimple_df->call_used_vars = NULL;
cfun->gimple_df->addressable_vars = NULL;
cfun->gimple_df->modified_noreturn_calls = NULL;
cfun->gimple_df = NULL;
/* We no longer need the edge variable maps. */
*************** warn_uninitialized_var (tree *tp, int *w
*** 1498,1505 ****
/* If there is not gimple stmt,
or alias information has not been computed,
then we cannot check VUSE ops. */
! if (data->stmt == NULL
! || !gimple_aliases_computed_p (cfun))
return NULL_TREE;
vuse = SINGLE_SSA_USE_OPERAND (data->stmt, SSA_OP_VUSE);
--- 1297,1303 ----
/* If there is not gimple stmt,
or alias information has not been computed,
then we cannot check VUSE ops. */
! if (data->stmt == NULL)
return NULL_TREE;
vuse = SINGLE_SSA_USE_OPERAND (data->stmt, SSA_OP_VUSE);
*************** execute_update_addresses_taken (void)
*** 1678,1687 ****
referenced_var_iterator rvi;
gimple_stmt_iterator gsi;
basic_block bb;
! bitmap addresses_taken = BITMAP_ALLOC (NULL);
bitmap not_reg_needs = BITMAP_ALLOC (NULL);
bool update_vops = false;
/* Collect into ADDRESSES_TAKEN all variables whose address is taken within
the function body. */
FOR_EACH_BB (bb)
--- 1476,1489 ----
referenced_var_iterator rvi;
gimple_stmt_iterator gsi;
basic_block bb;
! bitmap addresses_taken;
bitmap not_reg_needs = BITMAP_ALLOC (NULL);
bool update_vops = false;
+ /* Reset the addressable vars bitmap. */
+ addresses_taken = gimple_addressable_vars (cfun);
+ bitmap_clear (addresses_taken);
+
/* Collect into ADDRESSES_TAKEN all variables whose address is taken within
the function body. */
FOR_EACH_BB (bb)
*************** execute_update_addresses_taken (void)
*** 1738,1743 ****
--- 1540,1546 ----
if (TREE_ADDRESSABLE (var))
{
+ clear_call_clobbered (var);
TREE_ADDRESSABLE (var) = 0;
if (is_gimple_reg (var))
mark_sym_for_renaming (var);
*************** execute_update_addresses_taken (void)
*** 1777,1784 ****
if (gimple_references_memory_p (stmt))
update_stmt (stmt);
}
BITMAP_FREE (not_reg_needs);
! BITMAP_FREE (addresses_taken);
return 0;
}
--- 1580,1588 ----
if (gimple_references_memory_p (stmt))
update_stmt (stmt);
}
+
BITMAP_FREE (not_reg_needs);
!
return 0;
}
Index: alias-improvements/gcc/tree-tailcall.c
===================================================================
*** alias-improvements.orig/gcc/tree-tailcall.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-tailcall.c 2008-11-26 13:48:08.000000000 +0100
*************** suitable_for_tail_opt_p (void)
*** 135,149 ****
if (cfun->stdarg)
return false;
! /* No local variable nor structure field should be call-used. We
! ignore any kind of memory tag, as these are not real variables. */
!
FOR_EACH_REFERENCED_VAR (var, rvi)
{
if (!is_global_var (var)
! && !MTAG_P (var)
! && (gimple_aliases_computed_p (cfun)? is_call_used (var)
! : TREE_ADDRESSABLE (var)))
return false;
}
--- 135,145 ----
if (cfun->stdarg)
return false;
! /* No local variable nor structure field should be call-used. */
FOR_EACH_REFERENCED_VAR (var, rvi)
{
if (!is_global_var (var)
! && is_call_used (var))
return false;
}
*************** find_tail_calls (basic_block bb, struct
*** 409,419 ****
break;
}
! /* If the statement has virtual or volatile operands, fail. */
! if (!ZERO_SSA_OPERANDS (stmt, (SSA_OP_VUSE | SSA_OP_VIRTUAL_DEFS))
! || gimple_has_volatile_ops (stmt)
! || (!gimple_aliases_computed_p (cfun)
! && gimple_references_memory_p (stmt)))
return;
}
--- 405,413 ----
break;
}
! /* If the statement references memory or volatile operands, fail. */
! if (gimple_references_memory_p (stmt)
! || gimple_has_volatile_ops (stmt))
return;
}
Index: alias-improvements/gcc/tree-vect-transform.c
===================================================================
*** alias-improvements.orig/gcc/tree-vect-transform.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-vect-transform.c 2008-11-26 13:48:08.000000000 +0100
*************** vect_create_data_ref_ptr (gimple stmt, s
*** 1024,1030 ****
tree vectype = STMT_VINFO_VECTYPE (stmt_info);
tree vect_ptr_type;
tree vect_ptr;
- tree tag;
tree new_temp;
gimple vec_stmt;
gimple_seq new_stmt_list = NULL;
--- 1024,1029 ----
*************** vect_create_data_ref_ptr (gimple stmt, s
*** 1092,1110 ****
add_referenced_var (vect_ptr);
- /** (2) Add aliasing information to the new vector-pointer:
- (The points-to info (DR_PTR_INFO) may be defined later.) **/
-
- tag = DR_SYMBOL_TAG (dr);
- gcc_assert (tag);
-
- /* If tag is a variable (and NOT_A_TAG) than a new symbol memory
- tag must be created with tag added to its may alias list. */
- if (!MTAG_P (tag))
- new_type_alias (vect_ptr, tag, DR_REF (dr));
- else
- set_symbol_mem_tag (vect_ptr, tag);
-
/** Note: If the dataref is in an inner-loop nested in LOOP, and we are
vectorizing LOOP (i.e. outer-loop vectorization), we need to create two
def-use update cycles for the pointer: One relative to the outer-loop
--- 1091,1096 ----
Index: alias-improvements/gcc/tree.c
===================================================================
*** alias-improvements.orig/gcc/tree.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree.c 2008-11-26 13:48:08.000000000 +0100
*************** init_ttree (void)
*** 320,334 ****
tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_MINIMAL] = 1;
tree_contains_struct[LABEL_DECL][TS_DECL_MINIMAL] = 1;
tree_contains_struct[FIELD_DECL][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[NAME_MEMORY_TAG][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[SYMBOL_MEMORY_TAG][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[MEMORY_PARTITION_TAG][TS_DECL_MINIMAL] = 1;
-
- tree_contains_struct[NAME_MEMORY_TAG][TS_MEMORY_TAG] = 1;
- tree_contains_struct[SYMBOL_MEMORY_TAG][TS_MEMORY_TAG] = 1;
- tree_contains_struct[MEMORY_PARTITION_TAG][TS_MEMORY_TAG] = 1;
-
- tree_contains_struct[MEMORY_PARTITION_TAG][TS_MEMORY_PARTITION_TAG] = 1;
tree_contains_struct[VAR_DECL][TS_DECL_WITH_VIS] = 1;
tree_contains_struct[FUNCTION_DECL][TS_DECL_WITH_VIS] = 1;
--- 320,325 ----
*************** tree_code_size (enum tree_code code)
*** 465,475 ****
return sizeof (struct tree_type_decl);
case FUNCTION_DECL:
return sizeof (struct tree_function_decl);
- case NAME_MEMORY_TAG:
- case SYMBOL_MEMORY_TAG:
- return sizeof (struct tree_memory_tag);
- case MEMORY_PARTITION_TAG:
- return sizeof (struct tree_memory_partition_tag);
default:
return sizeof (struct tree_decl_non_common);
}
--- 456,461 ----
*************** tree_node_structure (const_tree t)
*** 2399,2408 ****
return TS_TYPE_DECL;
case FUNCTION_DECL:
return TS_FUNCTION_DECL;
- case SYMBOL_MEMORY_TAG:
- case NAME_MEMORY_TAG:
- case MEMORY_PARTITION_TAG:
- return TS_MEMORY_TAG;
default:
return TS_DECL_NON_COMMON;
}
--- 2385,2390 ----
*************** build5_stat (enum tree_code code, tree t
*** 3423,3431 ****
}
tree
! build7_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
! tree arg2, tree arg3, tree arg4, tree arg5,
! tree arg6 MEM_STAT_DECL)
{
bool constant, read_only, side_effects;
tree t;
--- 3405,3412 ----
}
tree
! build6_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
! tree arg2, tree arg3, tree arg4, tree arg5 MEM_STAT_DECL)
{
bool constant, read_only, side_effects;
tree t;
*************** build7_stat (enum tree_code code, tree t
*** 3443,3449 ****
PROCESS_ARG(3);
PROCESS_ARG(4);
PROCESS_ARG(5);
- PROCESS_ARG(6);
TREE_SIDE_EFFECTS (t) = side_effects;
TREE_THIS_VOLATILE (t) = 0;
--- 3424,3429 ----
Index: alias-improvements/gcc/tree.h
===================================================================
*** alias-improvements.orig/gcc/tree.h 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree.h 2008-11-26 13:48:08.000000000 +0100
*************** extern const enum tree_code_class tree_c
*** 105,118 ****
#define DECL_P(CODE)\
(TREE_CODE_CLASS (TREE_CODE (CODE)) == tcc_declaration)
- /* Nonzero if CODE represents a memory tag. */
-
- #define MTAG_P(CODE) \
- (TREE_CODE (CODE) == NAME_MEMORY_TAG \
- || TREE_CODE (CODE) == SYMBOL_MEMORY_TAG \
- || TREE_CODE (CODE) == MEMORY_PARTITION_TAG)
-
-
/* Nonzero if DECL represents a VAR_DECL or FUNCTION_DECL. */
#define VAR_OR_FUNCTION_DECL_P(DECL)\
--- 105,110 ----
*************** extern void omp_clause_range_check_faile
*** 933,939 ****
#define TYPE_CHECK(T) TREE_CLASS_CHECK (T, tcc_type)
#define DECL_MINIMAL_CHECK(T) CONTAINS_STRUCT_CHECK (T, TS_DECL_MINIMAL)
- #define TREE_MEMORY_TAG_CHECK(T) CONTAINS_STRUCT_CHECK (T, TS_MEMORY_TAG)
#define DECL_COMMON_CHECK(T) CONTAINS_STRUCT_CHECK (T, TS_DECL_COMMON)
#define DECL_WRTL_CHECK(T) CONTAINS_STRUCT_CHECK (T, TS_DECL_WRTL)
#define DECL_WITH_VIS_CHECK(T) CONTAINS_STRUCT_CHECK (T, TS_DECL_WITH_VIS)
--- 925,930 ----
*************** extern void protected_set_expr_location
*** 1611,1617 ****
#define TMR_STEP(NODE) (TREE_OPERAND (TARGET_MEM_REF_CHECK (NODE), 3))
#define TMR_OFFSET(NODE) (TREE_OPERAND (TARGET_MEM_REF_CHECK (NODE), 4))
#define TMR_ORIGINAL(NODE) (TREE_OPERAND (TARGET_MEM_REF_CHECK (NODE), 5))
- #define TMR_TAG(NODE) (TREE_OPERAND (TARGET_MEM_REF_CHECK (NODE), 6))
/* The operands of a BIND_EXPR. */
#define BIND_EXPR_VARS(NODE) (TREE_OPERAND (BIND_EXPR_CHECK (NODE), 0))
--- 1602,1607 ----
*************** struct tree_binfo GTY (())
*** 2430,2441 ****
(TREE_CODE (DECL) == VAR_DECL \
|| TREE_CODE (DECL) == PARM_DECL \
|| TREE_CODE (DECL) == RESULT_DECL \
- || MTAG_P (DECL) \
|| (TREE_CODE (DECL) == SSA_NAME \
&& (TREE_CODE (SSA_NAME_VAR (DECL)) == VAR_DECL \
|| TREE_CODE (SSA_NAME_VAR (DECL)) == PARM_DECL \
! || TREE_CODE (SSA_NAME_VAR (DECL)) == RESULT_DECL \
! || MTAG_P (SSA_NAME_VAR (DECL)))))
--- 2420,2429 ----
(TREE_CODE (DECL) == VAR_DECL \
|| TREE_CODE (DECL) == PARM_DECL \
|| TREE_CODE (DECL) == RESULT_DECL \
|| (TREE_CODE (DECL) == SSA_NAME \
&& (TREE_CODE (SSA_NAME_VAR (DECL)) == VAR_DECL \
|| TREE_CODE (SSA_NAME_VAR (DECL)) == PARM_DECL \
! || TREE_CODE (SSA_NAME_VAR (DECL)) == RESULT_DECL)))
*************** struct tree_decl_minimal GTY(())
*** 2490,2538 ****
tree context;
};
- /* When computing aliasing information, we represent the memory pointed-to
- by pointers with artificial variables called "memory tags" (MT). There
- are two kinds of tags, namely symbol and name:
-
- Symbol tags (SMT) are used in flow-insensitive alias analysis, they
- represent all the pointed-to locations and variables pointed-to by
- the same pointer symbol. Usually, this set is computed using
- type-based analysis (i.e., alias set classes), but this may not
- always be the case.
-
- Name tags (NMT) are used in flow-sensitive points-to alias
- analysis, they represent the variables and memory locations
- pointed-to by a specific SSA_NAME pointer.
-
- In general, given a pointer P with a symbol tag SMT, the alias set
- of SMT should be the union of all the alias sets of the NMTs of
- every SSA_NAME for P. */
- struct tree_memory_tag GTY(())
- {
- struct tree_decl_minimal common;
-
- bitmap GTY ((skip)) aliases;
-
- /* True if this tag has global scope. */
- unsigned int is_global : 1;
- };
-
- #define MTAG_GLOBAL(NODE) (TREE_MEMORY_TAG_CHECK (NODE)->mtag.is_global)
- #define MTAG_ALIASES(NODE) (TREE_MEMORY_TAG_CHECK (NODE)->mtag.aliases)
-
- /* Memory Partition Tags (MPTs) group memory symbols under one
- common name for the purposes of placing memory PHI nodes. */
-
- struct tree_memory_partition_tag GTY(())
- {
- struct tree_memory_tag common;
-
- /* Set of symbols grouped under this MPT. */
- bitmap symbols;
- };
-
- #define MPT_SYMBOLS(NODE) (MEMORY_PARTITION_TAG_CHECK (NODE)->mpt.symbols)
-
/* For any sort of a ..._DECL node, this points to the original (abstract)
decl node which this decl is an instance of, or else it is NULL indicating
--- 2478,2483 ----
*************** union tree_node GTY ((ptr_alias (union l
*** 3444,3452 ****
struct tree_binfo GTY ((tag ("TS_BINFO"))) binfo;
struct tree_statement_list GTY ((tag ("TS_STATEMENT_LIST"))) stmt_list;
struct tree_constructor GTY ((tag ("TS_CONSTRUCTOR"))) constructor;
- struct tree_memory_tag GTY ((tag ("TS_MEMORY_TAG"))) mtag;
struct tree_omp_clause GTY ((tag ("TS_OMP_CLAUSE"))) omp_clause;
- struct tree_memory_partition_tag GTY ((tag ("TS_MEMORY_PARTITION_TAG"))) mpt;
struct tree_optimization_option GTY ((tag ("TS_OPTIMIZATION"))) optimization;
struct tree_target_option GTY ((tag ("TS_TARGET_OPTION"))) target_option;
};
--- 3389,3395 ----
*************** extern tree build4_stat (enum tree_code,
*** 3938,3947 ****
extern tree build5_stat (enum tree_code, tree, tree, tree, tree, tree,
tree MEM_STAT_DECL);
#define build5(c,t1,t2,t3,t4,t5,t6) build5_stat (c,t1,t2,t3,t4,t5,t6 MEM_STAT_INFO)
! extern tree build7_stat (enum tree_code, tree, tree, tree, tree, tree,
! tree, tree, tree MEM_STAT_DECL);
! #define build7(c,t1,t2,t3,t4,t5,t6,t7,t8) \
! build7_stat (c,t1,t2,t3,t4,t5,t6,t7,t8 MEM_STAT_INFO)
extern tree build_int_cst (tree, HOST_WIDE_INT);
extern tree build_int_cst_type (tree, HOST_WIDE_INT);
--- 3881,3890 ----
extern tree build5_stat (enum tree_code, tree, tree, tree, tree, tree,
tree MEM_STAT_DECL);
#define build5(c,t1,t2,t3,t4,t5,t6) build5_stat (c,t1,t2,t3,t4,t5,t6 MEM_STAT_INFO)
! extern tree build6_stat (enum tree_code, tree, tree, tree, tree, tree,
! tree, tree MEM_STAT_DECL);
! #define build6(c,t1,t2,t3,t4,t5,t6,t7) \
! build6_stat (c,t1,t2,t3,t4,t5,t6,t7 MEM_STAT_INFO)
extern tree build_int_cst (tree, HOST_WIDE_INT);
extern tree build_int_cst_type (tree, HOST_WIDE_INT);
Index: alias-improvements/gcc/treestruct.def
===================================================================
*** alias-improvements.orig/gcc/treestruct.def 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/treestruct.def 2008-11-26 13:48:08.000000000 +0100
*************** DEFTREESTRUCT(TS_BINFO, "binfo")
*** 60,68 ****
DEFTREESTRUCT(TS_STATEMENT_LIST, "statement list")
DEFTREESTRUCT(TS_GIMPLE_STATEMENT, "gimple statement")
DEFTREESTRUCT(TS_CONSTRUCTOR, "constructor")
- DEFTREESTRUCT(TS_MEMORY_TAG, "memory tag")
DEFTREESTRUCT(TS_OMP_CLAUSE, "omp clause")
- DEFTREESTRUCT(TS_MEMORY_PARTITION_TAG, "memory partition tag")
DEFTREESTRUCT(TS_OPTIMIZATION, "optimization options")
DEFTREESTRUCT(TS_TARGET_OPTION, "target options")
--- 60,66 ----
Index: alias-improvements/gcc/tree-ssa-alias-warnings.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-alias-warnings.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-ssa-alias-warnings.c 2008-11-26 13:48:08.000000000 +0100
*************** build_reference_table (void)
*** 475,496 ****
pi = SSA_NAME_PTR_INFO (ptr);
! if (!SSA_NAME_IN_FREE_LIST (ptr) && pi && pi->name_mem_tag)
{
/* Add pointer to the interesting dereference list. */
add_key (ref_table->ptrs, ptr, references_pool);
/* Add all aliased names to the interesting reference list. */
! if (pi->pt_vars)
{
! unsigned ix;
! bitmap_iterator bi;
!
! EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, ix, bi)
! {
! tree alias = referenced_var (ix);
! add_key (ref_table->objs, alias, references_pool);
! }
}
}
}
--- 475,494 ----
pi = SSA_NAME_PTR_INFO (ptr);
! if (!SSA_NAME_IN_FREE_LIST (ptr)
! && pi && pi->pt_vars)
{
+ unsigned ix;
+ bitmap_iterator bi;
+
/* Add pointer to the interesting dereference list. */
add_key (ref_table->ptrs, ptr, references_pool);
/* Add all aliased names to the interesting reference list. */
! EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, ix, bi)
{
! tree alias = referenced_var (ix);
! add_key (ref_table->objs, alias, references_pool);
}
}
}
*************** ffan_walker (tree *t,
*** 670,676 ****
int *go_below ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED)
{
! if (DECL_P (*t) && !MTAG_P (*t) && DECL_ARTIFICIAL (*t))
return *t;
else
return NULL_TREE;
--- 668,674 ----
int *go_below ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED)
{
! if (DECL_P (*t) && DECL_ARTIFICIAL (*t))
return *t;
else
return NULL_TREE;
*************** detect_strict_aliasing_named (void)
*** 990,996 ****
pi = SSA_NAME_PTR_INFO (ptr);
! if (!SSA_NAME_IN_FREE_LIST (ptr) && pi && pi->name_mem_tag)
dsa_named_for (ptr);
}
}
--- 988,994 ----
pi = SSA_NAME_PTR_INFO (ptr);
! if (!SSA_NAME_IN_FREE_LIST (ptr) && pi && pi->pt_vars)
dsa_named_for (ptr);
}
}
Index: alias-improvements/gcc/tree-data-ref.h
===================================================================
*** alias-improvements.orig/gcc/tree-data-ref.h 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-data-ref.h 2008-11-26 13:48:08.000000000 +0100
*************** struct dr_alias
*** 87,93 ****
{
/* The alias information that should be used for new pointers to this
location. SYMBOL_TAG is either a DECL or a SYMBOL_MEMORY_TAG. */
- tree symbol_tag;
struct ptr_info_def *ptr_info;
/* The set of virtual operands corresponding to this memory reference,
--- 87,92 ----
*************** struct data_reference
*** 203,211 ****
#define DR_OFFSET(DR) (DR)->innermost.offset
#define DR_INIT(DR) (DR)->innermost.init
#define DR_STEP(DR) (DR)->innermost.step
- #define DR_SYMBOL_TAG(DR) (DR)->alias.symbol_tag
#define DR_PTR_INFO(DR) (DR)->alias.ptr_info
- #define DR_VOPS(DR) (DR)->alias.vops
#define DR_ALIGNED_TO(DR) (DR)->innermost.aligned_to
#define DR_ACCESS_MATRIX(DR) (DR)->access_matrix
--- 202,208 ----
Index: alias-improvements/gcc/tree-ssa-address.c
===================================================================
*** alias-improvements.orig/gcc/tree-ssa-address.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-ssa-address.c 2008-11-26 13:48:08.000000000 +0100
*************** create_mem_ref_raw (tree type, struct me
*** 333,341 ****
if (addr->offset && integer_zerop (addr->offset))
addr->offset = NULL_TREE;
! return build7 (TARGET_MEM_REF, type,
addr->symbol, addr->base, addr->index,
! addr->step, addr->offset, NULL, NULL);
}
/* Returns true if OBJ is an object whose address is a link time constant. */
--- 333,341 ----
if (addr->offset && integer_zerop (addr->offset))
addr->offset = NULL_TREE;
! return build6 (TARGET_MEM_REF, type,
addr->symbol, addr->base, addr->index,
! addr->step, addr->offset, NULL);
}
/* Returns true if OBJ is an object whose address is a link time constant. */
*************** get_address_description (tree op, struct
*** 709,717 ****
void
copy_mem_ref_info (tree to, tree from)
{
- /* Copy the annotation, to preserve the aliasing information. */
- TMR_TAG (to) = TMR_TAG (from);
-
/* And the info about the original reference. */
TMR_ORIGINAL (to) = TMR_ORIGINAL (from);
}
--- 709,714 ----
Index: alias-improvements/gcc/tree-vect-analyze.c
===================================================================
*** alias-improvements.orig/gcc/tree-vect-analyze.c 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree-vect-analyze.c 2008-11-26 13:48:08.000000000 +0100
*************** vect_analyze_data_refs (loop_vec_info lo
*** 3563,3578 ****
return false;
}
- if (!DR_SYMBOL_TAG (dr))
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
- {
- fprintf (vect_dump, "not vectorized: no memory tag for ");
- print_generic_expr (vect_dump, DR_REF (dr), TDF_SLIM);
- }
- return false;
- }
-
base = unshare_expr (DR_BASE_ADDRESS (dr));
offset = unshare_expr (DR_OFFSET (dr));
init = unshare_expr (DR_INIT (dr));
--- 3563,3568 ----
Index: alias-improvements/gcc/tree.def
===================================================================
*** alias-improvements.orig/gcc/tree.def 2008-11-26 13:47:02.000000000 +0100
--- alias-improvements/gcc/tree.def 2008-11-26 13:48:08.000000000 +0100
*************** DEFTREECODE (PARM_DECL, "parm_decl", tcc
*** 362,373 ****
DEFTREECODE (TYPE_DECL, "type_decl", tcc_declaration, 0)
DEFTREECODE (RESULT_DECL, "result_decl", tcc_declaration, 0)
- /* Memory tags used in tree-ssa to represent memory locations in
- virtual SSA. */
- DEFTREECODE (NAME_MEMORY_TAG, "name_memory_tag", tcc_declaration, 0)
- DEFTREECODE (SYMBOL_MEMORY_TAG, "symbol_memory_tag", tcc_declaration, 0)
- DEFTREECODE (MEMORY_PARTITION_TAG, "memory_partition_tag", tcc_declaration, 0)
-
/* A namespace declaration. Namespaces appear in DECL_CONTEXT of other
_DECLs, providing a hierarchy of names. */
DEFTREECODE (NAMESPACE_DECL, "namespace_decl", tcc_declaration, 0)
--- 362,367 ----
*************** DEFTREECODE (REALIGN_LOAD_EXPR, "realign
*** 980,989 ****
sizetype or a pointer type (if SYMBOL is NULL).
The sixth argument is the reference to the original memory access, which
! is preserved for the purposes of the RTL alias analysis. The seventh
! argument is a tag representing results of the tree level alias analysis. */
! DEFTREECODE (TARGET_MEM_REF, "target_mem_ref", tcc_reference, 7)
/* The ordering of the codes between OMP_PARALLEL and OMP_CRITICAL is
exposed to TREE_RANGE_CHECK. */
--- 974,982 ----
sizetype or a pointer type (if SYMBOL is NULL).
The sixth argument is the reference to the original memory access, which
! is preserved for the purposes of the RTL alias analysis. */
! DEFTREECODE (TARGET_MEM_REF, "target_mem_ref", tcc_reference, 6)
/* The ordering of the codes between OMP_PARALLEL and OMP_CRITICAL is
exposed to TREE_RANGE_CHECK. */