OSDN Git Service

* config/fp-bit.h (LSHIFT): Take shift count parameter.
[pf3gnuchains/gcc-fork.git] / gcc / loop-invariant.c
index 21dc8b8..8fe549b 100644 (file)
@@ -1,5 +1,5 @@
 /* Rtl-level loop invariant motion.
-   Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
    
 This file is part of GCC.
    
@@ -15,8 +15,8 @@ for more details.
    
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 /* This implements the loop invariant motion pass.  It is very simple
    (no calls, libcalls, etc.).  This should be sufficient to cleanup things like
@@ -40,7 +40,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "coretypes.h"
 #include "tm.h"
 #include "rtl.h"
+#include "tm_p.h"
 #include "hard-reg-set.h"
+#include "obstack.h"
 #include "basic-block.h"
 #include "cfgloop.h"
 #include "expr.h"
@@ -117,9 +119,14 @@ struct invariant
 
 static unsigned actual_stamp;
 
+typedef struct invariant *invariant_p;
+
+DEF_VEC_P(invariant_p);
+DEF_VEC_ALLOC_P(invariant_p, heap);
+
 /* The invariants.  */
 
-static varray_type invariants;
+static VEC(invariant_p,heap) *invariants;
 
 /* Test for possibility of invariantness of X.  */
 
@@ -285,7 +292,10 @@ find_exits (struct loop *loop, basic_block *body,
 static bool
 may_assign_reg_p (rtx x)
 {
-  return can_copy_p (GET_MODE (x));
+  return (can_copy_p (GET_MODE (x))
+         && (!REG_P (x)
+             || !HARD_REGISTER_P (x)
+             || REGNO_REG_CLASS (REGNO (x)) != NO_REGS));
 }
 
 /* Finds definitions that may correspond to invariants in LOOP with body BODY.
@@ -295,13 +305,13 @@ static void
 find_defs (struct loop *loop, basic_block *body, struct df *df)
 {
   unsigned i;
-  bitmap blocks = BITMAP_XMALLOC ();
+  bitmap blocks = BITMAP_ALLOC (NULL);
 
   for (i = 0; i < loop->num_nodes; i++)
     bitmap_set_bit (blocks, body[i]->index);
 
   df_analyze_subcfg (df, blocks, DF_UD_CHAIN | DF_HARD_REGS | DF_EQUIV_NOTES);
-  BITMAP_XFREE (blocks);
+  BITMAP_FREE (blocks);
 }
 
 /* Creates a new invariant for definition DEF in INSN, depending on invariants
@@ -331,10 +341,10 @@ create_new_invariant (struct def *def, rtx insn, bitmap depends_on,
   inv->stamp = 0;
   inv->insn = insn;
 
-  inv->invno = VARRAY_ACTIVE_SIZE (invariants);
+  inv->invno = VEC_length (invariant_p, invariants);
   if (def)
     def->invno = inv->invno;
-  VARRAY_PUSH_GENERIC_PTR_NOGC (invariants, inv);
+  VEC_safe_push (invariant_p, heap, invariants, inv);
 
   if (dump_file)
     {
@@ -354,8 +364,7 @@ record_use (struct def *def, rtx *use, rtx insn)
 
   if (GET_CODE (*use) == SUBREG)
     use = &SUBREG_REG (*use);
-  if (!REG_P (*use))
-    abort ();
+  gcc_assert (REG_P (*use));
 
   u->pos = use;
   u->insn = insn;
@@ -427,12 +436,12 @@ find_invariant_insn (rtx insn, bool always_reached, bool always_executed,
     return;
   dest = SET_DEST (set);
 
-  if (GET_CODE (dest) != REG
+  if (!REG_P (dest)
       || HARD_REGISTER_P (dest))
     simple = false;
 
-  if (!check_maybe_invariant (SET_SRC (set))
-      || !may_assign_reg_p (SET_DEST (set)))
+  if (!may_assign_reg_p (SET_DEST (set))
+      || !check_maybe_invariant (SET_SRC (set)))
     return;
 
   if (may_trap_p (PATTERN (insn)))
@@ -446,10 +455,10 @@ find_invariant_insn (rtx insn, bool always_reached, bool always_executed,
        return;
     }
 
-  depends_on = BITMAP_XMALLOC ();
+  depends_on = BITMAP_ALLOC (NULL);
   if (!check_dependencies (insn, df, depends_on))
     {
-      BITMAP_XFREE (depends_on);
+      BITMAP_FREE (depends_on);
       return;
     }
 
@@ -465,7 +474,7 @@ find_invariant_insn (rtx insn, bool always_reached, bool always_executed,
   create_new_invariant (def, insn, depends_on, always_executed);
 }
 
-/* Record registers used in INSN that have an unique invariant definition.
+/* Record registers used in INSN that have a unique invariant definition.
    DF is the dataflow object.  */
 
 static void
@@ -556,10 +565,10 @@ find_invariants_body (struct loop *loop, basic_block *body,
 static void
 find_invariants (struct loop *loop, struct df *df)
 {
-  bitmap may_exit = BITMAP_XMALLOC ();
-  bitmap always_reached = BITMAP_XMALLOC ();
-  bitmap has_exit = BITMAP_XMALLOC ();
-  bitmap always_executed = BITMAP_XMALLOC ();
+  bitmap may_exit = BITMAP_ALLOC (NULL);
+  bitmap always_reached = BITMAP_ALLOC (NULL);
+  bitmap has_exit = BITMAP_ALLOC (NULL);
+  bitmap always_executed = BITMAP_ALLOC (NULL);
   basic_block *body = get_loop_body_in_dom_order (loop);
 
   find_exits (loop, body, may_exit, has_exit);
@@ -569,10 +578,10 @@ find_invariants (struct loop *loop, struct df *df)
   find_defs (loop, body, df);
   find_invariants_body (loop, body, always_reached, always_executed, df);
 
-  BITMAP_XFREE (always_reached);
-  BITMAP_XFREE (always_executed);
-  BITMAP_XFREE (may_exit);
-  BITMAP_XFREE (has_exit);
+  BITMAP_FREE (always_reached);
+  BITMAP_FREE (always_executed);
+  BITMAP_FREE (may_exit);
+  BITMAP_FREE (has_exit);
   free (body);
 }
 
@@ -614,7 +623,7 @@ get_inv_cost (struct invariant *inv, int *comp_cost, unsigned *regs_needed)
 
   EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, depno, bi)
     {
-      dep = VARRAY_GENERIC_PTR_NOGC (invariants, depno);
+      dep = VEC_index (invariant_p, invariants, depno);
 
       get_inv_cost (dep, &acomp_cost, &aregs_needed);
 
@@ -673,9 +682,8 @@ best_gain_for_invariant (struct invariant **best, unsigned *regs_needed,
   int gain = 0, again;
   unsigned aregs_needed, invno;
 
-  for (invno = 0; invno < VARRAY_ACTIVE_SIZE (invariants); invno++)
+  for (invno = 0; VEC_iterate (invariant_p, invariants, invno, inv); invno++)
     {
-      inv = VARRAY_GENERIC_PTR_NOGC (invariants, invno);
       if (inv->move)
        continue;
 
@@ -697,7 +705,7 @@ best_gain_for_invariant (struct invariant **best, unsigned *regs_needed,
 static void
 set_move_mark (unsigned invno)
 {
-  struct invariant *inv = VARRAY_GENERIC_PTR_NOGC (invariants, invno);
+  struct invariant *inv = VEC_index (invariant_p, invariants, invno);
   bitmap_iterator bi;
 
   if (inv->move)
@@ -721,7 +729,7 @@ find_invariants_to_move (struct df *df)
   unsigned i, regs_used, n_inv_uses, regs_needed = 0, new_regs;
   struct invariant *inv = NULL;
 
-  if (!VARRAY_ACTIVE_SIZE (invariants))
+  if (!VEC_length (invariant_p, invariants))
     return;
 
   /* Now something slightly more involved.  First estimate the number of used
@@ -741,9 +749,8 @@ find_invariants_to_move (struct df *df)
        }
     }
 
-  for (i = 0; i < VARRAY_ACTIVE_SIZE (invariants); i++)
+  for (i = 0; VEC_iterate (invariant_p, invariants, i, inv); i++)
     {
-      inv = VARRAY_GENERIC_PTR_NOGC (invariants, i);
       if (inv->def)
        n_inv_uses += inv->def->n_uses;
     }
@@ -762,7 +769,7 @@ find_invariants_to_move (struct df *df)
 static void
 move_invariant_reg (struct loop *loop, unsigned invno, struct df *df)
 {
-  struct invariant *inv = VARRAY_GENERIC_PTR_NOGC (invariants, invno);
+  struct invariant *inv = VEC_index (invariant_p, invariants, invno);
   unsigned i;
   basic_block preheader = loop_preheader_edge (loop)->src;
   rtx reg, set;
@@ -790,9 +797,22 @@ move_invariant_reg (struct loop *loop, unsigned invno, struct df *df)
   reg = gen_reg_rtx (GET_MODE (SET_DEST (set)));
   df_pattern_emit_after (df, gen_move_insn (SET_DEST (set), reg),
                         BLOCK_FOR_INSN (inv->insn), inv->insn);
-  SET_DEST (set) = reg;
-  reorder_insns (inv->insn, inv->insn, BB_END (preheader));
-  df_insn_modify (df, preheader, inv->insn);
+
+  /* If the SET_DEST of the invariant insn is a reg, we can just move
+     the insn out of the loop.  Otherwise, we have to use gen_move_insn
+     to let emit_move_insn produce a valid instruction stream.  */
+  if (REG_P (SET_DEST (set)))
+    {
+      SET_DEST (set) = reg;
+      reorder_insns (inv->insn, inv->insn, BB_END (preheader));
+      df_insn_modify (df, preheader, inv->insn);
+    }
+  else
+    {
+      df_pattern_emit_after (df, gen_move_insn (reg, SET_SRC (set)),
+                            preheader, BB_END (preheader));
+      df_insn_delete (df, BLOCK_FOR_INSN (inv->insn), inv->insn);
+    }
 
   /* Replace the uses we know to be dominated.  It saves work for copy
      propagation, and also it is necessary so that dependent invariants
@@ -816,9 +836,8 @@ move_invariants (struct loop *loop, struct df *df)
   struct invariant *inv;
   unsigned i;
 
-  for (i = 0; i < VARRAY_ACTIVE_SIZE (invariants); i++)
+  for (i = 0; VEC_iterate (invariant_p, invariants, i, inv); i++)
     {
-      inv = VARRAY_GENERIC_PTR_NOGC (invariants, i);
       if (inv->move)
        move_invariant_reg (loop, i, df);
     }
@@ -831,8 +850,7 @@ init_inv_motion_data (void)
 {
   actual_stamp = 1;
 
-  if (!invariants)
-    VARRAY_GENERIC_PTR_NOGC_INIT (invariants, 100, "invariants");
+  invariants = VEC_alloc (invariant_p, heap, 100);
 }
 
 /* Frees the data allocated by invariant motion.  DF is the dataflow
@@ -859,13 +877,12 @@ free_inv_motion_data (struct df *df)
       DF_REF_DATA (df->defs[i]) = NULL;
     }
 
-  for (i = 0; i < VARRAY_ACTIVE_SIZE (invariants); i++)
+  for (i = 0; VEC_iterate (invariant_p, invariants, i, inv); i++)
     {
-      inv = VARRAY_GENERIC_PTR_NOGC (invariants, i);
-      BITMAP_XFREE (inv->depends_on);
+      BITMAP_FREE (inv->depends_on);
       free (inv);
     }
-  VARRAY_POP_ALL (invariants);
+  VEC_free (invariant_p, heap, invariants);
 }
 
 /* Move the invariants out of the LOOP.  DF is the dataflow object.  */
@@ -926,4 +943,8 @@ move_loop_invariants (struct loops *loops)
       free_loop_data (loops->parray[i]);
 
   df_finish (df);
+
+#ifdef ENABLE_CHECKING
+  verify_flow_info ();
+#endif
 }