summaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-loop-im.c
diff options
context:
space:
mode:
authordnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4>2013-03-26 10:33:36 +0000
committerdnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4>2013-03-26 10:33:36 +0000
commita63f89638edc7c3120e52faf6815bfe3e9b270e2 (patch)
tree61b7552b10852929b89f1cb93878fadffc1885c2 /gcc/tree-ssa-loop-im.c
parent9402409a6bd0d7d1f7358793f768bda3ec8a9574 (diff)
parent087a99ba8749638f86c111f776ed326b3fbd97c0 (diff)
downloadgcc-cxx-conversion.tar.gz
Merged revisions 196607-196608,196611-196614,196625,196629-196634,196636,196639,196645-196647,196649-196650,196654-196659,196666,196669,196671-196675,196682-196683,196694-196695,196697-196698,196700-196701,196704-196706,196709,196721-196748,196750-196751,196753,196755-196758,196762,196764-196765,196767-196771,196773-196779,196781-196784,196788-196792,196795-196797,196799-196800,196804-196807,196810-196814,196821,196823-196825,196828-196829,196831-196832,196834,196841-196842,196847-196853,196855-196856,196858,196860-196861,196864-196866,196868,196870-196872,196874,196876,196878-196879,196882,196884-196890,196896-196897,196899-196902,196954,196956-196961,196964-196965,196970,196977-196978,196981-196983,196989,197002-197005,197007,197011-197012,197016-197019,197021,197023-197025,197029-197034,197036-197042 via svnmerge from cxx-conversion
svn+ssh://gcc.gnu.org/svn/gcc/trunk git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/cxx-conversion@197098 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-ssa-loop-im.c')
-rw-r--r--gcc/tree-ssa-loop-im.c786
1 files changed, 378 insertions, 408 deletions
diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c
index 99226a67ae7..7ee00d6f585 100644
--- a/gcc/tree-ssa-loop-im.c
+++ b/gcc/tree-ssa-loop-im.c
@@ -58,15 +58,6 @@ along with GCC; see the file COPYING3. If not see
something;
} */
-/* A type for the list of statements that have to be moved in order to be able
- to hoist an invariant computation. */
-
-struct depend
-{
- gimple stmt;
- struct depend *next;
-};
-
/* The auxiliary data kept for each statement. */
struct lim_aux_data
@@ -85,11 +76,11 @@ struct lim_aux_data
unsigned cost; /* Cost of the computation performed by the
statement. */
- struct depend *depends; /* List of statements that must be also hoisted
- out of the loop when this statement is
- hoisted; i.e. those that define the operands
- of the statement and are inside of the
- MAX_LOOP loop. */
+ vec<gimple> depends; /* Vector of statements that must be also
+ hoisted out of the loop when this statement
+ is hoisted; i.e. those that define the
+ operands of the statement and are inside of
+ the MAX_LOOP loop. */
};
/* Maps statements to their lim_aux_data. */
@@ -105,45 +96,42 @@ typedef struct mem_ref_loc
} *mem_ref_loc_p;
-/* The list of memory reference locations in a loop. */
-
-typedef struct mem_ref_locs
-{
- vec<mem_ref_loc_p> locs;
-} *mem_ref_locs_p;
-
-
/* Description of a memory reference. */
typedef struct mem_ref
{
- tree mem; /* The memory itself. */
unsigned id; /* ID assigned to the memory reference
(its index in memory_accesses.refs_list) */
hashval_t hash; /* Its hash value. */
- bitmap stored; /* The set of loops in that this memory location
+
+ /* The memory access itself and associated caching of alias-oracle
+ query meta-data. */
+ ao_ref mem;
+
+ bitmap_head stored; /* The set of loops in that this memory location
is stored to. */
- vec<mem_ref_locs_p> accesses_in_loop;
+ vec<vec<mem_ref_loc> > accesses_in_loop;
/* The locations of the accesses. Vector
indexed by the loop number. */
/* The following sets are computed on demand. We keep both set and
its complement, so that we know whether the information was
already computed or not. */
- bitmap indep_loop; /* The set of loops in that the memory
+ bitmap_head indep_loop; /* The set of loops in that the memory
reference is independent, meaning:
If it is stored in the loop, this store
is independent on all other loads and
stores.
If it is only loaded, then it is independent
on all stores in the loop. */
- bitmap dep_loop; /* The complement of INDEP_LOOP. */
-
- bitmap indep_ref; /* The set of memory references on that
- this reference is independent. */
- bitmap dep_ref; /* The complement of INDEP_REF. */
+ bitmap_head dep_loop; /* The complement of INDEP_LOOP. */
} *mem_ref_p;
+/* We use two bits per loop in the ref->{in,}dep_loop bitmaps, the first
+ to record (in)dependence against stores in the loop and its subloops, the
+ second to record (in)dependence against all references in the loop
+ and its subloops. */
+#define LOOP_DEP_BIT(loopnum, storedp) (2 * (loopnum) + (storedp ? 1 : 0))
/* Mem_ref hashtable helpers. */
@@ -169,7 +157,7 @@ mem_ref_hasher::hash (const value_type *mem)
inline bool
mem_ref_hasher::equal (const value_type *mem1, const compare_type *obj2)
{
- return operand_equal_p (mem1->mem, obj2, 0);
+ return operand_equal_p (mem1->mem.ref, (const_tree) obj2, 0);
}
@@ -184,15 +172,13 @@ static struct
vec<mem_ref_p> refs_list;
/* The set of memory references accessed in each loop. */
- vec<bitmap> refs_in_loop;
+ vec<bitmap_head> refs_in_loop;
- /* The set of memory references accessed in each loop, including
- subloops. */
- vec<bitmap> all_refs_in_loop;
+ /* The set of memory references stored in each loop. */
+ vec<bitmap_head> refs_stored_in_loop;
- /* The set of memory references stored in each loop, including
- subloops. */
- vec<bitmap> all_refs_stored_in_loop;
+ /* The set of memory references stored in each loop, including subloops . */
+ vec<bitmap_head> all_refs_stored_in_loop;
/* Cache for expanding memory addresses. */
struct pointer_map_t *ttae_cache;
@@ -211,8 +197,11 @@ static bool ref_indep_loop_p (struct loop *, mem_ref_p);
#define ALWAYS_EXECUTED_IN(BB) ((struct loop *) (BB)->aux)
#define SET_ALWAYS_EXECUTED_IN(BB, VAL) ((BB)->aux = (void *) (VAL))
+/* ID of the shared unanalyzable mem. */
+#define UNANALYZABLE_MEM_ID 0
+
/* Whether the reference was analyzable. */
-#define MEM_ANALYZABLE(REF) ((REF)->mem != error_mark_node)
+#define MEM_ANALYZABLE(REF) ((REF)->id != UNANALYZABLE_MEM_ID)
static struct lim_aux_data *
init_lim_data (gimple stmt)
@@ -238,13 +227,7 @@ get_lim_data (gimple stmt)
static void
free_lim_aux_data (struct lim_aux_data *data)
{
- struct depend *dep, *next;
-
- for (dep = data->depends; dep; dep = next)
- {
- next = dep->next;
- free (dep);
- }
+ data->depends.release();
free (data);
}
@@ -509,7 +492,6 @@ add_dependency (tree def, struct lim_aux_data *data, struct loop *loop,
gimple def_stmt = SSA_NAME_DEF_STMT (def);
basic_block def_bb = gimple_bb (def_stmt);
struct loop *max_loop;
- struct depend *dep;
struct lim_aux_data *def_data;
if (!def_bb)
@@ -534,10 +516,7 @@ add_dependency (tree def, struct lim_aux_data *data, struct loop *loop,
&& def_bb->loop_father == loop)
data->cost += def_data->cost;
- dep = XNEW (struct depend);
- dep->stmt = def_stmt;
- dep->next = data->depends;
- data->depends = dep;
+ data->depends.safe_push (def_stmt);
return true;
}
@@ -631,13 +610,13 @@ outermost_indep_loop (struct loop *outer, struct loop *loop, mem_ref_p ref)
{
struct loop *aloop;
- if (bitmap_bit_p (ref->stored, loop->num))
+ if (bitmap_bit_p (&ref->stored, loop->num))
return NULL;
for (aloop = outer;
aloop != loop;
aloop = superloop_at_depth (loop, loop_depth (aloop) + 1))
- if (!bitmap_bit_p (ref->stored, aloop->num)
+ if (!bitmap_bit_p (&ref->stored, aloop->num)
&& ref_indep_loop_p (aloop, ref))
return aloop;
@@ -900,8 +879,9 @@ static void
set_level (gimple stmt, struct loop *orig_loop, struct loop *level)
{
struct loop *stmt_loop = gimple_bb (stmt)->loop_father;
- struct depend *dep;
struct lim_aux_data *lim_data;
+ gimple dep_stmt;
+ unsigned i;
stmt_loop = find_common_loop (orig_loop, stmt_loop);
lim_data = get_lim_data (stmt);
@@ -915,8 +895,8 @@ set_level (gimple stmt, struct loop *orig_loop, struct loop *level)
|| flow_loop_nested_p (lim_data->max_loop, level));
lim_data->tgt_loop = level;
- for (dep = lim_data->depends; dep; dep = dep->next)
- set_level (dep->stmt, orig_loop, level);
+ FOR_EACH_VEC_ELT (lim_data->depends, i, dep_stmt)
+ set_level (dep_stmt, orig_loop, level);
}
/* Determines an outermost loop from that we want to hoist the statement STMT.
@@ -1457,33 +1437,16 @@ force_move_till (tree ref, tree *index, void *data)
return true;
}
-/* Releases list of memory reference locations ACCS. */
-
-static void
-free_mem_ref_locs (mem_ref_locs_p accs)
-{
- unsigned i;
- mem_ref_loc_p loc;
-
- if (!accs)
- return;
-
- FOR_EACH_VEC_ELT (accs->locs, i, loc)
- free (loc);
- accs->locs.release ();
- free (accs);
-}
-
/* A function to free the mem_ref object OBJ. */
static void
memref_free (struct mem_ref *mem)
{
unsigned i;
- mem_ref_locs_p accs;
+ vec<mem_ref_loc> *accs;
FOR_EACH_VEC_ELT (mem->accesses_in_loop, i, accs)
- free_mem_ref_locs (accs);
+ accs->release ();
mem->accesses_in_loop.release ();
free (mem);
@@ -1496,54 +1459,32 @@ static mem_ref_p
mem_ref_alloc (tree mem, unsigned hash, unsigned id)
{
mem_ref_p ref = XNEW (struct mem_ref);
- ref->mem = mem;
+ ao_ref_init (&ref->mem, mem);
ref->id = id;
ref->hash = hash;
- ref->stored = BITMAP_ALLOC (&lim_bitmap_obstack);
- ref->indep_loop = BITMAP_ALLOC (&lim_bitmap_obstack);
- ref->dep_loop = BITMAP_ALLOC (&lim_bitmap_obstack);
- ref->indep_ref = BITMAP_ALLOC (&lim_bitmap_obstack);
- ref->dep_ref = BITMAP_ALLOC (&lim_bitmap_obstack);
+ bitmap_initialize (&ref->stored, &lim_bitmap_obstack);
+ bitmap_initialize (&ref->indep_loop, &lim_bitmap_obstack);
+ bitmap_initialize (&ref->dep_loop, &lim_bitmap_obstack);
ref->accesses_in_loop.create (0);
return ref;
}
-/* Allocates and returns the new list of locations. */
-
-static mem_ref_locs_p
-mem_ref_locs_alloc (void)
-{
- mem_ref_locs_p accs = XNEW (struct mem_ref_locs);
- accs->locs.create (0);
- return accs;
-}
-
/* Records memory reference location *LOC in LOOP to the memory reference
description REF. The reference occurs in statement STMT. */
static void
record_mem_ref_loc (mem_ref_p ref, struct loop *loop, gimple stmt, tree *loc)
{
- mem_ref_loc_p aref = XNEW (struct mem_ref_loc);
- mem_ref_locs_p accs;
- bitmap ril = memory_accesses.refs_in_loop[loop->num];
+ mem_ref_loc aref;
if (ref->accesses_in_loop.length ()
<= (unsigned) loop->num)
ref->accesses_in_loop.safe_grow_cleared (loop->num + 1);
- accs = ref->accesses_in_loop[loop->num];
- if (!accs)
- {
- accs = mem_ref_locs_alloc ();
- ref->accesses_in_loop[loop->num] = accs;
- }
-
- aref->stmt = stmt;
- aref->ref = loc;
- accs->locs.safe_push (aref);
- bitmap_set_bit (ril, ref->id);
+ aref.stmt = stmt;
+ aref.ref = loc;
+ ref->accesses_in_loop[loop->num].safe_push (aref);
}
/* Marks reference REF as stored in LOOP. */
@@ -1551,11 +1492,9 @@ record_mem_ref_loc (mem_ref_p ref, struct loop *loop, gimple stmt, tree *loc)
static void
mark_ref_stored (mem_ref_p ref, struct loop *loop)
{
- for (;
- loop != current_loops->tree_root
- && !bitmap_bit_p (ref->stored, loop->num);
- loop = loop_outer (loop))
- bitmap_set_bit (ref->stored, loop->num);
+ while (loop != current_loops->tree_root
+ && bitmap_set_bit (&ref->stored, loop->num))
+ loop = loop_outer (loop);
}
/* Gathers memory references in statement STMT in LOOP, storing the
@@ -1579,163 +1518,131 @@ gather_mem_refs_stmt (struct loop *loop, gimple stmt)
mem = simple_mem_ref_in_stmt (stmt, &is_stored);
if (!mem)
{
- id = memory_accesses.refs_list.length ();
- ref = mem_ref_alloc (error_mark_node, 0, id);
- memory_accesses.refs_list.safe_push (ref);
+ /* We use the shared mem_ref for all unanalyzable refs. */
+ id = UNANALYZABLE_MEM_ID;
+ ref = memory_accesses.refs_list[id];
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Unanalyzed memory reference %u: ", id);
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
}
- if (gimple_vdef (stmt))
- mark_ref_stored (ref, loop);
- record_mem_ref_loc (ref, loop, stmt, mem);
- return;
- }
-
- hash = iterative_hash_expr (*mem, 0);
- slot = memory_accesses.refs.find_slot_with_hash (*mem, hash, INSERT);
-
- if (*slot)
- {
- ref = (mem_ref_p) *slot;
- id = ref->id;
+ is_stored = gimple_vdef (stmt);
}
else
{
- id = memory_accesses.refs_list.length ();
- ref = mem_ref_alloc (*mem, hash, id);
- memory_accesses.refs_list.safe_push (ref);
- *slot = ref;
-
- if (dump_file && (dump_flags & TDF_DETAILS))
+ hash = iterative_hash_expr (*mem, 0);
+ slot = memory_accesses.refs.find_slot_with_hash (*mem, hash, INSERT);
+ if (*slot)
{
- fprintf (dump_file, "Memory reference %u: ", id);
- print_generic_expr (dump_file, ref->mem, TDF_SLIM);
- fprintf (dump_file, "\n");
+ ref = (mem_ref_p) *slot;
+ id = ref->id;
}
- }
+ else
+ {
+ id = memory_accesses.refs_list.length ();
+ ref = mem_ref_alloc (*mem, hash, id);
+ memory_accesses.refs_list.safe_push (ref);
+ *slot = ref;
- if (is_stored)
- mark_ref_stored (ref, loop);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Memory reference %u: ", id);
+ print_generic_expr (dump_file, ref->mem.ref, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ }
- record_mem_ref_loc (ref, loop, stmt, mem);
+ record_mem_ref_loc (ref, loop, stmt, mem);
+ }
+ bitmap_set_bit (&memory_accesses.refs_in_loop[loop->num], ref->id);
+ if (is_stored)
+ {
+ bitmap_set_bit (&memory_accesses.refs_stored_in_loop[loop->num], ref->id);
+ mark_ref_stored (ref, loop);
+ }
return;
}
+static unsigned *bb_loop_postorder;
+
+/* qsort sort function to sort blocks after their loop fathers postorder. */
+
+static int
+sort_bbs_in_loop_postorder_cmp (const void *bb1_, const void *bb2_)
+{
+ basic_block bb1 = *(basic_block *)const_cast<void *>(bb1_);
+ basic_block bb2 = *(basic_block *)const_cast<void *>(bb2_);
+ struct loop *loop1 = bb1->loop_father;
+ struct loop *loop2 = bb2->loop_father;
+ if (loop1->num == loop2->num)
+ return 0;
+ return bb_loop_postorder[loop1->num] < bb_loop_postorder[loop2->num] ? -1 : 1;
+}
+
/* Gathers memory references in loops. */
static void
-gather_mem_refs_in_loops (void)
+analyze_memory_references (void)
{
gimple_stmt_iterator bsi;
- basic_block bb;
- struct loop *loop;
+ basic_block bb, *bbs;
+ struct loop *loop, *outer;
loop_iterator li;
- bitmap lrefs, alrefs, alrefso;
+ unsigned i, n;
+ /* Initialize bb_loop_postorder with a mapping from loop->num to
+ its postorder index. */
+ i = 0;
+ bb_loop_postorder = XNEWVEC (unsigned, number_of_loops ());
+ FOR_EACH_LOOP (li, loop, LI_FROM_INNERMOST)
+ bb_loop_postorder[loop->num] = i++;
+ /* Collect all basic-blocks in loops and sort them after their
+ loops postorder. */
+ i = 0;
+ bbs = XNEWVEC (basic_block, n_basic_blocks - NUM_FIXED_BLOCKS);
FOR_EACH_BB (bb)
+ if (bb->loop_father != current_loops->tree_root)
+ bbs[i++] = bb;
+ n = i;
+ qsort (bbs, n, sizeof (basic_block), sort_bbs_in_loop_postorder_cmp);
+ free (bb_loop_postorder);
+
+ /* Visit blocks in loop postorder and assign mem-ref IDs in that order.
+ That results in better locality for all the bitmaps. */
+ for (i = 0; i < n; ++i)
{
- loop = bb->loop_father;
- if (loop == current_loops->tree_root)
- continue;
-
+ basic_block bb = bbs[i];
for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
- gather_mem_refs_stmt (loop, gsi_stmt (bsi));
+ gather_mem_refs_stmt (bb->loop_father, gsi_stmt (bsi));
}
+ free (bbs);
+
/* Propagate the information about accessed memory references up
the loop hierarchy. */
FOR_EACH_LOOP (li, loop, LI_FROM_INNERMOST)
{
- lrefs = memory_accesses.refs_in_loop[loop->num];
- alrefs = memory_accesses.all_refs_in_loop[loop->num];
- bitmap_ior_into (alrefs, lrefs);
-
- if (loop_outer (loop) == current_loops->tree_root)
+ /* Finalize the overall touched references (including subloops). */
+ bitmap_ior_into (&memory_accesses.all_refs_stored_in_loop[loop->num],
+ &memory_accesses.refs_stored_in_loop[loop->num]);
+
+ /* Propagate the information about accessed memory references up
+ the loop hierarchy. */
+ outer = loop_outer (loop);
+ if (outer == current_loops->tree_root)
continue;
- alrefso = memory_accesses.all_refs_in_loop[loop_outer (loop)->num];
- bitmap_ior_into (alrefso, alrefs);
- }
-}
-
-/* Create a mapping from virtual operands to references that touch them
- in LOOP. */
-
-static void
-create_vop_ref_mapping_loop (struct loop *loop)
-{
- bitmap refs = memory_accesses.refs_in_loop[loop->num];
- struct loop *sloop;
- bitmap_iterator bi;
- unsigned i;
- mem_ref_p ref;
-
- EXECUTE_IF_SET_IN_BITMAP (refs, 0, i, bi)
- {
- ref = memory_accesses.refs_list[i];
- for (sloop = loop; sloop != current_loops->tree_root;
- sloop = loop_outer (sloop))
- if (bitmap_bit_p (ref->stored, loop->num))
- {
- bitmap refs_stored
- = memory_accesses.all_refs_stored_in_loop[sloop->num];
- bitmap_set_bit (refs_stored, ref->id);
- }
- }
-}
-
-/* For each non-clobbered virtual operand and each loop, record the memory
- references in this loop that touch the operand. */
-
-static void
-create_vop_ref_mapping (void)
-{
- loop_iterator li;
- struct loop *loop;
-
- FOR_EACH_LOOP (li, loop, 0)
- {
- create_vop_ref_mapping_loop (loop);
- }
-}
-
-/* Gathers information about memory accesses in the loops. */
-
-static void
-analyze_memory_references (void)
-{
- unsigned i;
- bitmap empty;
-
- memory_accesses.refs.create (100);
- memory_accesses.refs_list.create (0);
- memory_accesses.refs_in_loop.create (number_of_loops ());
- memory_accesses.all_refs_in_loop.create (number_of_loops ());
- memory_accesses.all_refs_stored_in_loop.create (number_of_loops ());
-
- for (i = 0; i < number_of_loops (); i++)
- {
- empty = BITMAP_ALLOC (&lim_bitmap_obstack);
- memory_accesses.refs_in_loop.quick_push (empty);
- empty = BITMAP_ALLOC (&lim_bitmap_obstack);
- memory_accesses.all_refs_in_loop.quick_push (empty);
- empty = BITMAP_ALLOC (&lim_bitmap_obstack);
- memory_accesses.all_refs_stored_in_loop.quick_push (empty);
+ bitmap_ior_into (&memory_accesses.all_refs_stored_in_loop[outer->num],
+ &memory_accesses.all_refs_stored_in_loop[loop->num]);
}
-
- memory_accesses.ttae_cache = NULL;
-
- gather_mem_refs_in_loops ();
- create_vop_ref_mapping ();
}
/* Returns true if MEM1 and MEM2 may alias. TTAE_CACHE is used as a cache in
tree_to_aff_combination_expand. */
static bool
-mem_refs_may_alias_p (tree mem1, tree mem2, struct pointer_map_t **ttae_cache)
+mem_refs_may_alias_p (mem_ref_p mem1, mem_ref_p mem2,
+ struct pointer_map_t **ttae_cache)
{
/* Perform BASE + OFFSET analysis -- if MEM1 and MEM2 are based on the same
object and their offset differ in such a way that the locations cannot
@@ -1744,7 +1651,7 @@ mem_refs_may_alias_p (tree mem1, tree mem2, struct pointer_map_t **ttae_cache)
aff_tree off1, off2;
/* Perform basic offset and type-based disambiguation. */
- if (!refs_may_alias_p (mem1, mem2))
+ if (!refs_may_alias_p_1 (&mem1->mem, &mem2->mem, true))
return false;
/* The expansion of addresses may be a bit expensive, thus we only do
@@ -1752,8 +1659,8 @@ mem_refs_may_alias_p (tree mem1, tree mem2, struct pointer_map_t **ttae_cache)
if (optimize < 2)
return true;
- get_inner_reference_aff (mem1, &off1, &size1);
- get_inner_reference_aff (mem2, &off2, &size2);
+ get_inner_reference_aff (mem1->mem.ref, &off1, &size1);
+ get_inner_reference_aff (mem2->mem.ref, &off2, &size2);
aff_combination_expand (&off1, ttae_cache);
aff_combination_expand (&off2, ttae_cache);
aff_combination_scale (&off1, double_int_minus_one);
@@ -1765,43 +1672,46 @@ mem_refs_may_alias_p (tree mem1, tree mem2, struct pointer_map_t **ttae_cache)
return true;
}
-/* Rewrites location LOC by TMP_VAR. */
+/* Iterates over all locations of REF in LOOP and its subloops calling
+ fn.operator() with the location as argument. When that operator
+ returns true the iteration is stopped and true is returned.
+ Otherwise false is returned. */
-static void
-rewrite_mem_ref_loc (mem_ref_loc_p loc, tree tmp_var)
-{
- *loc->ref = tmp_var;
- update_stmt (loc->stmt);
-}
-
-/* Adds all locations of REF in LOOP and its subloops to LOCS. */
-
-static void
-get_all_locs_in_loop (struct loop *loop, mem_ref_p ref,
- vec<mem_ref_loc_p> *locs)
+template <typename FN>
+static bool
+for_all_locs_in_loop (struct loop *loop, mem_ref_p ref, FN fn)
{
- mem_ref_locs_p accs;
unsigned i;
mem_ref_loc_p loc;
- bitmap refs = memory_accesses.all_refs_in_loop[loop->num];
struct loop *subloop;
- if (!bitmap_bit_p (refs, ref->id))
- return;
-
- if (ref->accesses_in_loop.length ()
- > (unsigned) loop->num)
- {
- accs = ref->accesses_in_loop[loop->num];
- if (accs)
- {
- FOR_EACH_VEC_ELT (accs->locs, i, loc)
- locs->safe_push (loc);
- }
- }
+ if (ref->accesses_in_loop.length () > (unsigned) loop->num)
+ FOR_EACH_VEC_ELT (ref->accesses_in_loop[loop->num], i, loc)
+ if (fn (loc))
+ return true;
for (subloop = loop->inner; subloop != NULL; subloop = subloop->next)
- get_all_locs_in_loop (subloop, ref, locs);
+ if (for_all_locs_in_loop (subloop, ref, fn))
+ return true;
+
+ return false;
+}
+
+/* Rewrites location LOC by TMP_VAR. */
+
+struct rewrite_mem_ref_loc
+{
+ rewrite_mem_ref_loc (tree tmp_var_) : tmp_var (tmp_var_) {}
+ bool operator()(mem_ref_loc_p loc);
+ tree tmp_var;
+};
+
+bool
+rewrite_mem_ref_loc::operator()(mem_ref_loc_p loc)
+{
+ *loc->ref = tmp_var;
+ update_stmt (loc->stmt);
+ return false;
}
/* Rewrites all references to REF in LOOP by variable TMP_VAR. */
@@ -1809,14 +1719,7 @@ get_all_locs_in_loop (struct loop *loop, mem_ref_p ref,
static void
rewrite_mem_refs (struct loop *loop, mem_ref_p ref, tree tmp_var)
{
- unsigned i;
- mem_ref_loc_p loc;
- vec<mem_ref_loc_p> locs = vNULL;
-
- get_all_locs_in_loop (loop, ref, &locs);
- FOR_EACH_VEC_ELT (locs, i, loc)
- rewrite_mem_ref_loc (loc, tmp_var);
- locs.release ();
+ for_all_locs_in_loop (loop, ref, rewrite_mem_ref_loc (tmp_var));
}
/* The name and the length of the currently generated variable
@@ -2074,36 +1977,40 @@ execute_sm_if_changed (edge ex, tree mem, tree tmp_var, tree flag)
EDGE_SUCC (new_bb, 0)->flags &= ~EDGE_FALLTHRU;
}
+/* When REF is set on the location, set flag indicating the store. */
+
+struct sm_set_flag_if_changed
+{
+ sm_set_flag_if_changed (tree flag_) : flag (flag_) {}
+ bool operator()(mem_ref_loc_p loc);
+ tree flag;
+};
+
+bool
+sm_set_flag_if_changed::operator()(mem_ref_loc_p loc)
+{
+ /* Only set the flag for writes. */
+ if (is_gimple_assign (loc->stmt)
+ && gimple_assign_lhs_ptr (loc->stmt) == loc->ref)
+ {
+ gimple_stmt_iterator gsi = gsi_for_stmt (loc->stmt);
+ gimple stmt = gimple_build_assign (flag, boolean_true_node);
+ gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
+ }
+ return false;
+}
+
/* Helper function for execute_sm. On every location where REF is
set, set an appropriate flag indicating the store. */
static tree
execute_sm_if_changed_flag_set (struct loop *loop, mem_ref_p ref)
{
- unsigned i;
- mem_ref_loc_p loc;
tree flag;
- vec<mem_ref_loc_p> locs = vNULL;
- char *str = get_lsm_tmp_name (ref->mem, ~0);
-
+ char *str = get_lsm_tmp_name (ref->mem.ref, ~0);
lsm_tmp_name_add ("_flag");
flag = create_tmp_reg (boolean_type_node, str);
- get_all_locs_in_loop (loop, ref, &locs);
- FOR_EACH_VEC_ELT (locs, i, loc)
- {
- gimple_stmt_iterator gsi;
- gimple stmt;
-
- /* Only set the flag for writes. */
- if (is_gimple_assign (loc->stmt)
- && gimple_assign_lhs_ptr (loc->stmt) == loc->ref)
- {
- gsi = gsi_for_stmt (loc->stmt);
- stmt = gimple_build_assign (flag, boolean_true_node);
- gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
- }
- }
- locs.release ();
+ for_all_locs_in_loop (loop, ref, sm_set_flag_if_changed (flag));
return flag;
}
@@ -2126,16 +2033,16 @@ execute_sm (struct loop *loop, vec<edge> exits, mem_ref_p ref)
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Executing store motion of ");
- print_generic_expr (dump_file, ref->mem, 0);
+ print_generic_expr (dump_file, ref->mem.ref, 0);
fprintf (dump_file, " from loop %d\n", loop->num);
}
- tmp_var = create_tmp_reg (TREE_TYPE (ref->mem),
- get_lsm_tmp_name (ref->mem, ~0));
+ tmp_var = create_tmp_reg (TREE_TYPE (ref->mem.ref),
+ get_lsm_tmp_name (ref->mem.ref, ~0));
fmt_data.loop = loop;
fmt_data.orig_loop = loop;
- for_each_index (&ref->mem, force_move_till, &fmt_data);
+ for_each_index (&ref->mem.ref, force_move_till, &fmt_data);
if (block_in_transaction (loop_preheader_edge (loop)->src)
|| !PARAM_VALUE (PARAM_ALLOW_STORE_DATA_RACES))
@@ -2153,7 +2060,7 @@ execute_sm (struct loop *loop, vec<edge> exits, mem_ref_p ref)
/* FIXME/TODO: For the multi-threaded variant, we could avoid this
load altogether, since the store is predicated by a flag. We
could, do the load only if it was originally in the loop. */
- load = gimple_build_assign (tmp_var, unshare_expr (ref->mem));
+ load = gimple_build_assign (tmp_var, unshare_expr (ref->mem.ref));
lim_data = init_lim_data (load);
lim_data->max_loop = loop;
lim_data->tgt_loop = loop;
@@ -2173,11 +2080,11 @@ execute_sm (struct loop *loop, vec<edge> exits, mem_ref_p ref)
if (!multi_threaded_model_p)
{
gimple store;
- store = gimple_build_assign (unshare_expr (ref->mem), tmp_var);
+ store = gimple_build_assign (unshare_expr (ref->mem.ref), tmp_var);
gsi_insert_on_edge (ex, store);
}
else
- execute_sm_if_changed (ex, ref->mem, tmp_var, store_flag);
+ execute_sm_if_changed (ex, ref->mem.ref, tmp_var, store_flag);
}
/* Hoists memory references MEM_REFS out of LOOP. EXITS is the list of exit
@@ -2198,61 +2105,64 @@ hoist_memory_references (struct loop *loop, bitmap mem_refs,
}
}
-/* Returns true if REF is always accessed in LOOP. If STORED_P is true
- make sure REF is always stored to in LOOP. */
+struct ref_always_accessed
+{
+ ref_always_accessed (struct loop *loop_, tree base_, bool stored_p_)
+ : loop (loop_), base (base_), stored_p (stored_p_) {}
+ bool operator()(mem_ref_loc_p loc);
+ struct loop *loop;
+ tree base;
+ bool stored_p;
+};
-static bool
-ref_always_accessed_p (struct loop *loop, mem_ref_p ref, bool stored_p)
+bool
+ref_always_accessed::operator()(mem_ref_loc_p loc)
{
- vec<mem_ref_loc_p> locs = vNULL;
- unsigned i;
- mem_ref_loc_p loc;
- bool ret = false;
struct loop *must_exec;
- tree base;
- base = get_base_address (ref->mem);
- if (INDIRECT_REF_P (base)
- || TREE_CODE (base) == MEM_REF)
- base = TREE_OPERAND (base, 0);
+ if (!get_lim_data (loc->stmt))
+ return false;
- get_all_locs_in_loop (loop, ref, &locs);
- FOR_EACH_VEC_ELT (locs, i, loc)
+ /* If we require an always executed store make sure the statement
+ stores to the reference. */
+ if (stored_p)
{
- if (!get_lim_data (loc->stmt))
- continue;
+ tree lhs;
+ if (!gimple_get_lhs (loc->stmt))
+ return false;
+ lhs = get_base_address (gimple_get_lhs (loc->stmt));
+ if (!lhs)
+ return false;
+ if (INDIRECT_REF_P (lhs)
+ || TREE_CODE (lhs) == MEM_REF)
+ lhs = TREE_OPERAND (lhs, 0);
+ if (lhs != base)
+ return false;
+ }
- /* If we require an always executed store make sure the statement
- stores to the reference. */
- if (stored_p)
- {
- tree lhs;
- if (!gimple_get_lhs (loc->stmt))
- continue;
- lhs = get_base_address (gimple_get_lhs (loc->stmt));
- if (!lhs)
- continue;
- if (INDIRECT_REF_P (lhs)
- || TREE_CODE (lhs) == MEM_REF)
- lhs = TREE_OPERAND (lhs, 0);
- if (lhs != base)
- continue;
- }
+ must_exec = get_lim_data (loc->stmt)->always_executed_in;
+ if (!must_exec)
+ return false;
- must_exec = get_lim_data (loc->stmt)->always_executed_in;
- if (!must_exec)
- continue;
+ if (must_exec == loop
+ || flow_loop_nested_p (must_exec, loop))
+ return true;
- if (must_exec == loop
- || flow_loop_nested_p (must_exec, loop))
- {
- ret = true;
- break;
- }
- }
- locs.release ();
+ return false;
+}
- return ret;
+/* Returns true if REF is always accessed in LOOP. If STORED_P is true
+ make sure REF is always stored to in LOOP. */
+
+static bool
+ref_always_accessed_p (struct loop *loop, mem_ref_p ref, bool stored_p)
+{
+ tree base = ao_ref_base (&ref->mem);
+ if (TREE_CODE (base) == MEM_REF)
+ base = TREE_OPERAND (base, 0);
+
+ return for_all_locs_in_loop (loop, ref,
+ ref_always_accessed (loop, base, stored_p));
}
/* Returns true if REF1 and REF2 are independent. */
@@ -2260,104 +2170,130 @@ ref_always_accessed_p (struct loop *loop, mem_ref_p ref, bool stored_p)
static bool
refs_independent_p (mem_ref_p ref1, mem_ref_p ref2)
{
- if (ref1 == ref2
- || bitmap_bit_p (ref1->indep_ref, ref2->id))
+ if (ref1 == ref2)
return true;
- if (bitmap_bit_p (ref1->dep_ref, ref2->id))
- return false;
- if (!MEM_ANALYZABLE (ref1)
- || !MEM_ANALYZABLE (ref2))
- return false;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Querying dependency of refs %u and %u: ",
ref1->id, ref2->id);
- if (mem_refs_may_alias_p (ref1->mem, ref2->mem,
- &memory_accesses.ttae_cache))
+ if (mem_refs_may_alias_p (ref1, ref2, &memory_accesses.ttae_cache))
{
- bitmap_set_bit (ref1->dep_ref, ref2->id);
- bitmap_set_bit (ref2->dep_ref, ref1->id);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "dependent.\n");
return false;
}
else
{
- bitmap_set_bit (ref1->indep_ref, ref2->id);
- bitmap_set_bit (ref2->indep_ref, ref1->id);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "independent.\n");
return true;
}
}
-/* Records the information whether REF is independent in LOOP (according
- to INDEP). */
+/* Mark REF dependent on stores or loads (according to STORED_P) in LOOP
+ and its super-loops. */
static void
-record_indep_loop (struct loop *loop, mem_ref_p ref, bool indep)
+record_dep_loop (struct loop *loop, mem_ref_p ref, bool stored_p)
{
- if (indep)
- bitmap_set_bit (ref->indep_loop, loop->num);
- else
- bitmap_set_bit (ref->dep_loop, loop->num);
+ /* We can propagate dependent-in-loop bits up the loop
+ hierarchy to all outer loops. */
+ while (loop != current_loops->tree_root
+ && bitmap_set_bit (&ref->dep_loop, LOOP_DEP_BIT (loop->num, stored_p)))
+ loop = loop_outer (loop);
}
/* Returns true if REF is independent on all other memory references in
LOOP. */
static bool
-ref_indep_loop_p_1 (struct loop *loop, mem_ref_p ref)
+ref_indep_loop_p_1 (struct loop *loop, mem_ref_p ref, bool stored_p)
{
bitmap refs_to_check;
unsigned i;
bitmap_iterator bi;
- bool ret = true, stored = bitmap_bit_p (ref->stored, loop->num);
mem_ref_p aref;
- if (stored)
- refs_to_check = memory_accesses.all_refs_in_loop[loop->num];
+ if (stored_p)
+ refs_to_check = &memory_accesses.refs_in_loop[loop->num];
else
- refs_to_check = memory_accesses.all_refs_stored_in_loop[loop->num];
+ refs_to_check = &memory_accesses.refs_stored_in_loop[loop->num];
+
+ if (bitmap_bit_p (refs_to_check, UNANALYZABLE_MEM_ID))
+ return false;
EXECUTE_IF_SET_IN_BITMAP (refs_to_check, 0, i, bi)
{
aref = memory_accesses.refs_list[i];
- if (!MEM_ANALYZABLE (aref)
- || !refs_independent_p (ref, aref))
- {
- ret = false;
- record_indep_loop (loop, aref, false);
- break;
- }
+ if (!refs_independent_p (ref, aref))
+ return false;
}
- return ret;
+ return true;
}
/* Returns true if REF is independent on all other memory references in
LOOP. Wrapper over ref_indep_loop_p_1, caching its results. */
static bool
-ref_indep_loop_p (struct loop *loop, mem_ref_p ref)
+ref_indep_loop_p_2 (struct loop *loop, mem_ref_p ref, bool stored_p)
{
- bool ret;
+ stored_p |= bitmap_bit_p (&ref->stored, loop->num);
- if (bitmap_bit_p (ref->indep_loop, loop->num))
+ if (bitmap_bit_p (&ref->indep_loop, LOOP_DEP_BIT (loop->num, stored_p)))
return true;
- if (bitmap_bit_p (ref->dep_loop, loop->num))
+ if (bitmap_bit_p (&ref->dep_loop, LOOP_DEP_BIT (loop->num, stored_p)))
return false;
- ret = ref_indep_loop_p_1 (loop, ref);
+ struct loop *inner = loop->inner;
+ while (inner)
+ {
+ if (!ref_indep_loop_p_2 (inner, ref, stored_p))
+ return false;
+ inner = inner->next;
+ }
+
+ bool indep_p = ref_indep_loop_p_1 (loop, ref, stored_p);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Querying dependencies of ref %u in loop %d: %s\n",
- ref->id, loop->num, ret ? "independent" : "dependent");
+ ref->id, loop->num, indep_p ? "independent" : "dependent");
+
+ /* Record the computed result in the cache. */
+ if (indep_p)
+ {
+ if (bitmap_set_bit (&ref->indep_loop, LOOP_DEP_BIT (loop->num, stored_p))
+ && stored_p)
+ {
+ /* If it's independend against all refs then it's independent
+ against stores, too. */
+ bitmap_set_bit (&ref->indep_loop, LOOP_DEP_BIT (loop->num, false));
+ }
+ }
+ else
+ {
+ record_dep_loop (loop, ref, stored_p);
+ if (!stored_p)
+ {
+ /* If it's dependent against stores it's dependent against
+ all refs, too. */
+ record_dep_loop (loop, ref, true);
+ }
+ }
- record_indep_loop (loop, ref, ret);
+ return indep_p;
+}
- return ret;
+/* Returns true if REF is independent on all other memory references in
+ LOOP. */
+
+static bool
+ref_indep_loop_p (struct loop *loop, mem_ref_p ref)
+{
+ gcc_checking_assert (MEM_ANALYZABLE (ref));
+
+ return ref_indep_loop_p_2 (loop, ref, false);
}
/* Returns true if we can perform store motion of REF from LOOP. */
@@ -2371,26 +2307,22 @@ can_sm_ref_p (struct loop *loop, mem_ref_p ref)
if (!MEM_ANALYZABLE (ref))
return false;
- /* Unless the reference is stored in the loop, there is nothing to do. */
- if (!bitmap_bit_p (ref->stored, loop->num))
- return false;
-
/* It should be movable. */
- if (!is_gimple_reg_type (TREE_TYPE (ref->mem))
- || TREE_THIS_VOLATILE (ref->mem)
- || !for_each_index (&ref->mem, may_move_till, loop))
+ if (!is_gimple_reg_type (TREE_TYPE (ref->mem.ref))
+ || TREE_THIS_VOLATILE (ref->mem.ref)
+ || !for_each_index (&ref->mem.ref, may_move_till, loop))
return false;
/* If it can throw fail, we do not properly update EH info. */
- if (tree_could_throw_p (ref->mem))
+ if (tree_could_throw_p (ref->mem.ref))
return false;
/* If it can trap, it must be always executed in LOOP.
Readonly memory locations may trap when storing to them, but
tree_could_trap_p is a predicate for rvalues, so check that
explicitly. */
- base = get_base_address (ref->mem);
- if ((tree_could_trap_p (ref->mem)
+ base = get_base_address (ref->mem.ref);
+ if ((tree_could_trap_p (ref->mem.ref)
|| (DECL_P (base) && TREE_READONLY (base)))
&& !ref_always_accessed_p (loop, ref, true))
return false;
@@ -2410,7 +2342,7 @@ can_sm_ref_p (struct loop *loop, mem_ref_p ref)
static void
find_refs_for_sm (struct loop *loop, bitmap sm_executed, bitmap refs_to_sm)
{
- bitmap refs = memory_accesses.all_refs_in_loop[loop->num];
+ bitmap refs = &memory_accesses.all_refs_stored_in_loop[loop->num];
unsigned i;
bitmap_iterator bi;
mem_ref_p ref;
@@ -2450,7 +2382,7 @@ store_motion_loop (struct loop *loop, bitmap sm_executed)
{
vec<edge> exits = get_loop_exit_edges (loop);
struct loop *subloop;
- bitmap sm_in_loop = BITMAP_ALLOC (NULL);
+ bitmap sm_in_loop = BITMAP_ALLOC (&lim_bitmap_obstack);
if (loop_suitable_for_sm (loop, exits))
{
@@ -2473,7 +2405,7 @@ static void
store_motion (void)
{
struct loop *loop;
- bitmap sm_executed = BITMAP_ALLOC (NULL);
+ bitmap sm_executed = BITMAP_ALLOC (&lim_bitmap_obstack);
for (loop = current_loops->tree_root->inner; loop != NULL; loop = loop->next)
store_motion_loop (loop, sm_executed);
@@ -2488,7 +2420,7 @@ store_motion (void)
blocks that contain a nonpure call. */
static void
-fill_always_executed_in (struct loop *loop, sbitmap contains_call)
+fill_always_executed_in_1 (struct loop *loop, sbitmap contains_call)
{
basic_block bb = NULL, *bbs, last = NULL;
unsigned i;
@@ -2547,45 +2479,80 @@ fill_always_executed_in (struct loop *loop, sbitmap contains_call)
}
for (loop = loop->inner; loop; loop = loop->next)
- fill_always_executed_in (loop, contains_call);
+ fill_always_executed_in_1 (loop, contains_call);
}
-/* Compute the global information needed by the loop invariant motion pass. */
+/* Fills ALWAYS_EXECUTED_IN information for basic blocks, i.e.
+ for each such basic block bb records the outermost loop for that execution
+ of its header implies execution of bb. */
static void
-tree_ssa_lim_initialize (void)
+fill_always_executed_in (void)
{
sbitmap contains_call = sbitmap_alloc (last_basic_block);
- gimple_stmt_iterator bsi;
- struct loop *loop;
basic_block bb;
-
- bitmap_obstack_initialize (&lim_bitmap_obstack);
+ struct loop *loop;
bitmap_clear (contains_call);
FOR_EACH_BB (bb)
{
- for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+ gimple_stmt_iterator gsi;
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
- if (nonpure_call_p (gsi_stmt (bsi)))
+ if (nonpure_call_p (gsi_stmt (gsi)))
break;
}
- if (!gsi_end_p (bsi))
+ if (!gsi_end_p (gsi))
bitmap_set_bit (contains_call, bb->index);
}
for (loop = current_loops->tree_root->inner; loop; loop = loop->next)
- fill_always_executed_in (loop, contains_call);
+ fill_always_executed_in_1 (loop, contains_call);
sbitmap_free (contains_call);
+}
+
+
+/* Compute the global information needed by the loop invariant motion pass. */
+
+static void
+tree_ssa_lim_initialize (void)
+{
+ unsigned i;
+ bitmap_obstack_initialize (&lim_bitmap_obstack);
lim_aux_data_map = pointer_map_create ();
if (flag_tm)
compute_transaction_bits ();
alloc_aux_for_edges (0);
+
+ memory_accesses.refs.create (100);
+ memory_accesses.refs_list.create (100);
+ /* Allocate a special, unanalyzable mem-ref with ID zero. */
+ memory_accesses.refs_list.quick_push
+ (mem_ref_alloc (error_mark_node, 0, UNANALYZABLE_MEM_ID));
+
+ memory_accesses.refs_in_loop.create (number_of_loops ());
+ memory_accesses.refs_in_loop.quick_grow (number_of_loops ());
+ memory_accesses.refs_stored_in_loop.create (number_of_loops ());
+ memory_accesses.refs_stored_in_loop.quick_grow (number_of_loops ());
+ memory_accesses.all_refs_stored_in_loop.create (number_of_loops ());
+ memory_accesses.all_refs_stored_in_loop.quick_grow (number_of_loops ());
+
+ for (i = 0; i < number_of_loops (); i++)
+ {
+ bitmap_initialize (&memory_accesses.refs_in_loop[i],
+ &lim_bitmap_obstack);
+ bitmap_initialize (&memory_accesses.refs_stored_in_loop[i],
+ &lim_bitmap_obstack);
+ bitmap_initialize (&memory_accesses.all_refs_stored_in_loop[i],
+ &lim_bitmap_obstack);
+ }
+
+ memory_accesses.ttae_cache = NULL;
}
/* Cleans up after the invariant motion pass. */
@@ -2612,7 +2579,7 @@ tree_ssa_lim_finalize (void)
memory_accesses.refs_list.release ();
memory_accesses.refs_in_loop.release ();
- memory_accesses.all_refs_in_loop.release ();
+ memory_accesses.refs_stored_in_loop.release ();
memory_accesses.all_refs_stored_in_loop.release ();
if (memory_accesses.ttae_cache)
@@ -2632,6 +2599,9 @@ tree_ssa_lim (void)
/* Gathers information about memory accesses in the loops. */
analyze_memory_references ();
+ /* Fills ALWAYS_EXECUTED_IN information for basic blocks. */
+ fill_always_executed_in ();
+
/* For each statement determine the outermost loop in that it is
invariant and cost for computing the invariant. */
determine_invariantness ();