diff options
| -rw-r--r-- | gcc/ChangeLog | 18 | ||||
| -rw-r--r-- | gcc/tree-ssa-loop-im.c | 634 | 
2 files changed, 284 insertions, 368 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index efaf6ea3743..4cd2728a7d2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +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>  	* config/s390/s390.md: Add comment lines for 'f' and 't' constraint diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c index 88a621af4ef..810f3cf02b2 100644 --- a/gcc/tree-ssa-loop-im.c +++ b/gcc/tree-ssa-loop-im.c @@ -38,6 +38,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA  #include "tree-pass.h"  #include "flags.h"  #include "real.h" +#include "hashtab.h"  /* TODO:  Support for predicated code motion.  I.e. @@ -103,13 +104,26 @@ struct lim_aux_data  			? NULL \  			: (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 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.  */ @@ -119,21 +133,6 @@ struct mem_ref     block will be executed.  */  #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     kinds situations handled; in each of these cases, the memory reference     and DATA are passed to the callback: @@ -859,13 +858,13 @@ force_move_till (tree ref, tree *index, void *data)    return true;  } -/* Records memory reference *REF (that occurs in statement STMT) -   to the list MEM_REFS.  */ +/* Records memory reference location *REF to the list MEM_REFS.  The reference +   occurs in statement STMT.  */  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->ref = ref; @@ -874,12 +873,12 @@ record_mem_ref (struct mem_ref **mem_refs, tree stmt, tree *ref)    *mem_refs = aref;  } -/* Releases list of memory references MEM_REFS.  */ +/* Releases list of memory reference locations MEM_REFS.  */  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)      { @@ -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.  */  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;    ssa_op_iter iter; @@ -1143,9 +916,9 @@ rewrite_mem_refs (tree tmp_var, struct mem_ref *mem_refs)  static void  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;    unsigned i;    tree load, store; @@ -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.  */ - -static bool -is_call_clobbered_ref (tree ref) -{ -  tree base; -  HOST_WIDE_INT offset, size; -  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.  */ +/* 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 +   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.  CLOBBERED_VOPS is the bitmap of virtual +   operands that are clobbered by a call or accessed through multiple references +   in loop.  */  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 *mem_refs, *aref; +  struct mem_ref_loc *aref;    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.  */ -  if (!is_gimple_reg_type (TREE_TYPE (ref)) -      || TREE_THIS_VOLATILE (ref)) -    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; +  /* In case the memory is not stored to, there is nothing for SM to do.  */ +  if (!ref->is_stored) +    return; -  if (!for_each_index (&ref, may_move_till, loop)) -    goto fail; +  /* If the reference is aliased with any different ref, or killed by call +     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  	 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)  	 least one of the statements containing the memory reference is  	 executed.  */ -      for (aref = mem_refs; aref; aref = aref->next) +      for (aref = ref->locs; aref; aref = aref->next)  	{  	  if (!LIM_DATA (aref->stmt))  	    continue; @@ -1312,13 +1012,34 @@ determine_lsm_reg (struct loop *loop, edge *exits, unsigned n_exits, tree reg)  	}        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: ; -  free_mem_refs (mem_refs); +struct hmr_data +{ +  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 @@ -1338,15 +1059,187 @@ loop_suitable_for_sm (struct loop *loop ATTRIBUTE_UNUSED, edge *exits,    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     LOOP.  */  static void  determine_lsm_loop (struct loop *loop)  { -  tree phi;    unsigned 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))      { @@ -1354,10 +1247,28 @@ determine_lsm_loop (struct loop *loop)        return;      } -  for (phi = phi_nodes (loop->header); phi; phi = PHI_CHAIN (phi)) -    determine_lsm_reg (loop, exits, n_exits, PHI_RESULT (phi)); +  mem_refs = htab_create (100, memref_hash, memref_eq, memref_del); + +  /* 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); +  BITMAP_FREE (clobbered_vops);  }  /* Try to perform store motion for all memory references modified inside @@ -1367,25 +1278,12 @@ static void  determine_lsm (struct loops *loops)  {    struct loop *loop; -  basic_block bb;    if (!loops->tree_root->inner)      return; -  /* Create a UID for each statement in the function.  Ordering of the -     UIDs is not important for this pass.  */ -  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.  */ +  /* Pass the loops from the outermost and perform the store motion as +     suitable.  */    loop = loops->tree_root->inner;    while (1)  | 

