VEC (mem_ref_locs_p, heap) *accesses_in_loop;
/* The locations of the accesses. Vector
indexed by the loop number. */
- bitmap vops; /* Vops corresponding to this memory
- location. */
/* The following sets are computed on demand. We keep both set and
its complement, so that we know whether the information was
subloops. */
VEC (bitmap, heap) *all_refs_in_loop;
- /* The set of virtual operands clobbered in a given loop. */
- VEC (bitmap, heap) *clobbered_vops;
-
- /* Map from the pair (loop, virtual operand) to the set of refs that
- touch the virtual operand in the loop. */
- VEC (htab_t, heap) *vop_ref_map;
+ /* The set of memory references stored in each loop, including
+ subloops. */
+ VEC (bitmap, heap) *all_refs_stored_in_loop;
/* Cache for expanding memory addresses. */
struct pointer_map_t *ttae_cache;
/* Minimum cost of an expensive expression. */
#define LIM_EXPENSIVE ((unsigned) PARAM_VALUE (PARAM_LIM_EXPENSIVE))
-/* The outermost loop for that execution of the header guarantees that the
+/* The outermost loop for which execution of the header guarantees that the
block will be executed. */
#define ALWAYS_EXECUTED_IN(BB) ((struct loop *) (BB)->aux)
+#define SET_ALWAYS_EXECUTED_IN(BB, VAL) ((BB)->aux = (void *) (VAL))
+
+/* Whether the reference was analyzable. */
+#define MEM_ANALYZABLE(REF) ((REF)->mem != error_mark_node)
static struct lim_aux_data *
init_lim_data (gimple stmt)
return true;
}
-/* Returns an estimate for a cost of statement STMT. TODO -- the values here
- are just ad-hoc constants. The estimates should be based on target-specific
- values. */
+/* Returns an estimate for a cost of statement STMT. The values here
+ are just ad-hoc constants, similar to costs for inlining. */
static unsigned
stmt_cost (gimple stmt)
{
- tree fndecl;
- unsigned cost = 1;
-
/* Always try to create possibilities for unswitching. */
if (gimple_code (stmt) == GIMPLE_COND
|| gimple_code (stmt) == GIMPLE_PHI)
return LIM_EXPENSIVE;
- /* Hoisting memory references out should almost surely be a win. */
- if (gimple_references_memory_p (stmt))
- cost += 20;
-
+ /* We should be hoisting calls if possible. */
if (is_gimple_call (stmt))
{
- /* We should be hoisting calls if possible. */
+ tree fndecl;
/* Unless the call is a builtin_constant_p; this always folds to a
constant, so moving it is useless. */
&& DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CONSTANT_P)
return 0;
- return cost + 20;
+ return LIM_EXPENSIVE;
}
+ /* Hoisting memory references out should almost surely be a win. */
+ if (gimple_references_memory_p (stmt))
+ return LIM_EXPENSIVE;
+
if (gimple_code (stmt) != GIMPLE_ASSIGN)
- return cost;
+ return 1;
switch (gimple_assign_rhs_code (stmt))
{
case MULT_EXPR:
+ case WIDEN_MULT_EXPR:
+ case WIDEN_MULT_PLUS_EXPR:
+ case WIDEN_MULT_MINUS_EXPR:
+ case DOT_PROD_EXPR:
+ case FMA_EXPR:
case TRUNC_DIV_EXPR:
case CEIL_DIV_EXPR:
case FLOOR_DIV_EXPR:
case TRUNC_MOD_EXPR:
case RDIV_EXPR:
/* Division and multiplication are usually expensive. */
- cost += 20;
- break;
+ return LIM_EXPENSIVE;
case LSHIFT_EXPR:
case RSHIFT_EXPR:
- cost += 20;
- break;
+ case WIDEN_LSHIFT_EXPR:
+ case LROTATE_EXPR:
+ case RROTATE_EXPR:
+ /* Shifts and rotates are usually expensive. */
+ return LIM_EXPENSIVE;
+
+ case CONSTRUCTOR:
+ /* Make vector construction cost proportional to the number
+ of elements. */
+ return CONSTRUCTOR_NELTS (gimple_assign_rhs1 (stmt));
+
+ case SSA_NAME:
+ case PAREN_EXPR:
+ /* Whether or not something is wrapped inside a PAREN_EXPR
+ should not change move cost. Nor should an intermediate
+ unpropagated SSA name copy. */
+ return 0;
default:
- break;
+ return 1;
}
-
- return cost;
}
/* Finds the outermost loop between OUTER and LOOP in that the memory reference
gcc_assert (arg0 && arg1);
t = build2 (gimple_cond_code (cond), boolean_type_node,
gimple_cond_lhs (cond), gimple_cond_rhs (cond));
- t = build3 (COND_EXPR, TREE_TYPE (gimple_phi_result (stmt)),
- t, arg0, arg1);
- new_stmt = gimple_build_assign_with_ops (COND_EXPR,
- gimple_phi_result (stmt),
- t, NULL_TREE);
+ new_stmt = gimple_build_assign_with_ops3 (COND_EXPR,
+ gimple_phi_result (stmt),
+ t, arg0, arg1);
SSA_NAME_DEF_STMT (gimple_phi_result (stmt)) = new_stmt;
*((unsigned int *)(dw_data->global_data)) |= TODO_cleanup_cfg;
}
free_mem_ref_locs (accs);
VEC_free (mem_ref_locs_p, heap, mem->accesses_in_loop);
- BITMAP_FREE (mem->vops);
free (mem);
}
ref->indep_ref = BITMAP_ALLOC (NULL);
ref->dep_ref = BITMAP_ALLOC (NULL);
ref->accesses_in_loop = NULL;
- ref->vops = BITMAP_ALLOC (NULL);
return ref;
}
hashval_t hash;
PTR *slot;
mem_ref_p ref;
- tree vname;
bool is_stored;
- bitmap clvops;
unsigned id;
if (!gimple_vuse (stmt))
mem = simple_mem_ref_in_stmt (stmt, &is_stored);
if (!mem)
- goto fail;
+ {
+ id = VEC_length (mem_ref_p, memory_accesses.refs_list);
+ ref = mem_ref_alloc (error_mark_node, 0, id);
+ VEC_safe_push (mem_ref_p, heap, memory_accesses.refs_list, ref);
+ 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 = htab_find_slot_with_hash (memory_accesses.refs, *mem, hash, INSERT);
if (is_stored)
mark_ref_stored (ref, loop);
- if ((vname = gimple_vuse (stmt)) != NULL_TREE)
- bitmap_set_bit (ref->vops, DECL_UID (SSA_NAME_VAR (vname)));
record_mem_ref_loc (ref, loop, stmt, mem);
return;
-
-fail:
- clvops = VEC_index (bitmap, memory_accesses.clobbered_vops, loop->num);
- if ((vname = gimple_vuse (stmt)) != NULL_TREE)
- bitmap_set_bit (clvops, DECL_UID (SSA_NAME_VAR (vname)));
}
/* Gathers memory references in loops. */
basic_block bb;
struct loop *loop;
loop_iterator li;
- bitmap clvo, clvi;
bitmap lrefs, alrefs, alrefso;
FOR_EACH_BB (bb)
gather_mem_refs_stmt (loop, gsi_stmt (bsi));
}
- /* Propagate the information about clobbered vops and accessed memory
- references up the loop hierarchy. */
+ /* Propagate the information about accessed memory references up
+ the loop hierarchy. */
FOR_EACH_LOOP (li, loop, LI_FROM_INNERMOST)
{
lrefs = VEC_index (bitmap, memory_accesses.refs_in_loop, loop->num);
if (loop_outer (loop) == current_loops->tree_root)
continue;
- clvi = VEC_index (bitmap, memory_accesses.clobbered_vops, loop->num);
- clvo = VEC_index (bitmap, memory_accesses.clobbered_vops,
- loop_outer (loop)->num);
- bitmap_ior_into (clvo, clvi);
-
alrefso = VEC_index (bitmap, memory_accesses.all_refs_in_loop,
loop_outer (loop)->num);
bitmap_ior_into (alrefso, alrefs);
}
}
-/* Element of the hash table that maps vops to memory references. */
-
-struct vop_to_refs_elt
-{
- /* DECL_UID of the vop. */
- unsigned uid;
-
- /* List of the all references. */
- bitmap refs_all;
-
- /* List of stored references. */
- bitmap refs_stored;
-};
-
-/* A hash function for struct vop_to_refs_elt object OBJ. */
-
-static hashval_t
-vtoe_hash (const void *obj)
-{
- const struct vop_to_refs_elt *const vtoe =
- (const struct vop_to_refs_elt *) obj;
-
- return vtoe->uid;
-}
-
-/* An equality function for struct vop_to_refs_elt object OBJ1 with
- uid of a vop OBJ2. */
-
-static int
-vtoe_eq (const void *obj1, const void *obj2)
-{
- const struct vop_to_refs_elt *const vtoe =
- (const struct vop_to_refs_elt *) obj1;
- const unsigned *const uid = (const unsigned *) obj2;
-
- return vtoe->uid == *uid;
-}
-
-/* A function to free the struct vop_to_refs_elt object. */
-
-static void
-vtoe_free (void *obj)
-{
- struct vop_to_refs_elt *const vtoe =
- (struct vop_to_refs_elt *) obj;
-
- BITMAP_FREE (vtoe->refs_all);
- BITMAP_FREE (vtoe->refs_stored);
- free (vtoe);
-}
-
-/* Records REF to hashtable VOP_TO_REFS for the index VOP. STORED is true
- if the reference REF is stored. */
-
-static void
-record_vop_access (htab_t vop_to_refs, unsigned vop, unsigned ref, bool stored)
-{
- void **slot = htab_find_slot_with_hash (vop_to_refs, &vop, vop, INSERT);
- struct vop_to_refs_elt *vtoe;
-
- if (!*slot)
- {
- vtoe = XNEW (struct vop_to_refs_elt);
- vtoe->uid = vop;
- vtoe->refs_all = BITMAP_ALLOC (NULL);
- vtoe->refs_stored = BITMAP_ALLOC (NULL);
- *slot = vtoe;
- }
- else
- vtoe = (struct vop_to_refs_elt *) *slot;
-
- bitmap_set_bit (vtoe->refs_all, ref);
- if (stored)
- bitmap_set_bit (vtoe->refs_stored, ref);
-}
-
-/* Returns the set of references that access VOP according to the table
- VOP_TO_REFS. */
-
-static bitmap
-get_vop_accesses (htab_t vop_to_refs, unsigned vop)
-{
- struct vop_to_refs_elt *const vtoe =
- (struct vop_to_refs_elt *) htab_find_with_hash (vop_to_refs, &vop, vop);
- return vtoe->refs_all;
-}
-
-/* Returns the set of stores that access VOP according to the table
- VOP_TO_REFS. */
-
-static bitmap
-get_vop_stores (htab_t vop_to_refs, unsigned vop)
-{
- struct vop_to_refs_elt *const vtoe =
- (struct vop_to_refs_elt *) htab_find_with_hash (vop_to_refs, &vop, vop);
- return vtoe->refs_stored;
-}
-
-/* Adds REF to mapping from virtual operands to references in LOOP. */
-
-static void
-add_vop_ref_mapping (struct loop *loop, mem_ref_p ref)
-{
- htab_t map = VEC_index (htab_t, memory_accesses.vop_ref_map, loop->num);
- bool stored = bitmap_bit_p (ref->stored, loop->num);
- bitmap clobbers = VEC_index (bitmap, memory_accesses.clobbered_vops,
- loop->num);
- bitmap_iterator bi;
- unsigned vop;
-
- EXECUTE_IF_AND_COMPL_IN_BITMAP (ref->vops, clobbers, 0, vop, bi)
- {
- record_vop_access (map, vop, ref->id, stored);
- }
-}
-
/* Create a mapping from virtual operands to references that touch them
in LOOP. */
EXECUTE_IF_SET_IN_BITMAP (refs, 0, i, bi)
{
ref = VEC_index (mem_ref_p, memory_accesses.refs_list, i);
- for (sloop = loop; sloop != current_loops->tree_root; sloop = loop_outer (sloop))
- add_vop_ref_mapping (sloop, ref);
+ for (sloop = loop; sloop != current_loops->tree_root;
+ sloop = loop_outer (sloop))
+ if (bitmap_bit_p (ref->stored, loop->num))
+ {
+ bitmap refs_stored
+ = VEC_index (bitmap, memory_accesses.all_refs_stored_in_loop,
+ sloop->num);
+ bitmap_set_bit (refs_stored, ref->id);
+ }
}
}
{
unsigned i;
bitmap empty;
- htab_t hempty;
memory_accesses.refs
= htab_create (100, memref_hash, memref_eq, memref_free);
number_of_loops ());
memory_accesses.all_refs_in_loop = VEC_alloc (bitmap, heap,
number_of_loops ());
- memory_accesses.clobbered_vops = VEC_alloc (bitmap, heap,
- number_of_loops ());
- memory_accesses.vop_ref_map = VEC_alloc (htab_t, heap,
- number_of_loops ());
+ memory_accesses.all_refs_stored_in_loop = VEC_alloc (bitmap, heap,
+ number_of_loops ());
for (i = 0; i < number_of_loops (); i++)
{
empty = BITMAP_ALLOC (NULL);
VEC_quick_push (bitmap, memory_accesses.all_refs_in_loop, empty);
empty = BITMAP_ALLOC (NULL);
- VEC_quick_push (bitmap, memory_accesses.clobbered_vops, empty);
- hempty = htab_create (10, vtoe_hash, vtoe_eq, vtoe_free);
- VEC_quick_push (htab_t, memory_accesses.vop_ref_map, hempty);
+ VEC_quick_push (bitmap, memory_accesses.all_refs_stored_in_loop, empty);
}
memory_accesses.ttae_cache = NULL;
create_vop_ref_mapping ();
}
-/* Returns true if a region of size SIZE1 at position 0 and a region of
- size SIZE2 at position DIFF cannot overlap. */
-
-static bool
-cannot_overlap_p (aff_tree *diff, double_int size1, double_int size2)
-{
- double_int d, bound;
-
- /* Unless the difference is a constant, we fail. */
- if (diff->n != 0)
- return false;
-
- d = diff->offset;
- if (double_int_negative_p (d))
- {
- /* The second object is before the first one, we succeed if the last
- element of the second object is before the start of the first one. */
- bound = double_int_add (d, double_int_add (size2, double_int_minus_one));
- return double_int_negative_p (bound);
- }
- else
- {
- /* We succeed if the second object starts after the first one ends. */
- return double_int_scmp (size1, d) <= 0;
- }
-}
-
/* Returns true if MEM1 and MEM2 may alias. TTAE_CACHE is used as a cache in
tree_to_aff_combination_expand. */
aff_combination_scale (&off1, double_int_minus_one);
aff_combination_add (&off2, &off1);
- if (cannot_overlap_p (&off2, size1, size2))
+ if (aff_comb_cannot_overlap_p (&off2, size1, size2))
return false;
return true;
switch (TREE_CODE (ref))
{
case MEM_REF:
+ case TARGET_MEM_REF:
gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
lsm_tmp_name_add ("_");
break;
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: ",
static bool
ref_indep_loop_p_1 (struct loop *loop, mem_ref_p ref)
{
- bitmap clobbers, refs_to_check, refs;
+ bitmap refs_to_check;
unsigned i;
bitmap_iterator bi;
bool ret = true, stored = bitmap_bit_p (ref->stored, loop->num);
- htab_t map;
mem_ref_p aref;
- /* If the reference is clobbered, it is not independent. */
- clobbers = VEC_index (bitmap, memory_accesses.clobbered_vops, loop->num);
- if (bitmap_intersect_p (ref->vops, clobbers))
- return false;
-
- refs_to_check = BITMAP_ALLOC (NULL);
-
- map = VEC_index (htab_t, memory_accesses.vop_ref_map, loop->num);
- EXECUTE_IF_AND_COMPL_IN_BITMAP (ref->vops, clobbers, 0, i, bi)
- {
- if (stored)
- refs = get_vop_accesses (map, i);
- else
- refs = get_vop_stores (map, i);
-
- bitmap_ior_into (refs_to_check, refs);
- }
+ if (stored)
+ refs_to_check = VEC_index (bitmap,
+ memory_accesses.all_refs_in_loop, loop->num);
+ else
+ refs_to_check = VEC_index (bitmap,
+ memory_accesses.all_refs_stored_in_loop,
+ loop->num);
EXECUTE_IF_SET_IN_BITMAP (refs_to_check, 0, i, bi)
{
aref = VEC_index (mem_ref_p, memory_accesses.refs_list, i);
- if (!refs_independent_p (ref, aref))
+ if (!MEM_ANALYZABLE (aref)
+ || !refs_independent_p (ref, aref))
{
ret = false;
record_indep_loop (loop, aref, false);
}
}
- BITMAP_FREE (refs_to_check);
return ret;
}
{
tree base;
+ /* Can't hoist unanalyzable refs. */
+ 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;
edge e;
struct loop *inn_loop = loop;
- if (!loop->header->aux)
+ if (ALWAYS_EXECUTED_IN (loop->header) == NULL)
{
bbs = get_loop_body_in_dom_order (loop);
while (1)
{
- last->aux = loop;
+ SET_ALWAYS_EXECUTED_IN (last, loop);
if (last == loop->header)
break;
last = get_immediate_dominator (CDI_DOMINATORS, last);
basic_block bb;
unsigned i;
bitmap b;
- htab_t h;
FOR_EACH_BB (bb)
- {
- bb->aux = NULL;
- }
+ SET_ALWAYS_EXECUTED_IN (bb, NULL);
pointer_map_destroy (lim_aux_data_map);
BITMAP_FREE (b);
VEC_free (bitmap, heap, memory_accesses.all_refs_in_loop);
- FOR_EACH_VEC_ELT (bitmap, memory_accesses.clobbered_vops, i, b)
+ FOR_EACH_VEC_ELT (bitmap, memory_accesses.all_refs_stored_in_loop, i, b)
BITMAP_FREE (b);
- VEC_free (bitmap, heap, memory_accesses.clobbered_vops);
-
- FOR_EACH_VEC_ELT (htab_t, memory_accesses.vop_ref_map, i, h)
- htab_delete (h);
- VEC_free (htab_t, heap, memory_accesses.vop_ref_map);
+ VEC_free (bitmap, heap, memory_accesses.all_refs_stored_in_loop);
if (memory_accesses.ttae_cache)
pointer_map_destroy (memory_accesses.ttae_cache);