OSDN Git Service

2005-03-18 Daniel Berlin <dberlin@dberlin.org>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-loop-im.c
index de86491..51ada3d 100644 (file)
@@ -1,5 +1,5 @@
 /* Loop invariant motion.
-   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
    
 This file is part of GCC.
    
@@ -38,6 +38,28 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tree-pass.h"
 #include "flags.h"
 
+/* TODO:  Support for predicated code motion.  I.e.
+
+   while (1)
+     {
+       if (cond)
+        {
+          a = inv;
+          something;
+        }
+     }
+
+   Where COND and INV are is invariants, but evaluating INV may trap or be
+   invalid from some other reason if !COND.  This may be transformed to
+
+   if (cond)
+     a = inv;
+   while (1)
+     {
+       if (cond)
+        something;
+     }  */
+
 /* A type for the list of statements that have to be moved in order to be able
    to hoist an invariant computation.  */
 
@@ -128,7 +150,7 @@ get_stmt_uid (tree stmt)
 bool
 for_each_index (tree *addr_p, bool (*cbck) (tree, tree *, void *), void *data)
 {
-  tree *nxt;
+  tree *nxt, *idx;
 
   for (; ; addr_p = nxt)
     {
@@ -137,12 +159,13 @@ for_each_index (tree *addr_p, bool (*cbck) (tree, tree *, void *), void *data)
        case SSA_NAME:
          return cbck (*addr_p, addr_p, data);
 
+       case MISALIGNED_INDIRECT_REF:
+       case ALIGN_INDIRECT_REF:
        case INDIRECT_REF:
          nxt = &TREE_OPERAND (*addr_p, 0);
          return cbck (*addr_p, nxt, data);
 
        case BIT_FIELD_REF:
-       case COMPONENT_REF:
        case VIEW_CONVERT_EXPR:
        case ARRAY_RANGE_REF:
        case REALPART_EXPR:
@@ -150,6 +173,17 @@ for_each_index (tree *addr_p, bool (*cbck) (tree, tree *, void *), void *data)
          nxt = &TREE_OPERAND (*addr_p, 0);
          break;
 
+       case COMPONENT_REF:
+         /* If the component has varying offset, it behaves like index
+            as well.  */
+         idx = &TREE_OPERAND (*addr_p, 2);
+         if (*idx
+             && !cbck (*addr_p, idx, data))
+           return false;
+
+         nxt = &TREE_OPERAND (*addr_p, 0);
+         break;
+
        case ARRAY_REF:
          nxt = &TREE_OPERAND (*addr_p, 0);
          if (!cbck (*addr_p, &TREE_OPERAND (*addr_p, 1), data))
@@ -215,6 +249,28 @@ movement_possibility (tree stmt)
       || tree_could_trap_p (rhs))
     return MOVE_PRESERVE_EXECUTION;
 
+  if (get_call_expr_in (stmt))
+    {
+      /* While pure or const call is guaranteed to have no side effects, we
+        cannot move it arbitrarily.  Consider code like
+
+        char *s = something ();
+
+        while (1)
+          {
+            if (s)
+              t = strlen (s);
+            else
+              t = 0;
+          }
+
+        Here the strlen call cannot be moved out of the loop, even though
+        s is invariant.  In addition to possibly creating a call with
+        invalid arguments, moving out a function call that is not executed
+        may cause performance regressions in case the call is costly and
+        not executed at all.  */
+      return MOVE_PRESERVE_EXECUTION;
+    }
   return MOVE_POSSIBLE;
 }
 
@@ -271,7 +327,7 @@ outermost_invariant_loop_expr (tree expr, struct loop *loop)
       && class != tcc_comparison)
     return NULL;
 
-  nops = first_rtl_op (TREE_CODE (expr));
+  nops = TREE_CODE_LENGTH (TREE_CODE (expr));
   for (i = 0; i < nops; i++)
     {
       aloop = outermost_invariant_loop_expr (TREE_OPERAND (expr, i), loop);
@@ -342,20 +398,17 @@ add_dependency (tree def, struct lim_aux_data *data, struct loop *loop,
 static unsigned
 stmt_cost (tree stmt)
 {
-  tree lhs, rhs;
+  tree rhs;
   unsigned cost = 1;
 
   /* Always try to create possibilities for unswitching.  */
   if (TREE_CODE (stmt) == COND_EXPR)
     return LIM_EXPENSIVE;
 
-  lhs = TREE_OPERAND (stmt, 0);
   rhs = TREE_OPERAND (stmt, 1);
 
   /* Hoisting memory references out should almost surely be a win.  */
-  if (!is_gimple_variable (lhs))
-    cost += 20;
-  if (is_gimple_addressable (rhs) && !is_gimple_variable (rhs))
+  if (stmt_references_memory_p (stmt))
     cost += 20;
 
   switch (TREE_CODE (rhs))
@@ -366,7 +419,7 @@ stmt_cost (tree stmt)
       /* Unless the call is a builtin_constant_p; this always folds to a
         constant, so moving it is useless.  */
       rhs = get_callee_fndecl (rhs);
-      if (DECL_BUILT_IN (rhs)
+      if (DECL_BUILT_IN_CLASS (rhs) == BUILT_IN_NORMAL
          && DECL_FUNCTION_CODE (rhs) == BUILT_IN_CONSTANT_P)
        return 0;
 
@@ -424,7 +477,7 @@ determine_max_movement (tree stmt, bool must_preserve_exec)
     if (!add_dependency (val, lim_data, loop, true))
       return false;
 
-  FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter, SSA_OP_VIRTUAL_USES)
+  FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter, SSA_OP_VIRTUAL_USES | SSA_OP_VIRTUAL_KILLS)
     if (!add_dependency (val, lim_data, loop, false))
       return false;
 
@@ -586,13 +639,13 @@ loop_commit_inserts (void)
   basic_block bb;
 
   old_last_basic_block = last_basic_block;
-  bsi_commit_edge_inserts (NULL);
+  bsi_commit_edge_inserts ();
   for (i = old_last_basic_block; i < (unsigned) last_basic_block; i++)
     {
       bb = BASIC_BLOCK (i);
       add_bb_to_loop (bb,
-                     find_common_loop (bb->succ->dest->loop_father,
-                                       bb->pred->src->loop_father));
+                     find_common_loop (single_pred (bb)->loop_father,
+                                       single_succ (bb)->loop_father));
     }
 }
 
@@ -667,12 +720,12 @@ move_computations (void)
 
   loop_commit_inserts ();
   rewrite_into_ssa (false);
-  if (bitmap_first_set_bit (vars_to_rename) >= 0)
+  if (!bitmap_empty_p (vars_to_rename))
     {
       /* The rewrite of ssa names may cause violation of loop closed ssa
         form invariants.  TODO -- avoid these rewrites completely.
         Information in virtual phi nodes is sufficient for it.  */
-      rewrite_into_loop_closed_ssa ();
+      rewrite_into_loop_closed_ssa (NULL);
     }
   bitmap_clear (vars_to_rename);
 }
@@ -733,7 +786,7 @@ force_move_till_expr (tree expr, struct loop *orig_loop, struct loop *loop)
       && class != tcc_comparison)
     return;
 
-  nops = first_rtl_op (TREE_CODE (expr));
+  nops = TREE_CODE_LENGTH (TREE_CODE (expr));
   for (i = 0; i < nops; i++)
     force_move_till_expr (TREE_OPERAND (expr, i), orig_loop, loop);
 }
@@ -970,8 +1023,9 @@ single_reachable_address (struct loop *loop, tree stmt,
 
        case PHI_NODE:
          for (i = 0; i < (unsigned) PHI_NUM_ARGS (stmt); i++)
-           maybe_queue_var (PHI_ARG_DEF (stmt, i), loop,
-                            seen, queue, &in_queue);
+           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:
@@ -1021,8 +1075,7 @@ rewrite_mem_refs (tree tmp_var, struct mem_ref *mem_refs)
 
   for (; mem_refs; mem_refs = mem_refs->next)
     {
-      FOR_EACH_SSA_TREE_OPERAND (var, mem_refs->stmt, iter,
-                                (SSA_OP_VIRTUAL_DEFS | SSA_OP_VUSE))
+      FOR_EACH_SSA_TREE_OPERAND (var, mem_refs->stmt, iter, SSA_OP_ALL_VIRTUALS)
        {
          var = SSA_NAME_VAR (var);
          bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
@@ -1093,15 +1146,42 @@ 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))
-    return is_call_clobbered (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 (TREE_CODE (base) == INDIRECT_REF)
+  if (INDIRECT_REF_P (base))
     {
       /* Check whether the alias tags associated with the pointer
         are call clobbered.  */
@@ -1227,7 +1307,7 @@ determine_lsm_loop (struct loop *loop)
       return;
     }
 
-  for (phi = phi_nodes (loop->header); phi; phi = TREE_CHAIN (phi))
+  for (phi = phi_nodes (loop->header); phi; phi = PHI_CHAIN (phi))
     determine_lsm_reg (loop, exits, n_exits, PHI_RESULT (phi));
 
   free (exits);
@@ -1242,6 +1322,9 @@ 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;
@@ -1302,6 +1385,7 @@ fill_always_executed_in (struct loop *loop, sbitmap contains_call)
 
       for (i = 0; i < loop->num_nodes; i++)
        {
+         edge_iterator ei;
          bb = bbs[i];
 
          if (dominated_by_p (CDI_DOMINATORS, loop->latch, bb))
@@ -1310,7 +1394,7 @@ fill_always_executed_in (struct loop *loop, sbitmap contains_call)
          if (TEST_BIT (contains_call, bb->index))
            break;
 
-         for (e = bb->succ; e; e = e->succ_next)
+         FOR_EACH_EDGE (e, ei, bb->succs)
            if (!flow_bb_inside_loop_p (loop, e->dest))
              break;
          if (e)