OSDN Git Service

Fix date on last entry.
[pf3gnuchains/gcc-fork.git] / gcc / loop.c
index c89718f..cbb1731 100644 (file)
@@ -1,5 +1,6 @@
 /* Perform various loop optimizations, including strength reduction.
-   Copyright (C) 1987, 88, 89, 91-99, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+   1998, 1999, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -50,6 +51,7 @@ Boston, MA 02111-1307, USA.  */
 #include "flags.h"
 #include "real.h"
 #include "loop.h"
+#include "cselib.h"
 #include "except.h"
 #include "toplev.h"
 
@@ -160,7 +162,7 @@ static int num_mem_sets;
 
 /* Bound on pseudo register number before loop optimization.
    A pseudo has valid regscan info if its number is < max_reg_before_loop.  */
-int max_reg_before_loop;
+unsigned int max_reg_before_loop;
 
 /* The value to pass to the next call of reg_scan_update.  */
 static int loop_max_reg;
@@ -192,7 +194,7 @@ struct movable
                                   of any registers used within the LIBCALL.  */
   int consec;                  /* Number of consecutive following insns 
                                   that must be moved with this one.  */
-  int regno;                   /* The register it sets */
+  unsigned int regno;          /* The register it sets */
   short lifetime;              /* lifetime of that register;
                                   may be adjusted when matching movables
                                   that load the same value are found.  */
@@ -304,7 +306,7 @@ static int insert_loop_mem PARAMS ((rtx *, void *));
 static int replace_loop_mem PARAMS ((rtx *, void *));
 static int replace_loop_reg PARAMS ((rtx *, void *));
 static void note_reg_stored PARAMS ((rtx, rtx, void *));
-static void try_copy_prop PARAMS ((const struct loop *, rtx, int));
+static void try_copy_prop PARAMS ((const struct loop *, rtx, unsigned int));
 static int replace_label PARAMS ((rtx *, void *));
 
 typedef struct rtx_and_int {
@@ -516,14 +518,6 @@ loop_optimize (f, dumpfile, unroll_p, bct_p)
     if (uid_luid[i] == 0)
       uid_luid[i] = uid_luid[i - 1];
 
-  /* If debugging and unrolling loops, we must replicate the tree
-     nodes corresponding to the BLOCKs inside the loop, so that the
-     original one to one mapping will remain.  We sometimes unroll
-     loops even when unroll_p is false, so we must always do this when
-     debugging.  */
-  if (write_symbols != NO_DEBUG)
-    find_loop_tree_blocks ();
-
   /* Determine if the function has indirect jump.  On some systems
      this prevents low overhead loop instructions from being used.  */
   indirect_jump_in_function = indirect_jump_in_function_p (f);
@@ -538,9 +532,12 @@ loop_optimize (f, dumpfile, unroll_p, bct_p)
        scan_loop (loop, unroll_p, bct_p);
     }
 
-  /* Replicate the BLOCKs.  */
+  /* If there were lexical blocks inside the loop, they have been
+     replicated.  We will now have more than one NOTE_INSN_BLOCK_BEG
+     and NOTE_INSN_BLOCK_END for each such block.  We must duplicate
+     the BLOCKs as well.  */
   if (write_symbols != NO_DEBUG)
-    unroll_block_trees ();
+    reorder_blocks ();
 
   end_alias_analysis ();
 
@@ -1283,8 +1280,12 @@ reg_in_basic_block_p (insn, reg)
        }
     }
 
-  /* The "last use" doesn't follow the "first use"??  */
-  abort ();
+  /* The "last use" that was recorded can't be found after the first
+     use.  This can happen when the last use was deleted while
+     processing an inner loop, this inner loop was then completely
+     unrolled, and the outer loop is always exited after the inner loop,
+     so that everything after the first use becomes a single basic block.  */
+  return 1;
 }
 \f
 /* Compute the benefit of eliminating the insns in the block whose
@@ -1535,8 +1536,8 @@ regs_match_p (x, y, movables)
      rtx x, y;
      struct movable *movables;
 {
-  int xn = REGNO (x);
-  int yn = REGNO (y);
+  unsigned int xn = REGNO (x);
+  unsigned int yn = REGNO (y);
   struct movable *mx, *my;
 
   for (mx = movables; mx; mx = mx->next)
@@ -3347,8 +3348,8 @@ consec_sets_invariant_p (loop, reg, n_sets, insn)
      int n_sets;
      rtx reg, insn;
 {
-  register rtx p = insn;
-  register int regno = REGNO (reg);
+  rtx p = insn;
+  unsigned int regno = REGNO (reg);
   rtx temp;
   /* Number of sets we have to insist on finding after INSN.  */
   int count = n_sets - 1;
@@ -3656,7 +3657,7 @@ struct iv_class *loop_iv_list;
 /* Givs made from biv increments are always splittable for loop unrolling.
    Since there is no regscan info for them, we have to keep track of them
    separately.  */
-int first_increment_giv, last_increment_giv;
+unsigned int first_increment_giv, last_increment_giv;
 
 /* Communication with routines called via `note_stores'.  */
 
@@ -4088,7 +4089,7 @@ strength_reduce (loop, insn_count, unroll_p, bct_p)
              && CONSTANT_P (XEXP (src, 1))
              && ((increment = biv_total_increment (bl)) != NULL_RTX))
            {
-             int regno = REGNO (XEXP (src, 0));
+             unsigned int regno = REGNO (XEXP (src, 0));
 
              for (bl2 = loop_iv_list; bl2; bl2 = bl2->next)
                if (bl2->regno == regno)
@@ -4214,7 +4215,7 @@ strength_reduce (loop, insn_count, unroll_p, bct_p)
      markers.  */
   if (n_extra_increment  && ! loop_info->has_volatile)
     {
-      int nregs = first_increment_giv + n_extra_increment;
+      unsigned int nregs = first_increment_giv + n_extra_increment;
 
       /* Reallocate reg_iv_type and reg_iv_info.  */
       VARRAY_GROW (reg_iv_type, nregs);
@@ -8457,7 +8458,7 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
 
              if (set && GET_CODE (SET_DEST (set)) == REG)
                {
-                 int regno = REGNO (SET_DEST (set));
+                 unsigned int regno = REGNO (SET_DEST (set));
 
                  if (regno < max_reg_before_loop
                      && REG_IV_TYPE (regno) == GENERAL_INDUCT
@@ -9768,6 +9769,19 @@ load_mems (loop)
   if (loop_mems_idx == 0)
     return;
 
+  /* Find start of the extended basic block that enters the loop.  */
+  for (p = loop->start;
+       PREV_INSN (p) && GET_CODE (p) != CODE_LABEL;
+       p = PREV_INSN (p))
+    ;
+
+  cselib_init ();
+
+  /* Build table of mems that get set to constant values before the
+     loop.  */
+  for (; p != loop->start; p = NEXT_INSN (p))
+    cselib_process_insn (p);
+
   /* Check to see if it's possible that some instructions in the
      loop are never executed.  */
   for (p = next_insn_in_loop (loop, loop->scan_start); 
@@ -9919,13 +9933,49 @@ load_mems (loop)
        loop_mems[i].optimize = 0;
       else
        {
-         int j;
-         rtx set;
-
          /* Load the memory immediately before LOOP->START, which is
             the NOTE_LOOP_BEG.  */
-         set = gen_move_insn (reg, mem);
-         emit_insn_before (set, loop->start);
+         cselib_val *e = cselib_lookup (mem, VOIDmode, 0);
+         rtx set;
+         rtx best = mem;
+         int j;
+         struct elt_loc_list *const_equiv = 0;
+
+         if (e)
+           {
+             struct elt_loc_list *equiv;
+             struct elt_loc_list *best_equiv = 0;
+             for (equiv = e->locs; equiv; equiv = equiv->next)
+               {
+                 if (CONSTANT_P (equiv->loc))
+                   const_equiv = equiv;
+                 else if (GET_CODE (equiv->loc) == REG)
+                   best_equiv = equiv;
+               }
+             /* Use the constant equivalence if that is cheap enough.  */
+             if (! best_equiv)
+               best_equiv = const_equiv;
+             else if (const_equiv
+                      && (rtx_cost (const_equiv->loc, SET)
+                          <= rtx_cost (best_equiv->loc, SET)))
+               {
+                 best_equiv = const_equiv;
+                 const_equiv = 0;
+               }
+
+             /* If best_equiv is nonzero, we know that MEM is set to a
+                constant or register before the loop.  We will use this
+                knowledge to initialize the shadow register with that
+                constant or reg rather than by loading from MEM.  */
+             if (best_equiv)
+               best = copy_rtx (best_equiv->loc);
+           }
+         set = gen_move_insn (reg, best);
+         set = emit_insn_before (set, loop->start);
+         if (const_equiv)
+           REG_NOTES (set) = gen_rtx_EXPR_LIST (REG_EQUAL,
+                                                copy_rtx (const_equiv->loc),
+                                                REG_NOTES (set));
 
          if (written)
            {
@@ -9987,6 +10037,8 @@ load_mems (loop)
            JUMP_LABEL (p) = label;
        }
     }
+
+  cselib_finish ();
 }
 
 /* For communication between note_reg_stored and its caller.  */
@@ -10012,11 +10064,12 @@ note_reg_stored (x, setter, arg)
    There must be exactly one insn that sets this pseudo; it will be
    deleted if all replacements succeed and we can prove that the register
    is not used after the loop.  */
+
 static void
 try_copy_prop (loop, replacement, regno)
      const struct loop *loop;
      rtx replacement;
-     int regno;
+     unsigned int regno;
 {
   /* This is the reg that we are copying from.  */
   rtx reg_rtx = regno_reg_rtx[regno];