tree-ssa-loop-im.c (fem_single_reachable_address, [...]): New functions.
authorZdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
Mon, 23 Aug 2004 08:17:20 +0000 (10:17 +0200)
committerZdenek Dvorak <rakdver@gcc.gnu.org>
Mon, 23 Aug 2004 08:17:20 +0000 (08:17 +0000)
* tree-ssa-loop-im.c (fem_single_reachable_address, for_each_memref):
New functions.
(single_reachable_address): Use them.
(schedule_sm): Add dump.
(is_call_clobbered_ref): New function.
(determine_lsm_reg): Check whether the reference is call clobbered.
Only work for gimple_reg_type values.

From-SVN: r86418

gcc/ChangeLog
gcc/tree-ssa-loop-im.c

index 7beb5cb8577eb1f4bd8c11d9ceea9617dcb1e488..c68a2ed73e55b84641bd22bbbfda0403c4ee09a3 100644 (file)
@@ -1,3 +1,13 @@
+2004-08-23  Zdenek Dvorak  <rakdver@atrey.karlin.mff.cuni.cz>
+
+       * tree-ssa-loop-im.c (fem_single_reachable_address, for_each_memref):
+       New functions.
+       (single_reachable_address): Use them.
+       (schedule_sm): Add dump.
+       (is_call_clobbered_ref): New function.
+       (determine_lsm_reg): Check whether the reference is call clobbered.
+       Only work for gimple_reg_type values.
+
 2004-08-23  Richard Sandiford  <rsandifo@redhat.com>
 
        * config/mips/mips.md (*mov<mode>_ra): Name previously unnamed MIPS16
index 3d2d1c6a7a9933e655fe4e985ce21eecbbe17a1b..de2540aa4f2c28f622a0418e04bad8d0a493af16 100644 (file)
@@ -833,34 +833,118 @@ maybe_queue_var (tree var, struct loop *loop,
   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.  */
+   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)
+                         struct mem_ref **mem_refs,
+                         bool *seen_call_stmt)
 {
   tree *queue = xmalloc (sizeof (tree) * max_uid);
   sbitmap seen = sbitmap_alloc (max_uid);
-  tree common_ref = NULL, *aref;
   unsigned in_queue = 1;
   dataflow_t df;
   unsigned i, n;
   v_may_def_optype v_may_defs;
   vuse_optype vuses;
+  struct sra_data sra_data;
+  tree call;
 
   sbitmap_zero (seen);
 
   *mem_refs = NULL;
+  sra_data.mem_refs = mem_refs;
+  sra_data.common_ref = NULL_TREE;
 
   queue[0] = stmt;
   SET_BIT (seen, stmt_ann (stmt)->uid);
+  *seen_call_stmt = false;
 
   while (in_queue)
     {
       stmt = queue[--in_queue];
+      sra_data.stmt = stmt;
 
       if (LIM_DATA (stmt)
          && LIM_DATA (stmt)->sm_done)
@@ -869,17 +953,20 @@ single_reachable_address (struct loop *loop, tree stmt,
       switch (TREE_CODE (stmt))
        {
        case MODIFY_EXPR:
-         aref = &TREE_OPERAND (stmt, 0);
-         if (is_gimple_reg (*aref)
-             || !is_gimple_lvalue (*aref))
-           aref = &TREE_OPERAND (stmt, 1);
-         if (is_gimple_reg (*aref)
-             || !is_gimple_lvalue (*aref)
-             || (common_ref && !operand_equal_p (*aref, common_ref, 0)))
+       case CALL_EXPR:
+       case RETURN_EXPR:
+         if (!for_each_memref (stmt, fem_single_reachable_address,
+                               &sra_data))
            goto fail;
-         common_ref = *aref;
 
-         record_mem_ref (mem_refs, stmt, aref);
+         /* 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).  */
@@ -926,7 +1013,7 @@ single_reachable_address (struct loop *loop, tree stmt,
   free (queue);
   sbitmap_free (seen);
 
-  return common_ref;
+  return sra_data.common_ref;
 
 fail:
   free_mem_refs (*mem_refs);
@@ -994,6 +1081,13 @@ schedule_sm (struct loop *loop, edge *exits, unsigned n_exits, tree ref,
   tree load, store;
   struct fmt_data fmt_data;
 
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Executing store motion of ");
+      print_generic_expr (dump_file, ref, 0);
+      fprintf (dump_file, " from loop %d\n", loop->num);
+    }
+
   tmp_var = make_rename_temp (TREE_TYPE (ref), "lsm_tmp");
 
   fmt_data.loop = loop;
@@ -1023,6 +1117,39 @@ 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;
+
+  base = get_base_address (ref);
+  if (!base)
+    return true;
+
+  if (DECL_P (base))
+    return is_call_clobbered (base);
+
+  if (TREE_CODE (base) == INDIRECT_REF)
+    {
+      /* 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;
+    }
+
+  abort ();
+}
+
 /* 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,
@@ -1037,19 +1164,28 @@ determine_lsm_reg (struct loop *loop, edge *exits, unsigned n_exits, tree reg)
   tree ref;
   struct mem_ref *mem_refs, *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);
+  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;
+
   if (!for_each_index (&ref, may_move_till, loop))
-    {
-      free_mem_refs (mem_refs);
-      return;
-    }
+    goto fail;
 
   if (tree_could_trap_p (ref))
     {
@@ -1079,13 +1215,12 @@ determine_lsm_reg (struct loop *loop, edge *exits, unsigned n_exits, tree reg)
        }
 
       if (!aref)
-       {
-         free_mem_refs (mem_refs);
-         return;
-       }
+       goto fail;
     }
 
   schedule_sm (loop, exits, n_exits, ref, mem_refs);
+
+fail: ;
   free_mem_refs (mem_refs);
 }