Commit 01fd257a by Zdenek Dvorak Committed by Zdenek Dvorak

tree-ssa-loop-im.c: Include hashtab.h.

	* tree-ssa-loop-im.c: Include hashtab.h.
	(struct mem_ref_loc): New.
	(struct mem_ref): Describe the set of references with the same
	shape.
	(max_stmt_uid, get_stmt_uid, record_mem_ref, free_mem_refs,
	maybe_queue_var, fem_single_reachable_address,
	for_each_memref, single_reachable_address,
	is_call_clobbered_ref, determine_lsm_reg): Removed.
	(record_mem_ref_loc, free_mem_ref_locs, determine_lsm_ref,
	hoist_memory_reference, memref_hash, memref_eq, memref_del,
	gather_mem_refs_stmt, gather_mem_refs, find_more_ref_vops):
	New functions.
	(rewrite_mem_refs, schedule_sm): Use mem_ref_loc list.
	(determine_lsm_loop): Rewritten.
	(determine_lsm): Do not set stmt uids.

From-SVN: r99539
parent 09366c43
2005-05-10 Zdenek Dvorak <dvorakz@suse.cz>
* tree-ssa-loop-im.c: Include hashtab.h.
(struct mem_ref_loc): New.
(struct mem_ref): Describe the set of references with the same
shape.
(max_stmt_uid, get_stmt_uid, record_mem_ref, free_mem_refs,
maybe_queue_var, fem_single_reachable_address,
for_each_memref, single_reachable_address,
is_call_clobbered_ref, determine_lsm_reg): Removed.
(record_mem_ref_loc, free_mem_ref_locs, determine_lsm_ref,
hoist_memory_reference, memref_hash, memref_eq, memref_del,
gather_mem_refs_stmt, gather_mem_refs, find_more_ref_vops):
New functions.
(rewrite_mem_refs, schedule_sm): Use mem_ref_loc list.
(determine_lsm_loop): Rewritten.
(determine_lsm): Do not set stmt uids.
2005-05-10 Adrian Straetling <straetling@de.ibm.com> 2005-05-10 Adrian Straetling <straetling@de.ibm.com>
* config/s390/s390.md: Add comment lines for 'f' and 't' constraint * config/s390/s390.md: Add comment lines for 'f' and 't' constraint
......
...@@ -38,6 +38,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -38,6 +38,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "tree-pass.h" #include "tree-pass.h"
#include "flags.h" #include "flags.h"
#include "real.h" #include "real.h"
#include "hashtab.h"
/* TODO: Support for predicated code motion. I.e. /* TODO: Support for predicated code motion. I.e.
...@@ -103,13 +104,26 @@ struct lim_aux_data ...@@ -103,13 +104,26 @@ struct lim_aux_data
? NULL \ ? NULL \
: (struct lim_aux_data *) (stmt_ann (STMT)->aux)) : (struct lim_aux_data *) (stmt_ann (STMT)->aux))
/* Description of a memory reference for store motion. */ /* Description of a memory reference location for store motion. */
struct mem_ref struct mem_ref_loc
{ {
tree *ref; /* The reference itself. */ tree *ref; /* The reference itself. */
tree stmt; /* The statement in that it occurs. */ tree stmt; /* The statement in that it occurs. */
struct mem_ref *next; /* Next use in the chain. */ struct mem_ref_loc *next; /* Next use in the chain. */
};
/* Description of a memory reference for store motion. */
struct mem_ref
{
tree mem; /* The memory itself. */
hashval_t hash; /* Its hash value. */
bool is_stored; /* True if there is a store to the location
in the loop. */
struct mem_ref_loc *locs; /* The locations where it is found. */
bitmap vops; /* Vops corresponding to this memory
location. */
}; };
/* Minimum cost of an expensive expression. */ /* Minimum cost of an expensive expression. */
...@@ -119,21 +133,6 @@ struct mem_ref ...@@ -119,21 +133,6 @@ struct mem_ref
block will be executed. */ block will be executed. */
#define ALWAYS_EXECUTED_IN(BB) ((struct loop *) (BB)->aux) #define ALWAYS_EXECUTED_IN(BB) ((struct loop *) (BB)->aux)
static unsigned max_stmt_uid; /* Maximal uid of a statement. Uids to phi
nodes are assigned using the versions of
ssa names they define. */
/* Returns uid of statement STMT. */
static unsigned
get_stmt_uid (tree stmt)
{
if (TREE_CODE (stmt) == PHI_NODE)
return SSA_NAME_VERSION (PHI_RESULT (stmt)) + max_stmt_uid;
return stmt_ann (stmt)->uid;
}
/* Calls CBCK for each index in memory reference ADDR_P. There are two /* Calls CBCK for each index in memory reference ADDR_P. There are two
kinds situations handled; in each of these cases, the memory reference kinds situations handled; in each of these cases, the memory reference
and DATA are passed to the callback: and DATA are passed to the callback:
...@@ -859,13 +858,13 @@ force_move_till (tree ref, tree *index, void *data) ...@@ -859,13 +858,13 @@ force_move_till (tree ref, tree *index, void *data)
return true; return true;
} }
/* Records memory reference *REF (that occurs in statement STMT) /* Records memory reference location *REF to the list MEM_REFS. The reference
to the list MEM_REFS. */ occurs in statement STMT. */
static void static void
record_mem_ref (struct mem_ref **mem_refs, tree stmt, tree *ref) record_mem_ref_loc (struct mem_ref_loc **mem_refs, tree stmt, tree *ref)
{ {
struct mem_ref *aref = xmalloc (sizeof (struct mem_ref)); struct mem_ref_loc *aref = xmalloc (sizeof (struct mem_ref_loc));
aref->stmt = stmt; aref->stmt = stmt;
aref->ref = ref; aref->ref = ref;
...@@ -874,12 +873,12 @@ record_mem_ref (struct mem_ref **mem_refs, tree stmt, tree *ref) ...@@ -874,12 +873,12 @@ record_mem_ref (struct mem_ref **mem_refs, tree stmt, tree *ref)
*mem_refs = aref; *mem_refs = aref;
} }
/* Releases list of memory references MEM_REFS. */ /* Releases list of memory reference locations MEM_REFS. */
static void static void
free_mem_refs (struct mem_ref *mem_refs) free_mem_ref_locs (struct mem_ref_loc *mem_refs)
{ {
struct mem_ref *act; struct mem_ref_loc *act;
while (mem_refs) while (mem_refs)
{ {
...@@ -889,236 +888,10 @@ free_mem_refs (struct mem_ref *mem_refs) ...@@ -889,236 +888,10 @@ free_mem_refs (struct mem_ref *mem_refs)
} }
} }
/* If VAR is defined in LOOP and the statement it is defined in does not belong
to the set SEEN, add the statement to QUEUE of length IN_QUEUE and
to the set SEEN. */
static void
maybe_queue_var (tree var, struct loop *loop,
sbitmap seen, tree *queue, unsigned *in_queue)
{
tree stmt = SSA_NAME_DEF_STMT (var);
basic_block def_bb = bb_for_stmt (stmt);
if (!def_bb
|| !flow_bb_inside_loop_p (loop, def_bb)
|| TEST_BIT (seen, get_stmt_uid (stmt)))
return;
SET_BIT (seen, get_stmt_uid (stmt));
queue[(*in_queue)++] = stmt;
}
/* If COMMON_REF is NULL, set COMMON_REF to *OP and return true.
Otherwise return true if the memory reference *OP is equal to COMMON_REF.
Record the reference OP to list MEM_REFS. STMT is the statement in that
the reference occurs. */
struct sra_data
{
struct mem_ref **mem_refs;
tree common_ref;
tree stmt;
};
static bool
fem_single_reachable_address (tree *op, void *data)
{
struct sra_data *sra_data = data;
if (sra_data->common_ref
&& !operand_equal_p (*op, sra_data->common_ref, 0))
return false;
sra_data->common_ref = *op;
record_mem_ref (sra_data->mem_refs, sra_data->stmt, op);
return true;
}
/* Runs CALLBACK for each operand of STMT that is a memory reference. DATA
is passed to the CALLBACK as well. The traversal stops if CALLBACK
returns false, for_each_memref then returns false as well. Otherwise
for_each_memref returns true. */
static bool
for_each_memref (tree stmt, bool (*callback)(tree *, void *), void *data)
{
tree *op;
if (TREE_CODE (stmt) == RETURN_EXPR)
stmt = TREE_OPERAND (stmt, 1);
if (TREE_CODE (stmt) == MODIFY_EXPR)
{
op = &TREE_OPERAND (stmt, 0);
if (TREE_CODE (*op) != SSA_NAME
&& !callback (op, data))
return false;
op = &TREE_OPERAND (stmt, 1);
if (TREE_CODE (*op) != SSA_NAME
&& is_gimple_lvalue (*op)
&& !callback (op, data))
return false;
stmt = TREE_OPERAND (stmt, 1);
}
if (TREE_CODE (stmt) == WITH_SIZE_EXPR)
stmt = TREE_OPERAND (stmt, 0);
if (TREE_CODE (stmt) == CALL_EXPR)
{
tree args;
for (args = TREE_OPERAND (stmt, 1); args; args = TREE_CHAIN (args))
{
op = &TREE_VALUE (args);
if (TREE_CODE (*op) != SSA_NAME
&& is_gimple_lvalue (*op)
&& !callback (op, data))
return false;
}
}
return true;
}
/* Determine whether all memory references inside the LOOP that correspond
to virtual ssa names defined in statement STMT are equal.
If so, store the list of the references to MEM_REFS, and return one
of them. Otherwise store NULL to MEM_REFS and return NULL_TREE.
*SEEN_CALL_STMT is set to true if the virtual operands suggest
that the reference might be clobbered by a call inside the LOOP. */
static tree
single_reachable_address (struct loop *loop, tree stmt,
struct mem_ref **mem_refs,
bool *seen_call_stmt)
{
unsigned max_uid = max_stmt_uid + num_ssa_names;
tree *queue = xmalloc (sizeof (tree) * max_uid);
sbitmap seen = sbitmap_alloc (max_uid);
unsigned in_queue = 1;
unsigned i;
struct sra_data sra_data;
tree call;
tree val;
ssa_op_iter iter;
imm_use_iterator imm_iter;
use_operand_p use_p;
sbitmap_zero (seen);
*mem_refs = NULL;
sra_data.mem_refs = mem_refs;
sra_data.common_ref = NULL_TREE;
queue[0] = stmt;
SET_BIT (seen, get_stmt_uid (stmt));
*seen_call_stmt = false;
while (in_queue)
{
stmt = queue[--in_queue];
sra_data.stmt = stmt;
if (LIM_DATA (stmt)
&& LIM_DATA (stmt)->sm_done)
goto fail;
switch (TREE_CODE (stmt))
{
case MODIFY_EXPR:
case CALL_EXPR:
case RETURN_EXPR:
if (!for_each_memref (stmt, fem_single_reachable_address,
&sra_data))
goto fail;
/* If this is a function that may depend on the memory location,
record the fact. We cannot directly refuse call clobbered
operands here, since sra_data.common_ref did not have
to be set yet. */
call = get_call_expr_in (stmt);
if (call
&& !(call_expr_flags (call) & ECF_CONST))
*seen_call_stmt = true;
/* Traverse also definitions of the VUSES (there may be other
distinct from the one we used to get to this statement). */
FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter, SSA_OP_VIRTUAL_USES)
maybe_queue_var (val, loop, seen, queue, &in_queue);
break;
case PHI_NODE:
for (i = 0; i < (unsigned) PHI_NUM_ARGS (stmt); i++)
if (TREE_CODE (PHI_ARG_DEF (stmt, i)) == SSA_NAME)
maybe_queue_var (PHI_ARG_DEF (stmt, i), loop,
seen, queue, &in_queue);
break;
default:
goto fail;
}
/* Find uses of virtual names. */
if (TREE_CODE (stmt) == PHI_NODE)
{
if (!is_gimple_reg (SSA_NAME_VAR (PHI_RESULT (stmt))))
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, PHI_RESULT (stmt))
{
tree imm_stmt = USE_STMT (use_p);
if (TEST_BIT (seen, get_stmt_uid (imm_stmt)))
continue;
if (!flow_bb_inside_loop_p (loop, bb_for_stmt (imm_stmt)))
continue;
SET_BIT (seen, get_stmt_uid (imm_stmt));
queue[in_queue++] = imm_stmt;
}
}
else
FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter, SSA_OP_VIRTUAL_DEFS)
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, val)
{
tree imm_stmt = USE_STMT (use_p);
if (TEST_BIT (seen, get_stmt_uid (imm_stmt)))
continue;
if (!flow_bb_inside_loop_p (loop, bb_for_stmt (imm_stmt)))
continue;
SET_BIT (seen, get_stmt_uid (imm_stmt));
queue[in_queue++] = imm_stmt;
}
}
free (queue);
sbitmap_free (seen);
return sra_data.common_ref;
fail:
free_mem_refs (*mem_refs);
*mem_refs = NULL;
free (queue);
sbitmap_free (seen);
return NULL;
}
/* Rewrites memory references in list MEM_REFS by variable TMP_VAR. */ /* Rewrites memory references in list MEM_REFS by variable TMP_VAR. */
static void static void
rewrite_mem_refs (tree tmp_var, struct mem_ref *mem_refs) rewrite_mem_refs (tree tmp_var, struct mem_ref_loc *mem_refs)
{ {
tree var; tree var;
ssa_op_iter iter; ssa_op_iter iter;
...@@ -1143,9 +916,9 @@ rewrite_mem_refs (tree tmp_var, struct mem_ref *mem_refs) ...@@ -1143,9 +916,9 @@ rewrite_mem_refs (tree tmp_var, struct mem_ref *mem_refs)
static void static void
schedule_sm (struct loop *loop, edge *exits, unsigned n_exits, tree ref, schedule_sm (struct loop *loop, edge *exits, unsigned n_exits, tree ref,
struct mem_ref *mem_refs) struct mem_ref_loc *mem_refs)
{ {
struct mem_ref *aref; struct mem_ref_loc *aref;
tree tmp_var; tree tmp_var;
unsigned i; unsigned i;
tree load, store; tree load, store;
...@@ -1187,104 +960,31 @@ schedule_sm (struct loop *loop, edge *exits, unsigned n_exits, tree ref, ...@@ -1187,104 +960,31 @@ schedule_sm (struct loop *loop, edge *exits, unsigned n_exits, tree ref,
} }
} }
/* Returns true if REF may be clobbered by calls. */ /* Check whether memory reference REF can be hoisted out of the LOOP. If this
is true, prepare the statements that load the value of the memory reference
static bool to a temporary variable in the loop preheader, store it back on the loop
is_call_clobbered_ref (tree ref) exits, and replace all the references inside LOOP by this temporary variable.
{ LOOP has N_EXITS stored in EXITS. CLOBBERED_VOPS is the bitmap of virtual
tree base; operands that are clobbered by a call or accessed through multiple references
HOST_WIDE_INT offset, size; in loop. */
subvar_t sv;
subvar_t svars;
tree sref = ref;
if (TREE_CODE (sref) == COMPONENT_REF
&& (sref = okay_component_ref_for_subvars (sref, &offset, &size)))
{
svars = get_subvars_for_var (sref);
for (sv = svars; sv; sv = sv->next)
{
if (overlap_subvar (offset, size, sv, NULL)
&& is_call_clobbered (sv->var))
return true;
}
}
base = get_base_address (ref);
if (!base)
return true;
if (DECL_P (base))
{
if (var_can_have_subvars (base)
&& (svars = get_subvars_for_var (base)))
{
for (sv = svars; sv; sv = sv->next)
if (is_call_clobbered (sv->var))
return true;
return false;
}
else
return is_call_clobbered (base);
}
if (INDIRECT_REF_P (base))
{
/* Check whether the alias tags associated with the pointer
are call clobbered. */
tree ptr = TREE_OPERAND (base, 0);
struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
tree nmt = (pi) ? pi->name_mem_tag : NULL_TREE;
tree tmt = var_ann (SSA_NAME_VAR (ptr))->type_mem_tag;
if ((nmt && is_call_clobbered (nmt))
|| (tmt && is_call_clobbered (tmt)))
return true;
return false;
}
gcc_unreachable ();
}
/* Determine whether all memory references inside LOOP corresponding to the
virtual ssa name REG are equal to each other, and whether the address of
this common reference can be hoisted outside of the loop. If this is true,
prepare the statements that load the value of the memory reference to a
temporary variable in the loop preheader, store it back on the loop exits,
and replace all the references inside LOOP by this temporary variable.
LOOP has N_EXITS stored in EXITS. */
static void static void
determine_lsm_reg (struct loop *loop, edge *exits, unsigned n_exits, tree reg) determine_lsm_ref (struct loop *loop, edge *exits, unsigned n_exits,
bitmap clobbered_vops, struct mem_ref *ref)
{ {
tree ref; struct mem_ref_loc *aref;
struct mem_ref *mem_refs, *aref;
struct loop *must_exec; struct loop *must_exec;
bool sees_call;
if (is_gimple_reg (reg))
return;
ref = single_reachable_address (loop, SSA_NAME_DEF_STMT (reg), &mem_refs,
&sees_call);
if (!ref)
return;
/* If we cannot create a ssa name for the result, give up. */ /* In case the memory is not stored to, there is nothing for SM to do. */
if (!is_gimple_reg_type (TREE_TYPE (ref)) if (!ref->is_stored)
|| TREE_THIS_VOLATILE (ref)) return;
goto fail;
/* If there is a call that may use the location, give up as well. */
if (sees_call
&& is_call_clobbered_ref (ref))
goto fail;
if (!for_each_index (&ref, may_move_till, loop)) /* If the reference is aliased with any different ref, or killed by call
goto fail; in function, then fail. */
if (bitmap_intersect_p (ref->vops, clobbered_vops))
return;
if (tree_could_trap_p (ref)) if (tree_could_trap_p (ref->mem))
{ {
/* If the memory access is unsafe (i.e. it might trap), ensure that some /* If the memory access is unsafe (i.e. it might trap), ensure that some
of the statements in that it occurs is always executed when the loop of the statements in that it occurs is always executed when the loop
...@@ -1297,7 +997,7 @@ determine_lsm_reg (struct loop *loop, edge *exits, unsigned n_exits, tree reg) ...@@ -1297,7 +997,7 @@ determine_lsm_reg (struct loop *loop, edge *exits, unsigned n_exits, tree reg)
least one of the statements containing the memory reference is least one of the statements containing the memory reference is
executed. */ executed. */
for (aref = mem_refs; aref; aref = aref->next) for (aref = ref->locs; aref; aref = aref->next)
{ {
if (!LIM_DATA (aref->stmt)) if (!LIM_DATA (aref->stmt))
continue; continue;
...@@ -1312,13 +1012,34 @@ determine_lsm_reg (struct loop *loop, edge *exits, unsigned n_exits, tree reg) ...@@ -1312,13 +1012,34 @@ determine_lsm_reg (struct loop *loop, edge *exits, unsigned n_exits, tree reg)
} }
if (!aref) if (!aref)
goto fail; return;
} }
schedule_sm (loop, exits, n_exits, ref, mem_refs); schedule_sm (loop, exits, n_exits, ref->mem, ref->locs);
}
/* Attempts to hoist memory reference described in SLOT out of loop
described in DATA. Callback for htab_traverse. */
fail: ; struct hmr_data
free_mem_refs (mem_refs); {
struct loop *loop; /* Loop from that the reference should be hoisted. */
edge *exits; /* Exits of the loop. */
unsigned n_exits; /* Length of the exits array. */
bitmap clobbered_vops;/* The vops clobbered by call in loop or accessed by
multiple memory references. */
};
static int
hoist_memory_reference (void **slot, void *data)
{
struct mem_ref *ref = *slot;
struct hmr_data *hmr_data = data;
determine_lsm_ref (hmr_data->loop, hmr_data->exits, hmr_data->n_exits,
hmr_data->clobbered_vops, ref);
return 1;
} }
/* Checks whether LOOP (with N_EXITS exits stored in EXITS array) is suitable /* Checks whether LOOP (with N_EXITS exits stored in EXITS array) is suitable
...@@ -1338,15 +1059,187 @@ loop_suitable_for_sm (struct loop *loop ATTRIBUTE_UNUSED, edge *exits, ...@@ -1338,15 +1059,187 @@ loop_suitable_for_sm (struct loop *loop ATTRIBUTE_UNUSED, edge *exits,
return true; return true;
} }
/* A hash function for struct mem_ref object OBJ. */
static hashval_t
memref_hash (const void *obj)
{
const struct mem_ref *mem = obj;
return mem->hash;
}
/* An equality function for struct mem_ref object OBJ1 with
memory reference OBJ2. */
static int
memref_eq (const void *obj1, const void *obj2)
{
const struct mem_ref *mem1 = obj1;
return operand_equal_p (mem1->mem, (tree) obj2, 0);
}
/* A function to free the struct mem_ref object OBJ. */
static void
memref_del (void *obj)
{
struct mem_ref *mem = obj;
free_mem_ref_locs (mem->locs);
BITMAP_FREE (mem->vops);
free (mem);
}
/* Gathers memory references in statement STMT in LOOP, storing the
information about them in MEM_REFS hash table. Note vops accessed through
unrecognized statements in CLOBBERED_VOPS. */
static void
gather_mem_refs_stmt (struct loop *loop, htab_t mem_refs,
bitmap clobbered_vops, tree stmt)
{
tree *lhs, *rhs, *mem = NULL;
hashval_t hash;
PTR *slot;
struct mem_ref *ref = NULL;
ssa_op_iter oi;
tree vname;
bool is_stored;
if (ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
return;
/* Recognize MEM = (SSA_NAME | invariant) and SSA_NAME = MEM patterns. */
if (TREE_CODE (stmt) != MODIFY_EXPR)
goto fail;
lhs = &TREE_OPERAND (stmt, 0);
rhs = &TREE_OPERAND (stmt, 1);
if (TREE_CODE (*lhs) == SSA_NAME)
{
if (!is_gimple_addressable (*rhs))
goto fail;
mem = rhs;
is_stored = false;
}
else if (TREE_CODE (*rhs) == SSA_NAME
|| is_gimple_min_invariant (*rhs))
{
mem = lhs;
is_stored = true;
}
else
goto fail;
/* If we cannot create an SSA name for the result, give up. */
if (!is_gimple_reg_type (TREE_TYPE (*mem))
|| TREE_THIS_VOLATILE (*mem))
goto fail;
/* If we cannot move the reference out of the loop, fail. */
if (!for_each_index (mem, may_move_till, loop))
goto fail;
hash = iterative_hash_expr (*mem, 0);
slot = htab_find_slot_with_hash (mem_refs, *mem, hash, INSERT);
if (*slot)
ref = *slot;
else
{
ref = xmalloc (sizeof (struct mem_ref));
ref->mem = *mem;
ref->hash = hash;
ref->locs = NULL;
ref->is_stored = false;
ref->vops = BITMAP_ALLOC (NULL);
*slot = ref;
}
ref->is_stored |= is_stored;
FOR_EACH_SSA_TREE_OPERAND (vname, stmt, oi,
SSA_OP_VIRTUAL_USES | SSA_OP_VIRTUAL_KILLS)
{
bitmap_set_bit (ref->vops,
var_ann (SSA_NAME_VAR (vname))->uid);
}
record_mem_ref_loc (&ref->locs, stmt, mem);
return;
fail:
FOR_EACH_SSA_TREE_OPERAND (vname, stmt, oi,
SSA_OP_VIRTUAL_USES | SSA_OP_VIRTUAL_KILLS)
{
bitmap_set_bit (clobbered_vops,
var_ann (SSA_NAME_VAR (vname))->uid);
}
}
/* Gathers memory references in LOOP, storing the information about them
in MEM_REFS hash table. Note vops accessed through unrecognized
statements in CLOBBERED_VOPS. */
static void
gather_mem_refs (struct loop *loop, htab_t mem_refs, bitmap clobbered_vops)
{
basic_block *body = get_loop_body (loop);
block_stmt_iterator bsi;
unsigned i;
for (i = 0; i < loop->num_nodes; i++)
{
for (bsi = bsi_start (body[i]); !bsi_end_p (bsi); bsi_next (&bsi))
gather_mem_refs_stmt (loop, mem_refs, clobbered_vops, bsi_stmt (bsi));
}
free (body);
}
/* Finds the vops accessed by memory reference described in SLOT as well as
some other reference(s) and marks them in DATA->clobbered_vops.
Callback for htab_traverse. */
struct fmrv_data
{
bitmap clobbered_vops; /* The vops clobbered by call in loop or accessed by
multiple memory references. */
bitmap all_vops; /* All vops referenced in the loop. */
};
static int
find_more_ref_vops (void **slot, void *data)
{
struct mem_ref *ref = *slot;
struct fmrv_data *fmrv_data = data;
bitmap_head tmp;
/* The vops that are already in all_vops are accessed by more than
one memory reference. */
bitmap_initialize (&tmp, &bitmap_default_obstack);
bitmap_and (&tmp, fmrv_data->all_vops, ref->vops);
bitmap_ior_into (fmrv_data->clobbered_vops, &tmp);
bitmap_clear (&tmp);
bitmap_ior_into (fmrv_data->all_vops, ref->vops);
return 1;
}
/* Try to perform store motion for all memory references modified inside /* Try to perform store motion for all memory references modified inside
LOOP. */ LOOP. */
static void static void
determine_lsm_loop (struct loop *loop) determine_lsm_loop (struct loop *loop)
{ {
tree phi;
unsigned n_exits; unsigned n_exits;
edge *exits = get_loop_exit_edges (loop, &n_exits); edge *exits = get_loop_exit_edges (loop, &n_exits);
htab_t mem_refs;
struct hmr_data hmr_data;
struct fmrv_data fmrv_data;
bitmap clobbered_vops;
if (!loop_suitable_for_sm (loop, exits, n_exits)) if (!loop_suitable_for_sm (loop, exits, n_exits))
{ {
...@@ -1354,10 +1247,28 @@ determine_lsm_loop (struct loop *loop) ...@@ -1354,10 +1247,28 @@ determine_lsm_loop (struct loop *loop)
return; return;
} }
for (phi = phi_nodes (loop->header); phi; phi = PHI_CHAIN (phi)) mem_refs = htab_create (100, memref_hash, memref_eq, memref_del);
determine_lsm_reg (loop, exits, n_exits, PHI_RESULT (phi));
/* Find the memory references in LOOP. */
clobbered_vops = BITMAP_ALLOC (NULL);
gather_mem_refs (loop, mem_refs, clobbered_vops);
/* Find the vops that are used for more than one reference. */
fmrv_data.all_vops = BITMAP_ALLOC (NULL);
fmrv_data.clobbered_vops = clobbered_vops;
htab_traverse (mem_refs, find_more_ref_vops, &fmrv_data);
BITMAP_FREE (fmrv_data.all_vops);
/* Hoist all suitable memory references. */
hmr_data.loop = loop;
hmr_data.exits = exits;
hmr_data.n_exits = n_exits;
hmr_data.clobbered_vops = clobbered_vops;
htab_traverse (mem_refs, hoist_memory_reference, &hmr_data);
htab_delete (mem_refs);
free (exits); free (exits);
BITMAP_FREE (clobbered_vops);
} }
/* Try to perform store motion for all memory references modified inside /* Try to perform store motion for all memory references modified inside
...@@ -1367,25 +1278,12 @@ static void ...@@ -1367,25 +1278,12 @@ static void
determine_lsm (struct loops *loops) determine_lsm (struct loops *loops)
{ {
struct loop *loop; struct loop *loop;
basic_block bb;
if (!loops->tree_root->inner) if (!loops->tree_root->inner)
return; return;
/* Create a UID for each statement in the function. Ordering of the /* Pass the loops from the outermost and perform the store motion as
UIDs is not important for this pass. */ suitable. */
max_stmt_uid = 0;
FOR_EACH_BB (bb)
{
block_stmt_iterator bsi;
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
stmt_ann (bsi_stmt (bsi))->uid = max_stmt_uid++;
}
/* Pass the loops from the outermost. For each virtual operand loop phi node
check whether all the references inside the loop correspond to a single
address, and if so, move them. */
loop = loops->tree_root->inner; loop = loops->tree_root->inner;
while (1) while (1)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment