OSDN Git Service

PR c/10175
[pf3gnuchains/gcc-fork.git] / gcc / loop.c
index 8e88063..d7ae3ea 100644 (file)
@@ -1,6 +1,6 @@
 /* Perform various loop optimizations, including strength reduction.
    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -36,9 +36,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "tm_p.h"
-#include "obstack.h"
 #include "function.h"
 #include "expr.h"
 #include "hard-reg-set.h"
@@ -53,6 +54,96 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "except.h"
 #include "toplev.h"
 #include "predict.h"
+#include "insn-flags.h"
+#include "optabs.h"
+#include "cfgloop.h"
+
+/* Not really meaningful values, but at least something.  */
+#ifndef SIMULTANEOUS_PREFETCHES
+#define SIMULTANEOUS_PREFETCHES 3
+#endif
+#ifndef PREFETCH_BLOCK
+#define PREFETCH_BLOCK 32
+#endif
+#ifndef HAVE_prefetch
+#define HAVE_prefetch 0
+#define CODE_FOR_prefetch 0
+#define gen_prefetch(a,b,c) (abort(), NULL_RTX)
+#endif
+
+/* Give up the prefetch optimizations once we exceed a given threshhold.
+   It is unlikely that we would be able to optimize something in a loop
+   with so many detected prefetches.  */
+#define MAX_PREFETCHES 100
+/* The number of prefetch blocks that are beneficial to fetch at once before
+   a loop with a known (and low) iteration count.  */
+#define PREFETCH_BLOCKS_BEFORE_LOOP_MAX  6
+/* For very tiny loops it is not worthwhile to prefetch even before the loop,
+   since it is likely that the data are already in the cache.  */
+#define PREFETCH_BLOCKS_BEFORE_LOOP_MIN  2
+
+/* Parameterize some prefetch heuristics so they can be turned on and off
+   easily for performance testing on new architectures.  These can be
+   defined in target-dependent files.  */
+
+/* Prefetch is worthwhile only when loads/stores are dense.  */
+#ifndef PREFETCH_ONLY_DENSE_MEM
+#define PREFETCH_ONLY_DENSE_MEM 1
+#endif
+
+/* Define what we mean by "dense" loads and stores; This value divided by 256
+   is the minimum percentage of memory references that worth prefetching.  */
+#ifndef PREFETCH_DENSE_MEM
+#define PREFETCH_DENSE_MEM 220
+#endif
+
+/* Do not prefetch for a loop whose iteration count is known to be low.  */
+#ifndef PREFETCH_NO_LOW_LOOPCNT
+#define PREFETCH_NO_LOW_LOOPCNT 1
+#endif
+
+/* Define what we mean by a "low" iteration count.  */
+#ifndef PREFETCH_LOW_LOOPCNT
+#define PREFETCH_LOW_LOOPCNT 32
+#endif
+
+/* Do not prefetch for a loop that contains a function call; such a loop is
+   probably not an internal loop.  */
+#ifndef PREFETCH_NO_CALL
+#define PREFETCH_NO_CALL 1
+#endif
+
+/* Do not prefetch accesses with an extreme stride.  */
+#ifndef PREFETCH_NO_EXTREME_STRIDE
+#define PREFETCH_NO_EXTREME_STRIDE 1
+#endif
+
+/* Define what we mean by an "extreme" stride.  */
+#ifndef PREFETCH_EXTREME_STRIDE
+#define PREFETCH_EXTREME_STRIDE 4096
+#endif
+
+/* Define a limit to how far apart indices can be and still be merged
+   into a single prefetch.  */
+#ifndef PREFETCH_EXTREME_DIFFERENCE
+#define PREFETCH_EXTREME_DIFFERENCE 4096
+#endif
+
+/* Issue prefetch instructions before the loop to fetch data to be used
+   in the first few loop iterations.  */
+#ifndef PREFETCH_BEFORE_LOOP
+#define PREFETCH_BEFORE_LOOP 1
+#endif
+
+/* Do not handle reversed order prefetches (negative stride).  */
+#ifndef PREFETCH_NO_REVERSE_ORDER
+#define PREFETCH_NO_REVERSE_ORDER 1
+#endif
+
+/* Prefetch even if the GIV is in conditional code.  */
+#ifndef PREFETCH_CONDITIONAL
+#define PREFETCH_CONDITIONAL 1
+#endif
 
 #define LOOP_REG_LIFETIME(LOOP, REGNO) \
 ((REGNO_LAST_LUID (REGNO) - REGNO_FIRST_LUID (REGNO)))
@@ -61,6 +152,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 ((REGNO_LAST_LUID (REGNO) > INSN_LUID ((LOOP)->end) \
  || REGNO_FIRST_LUID (REGNO) < INSN_LUID ((LOOP)->start)))
 
+#define LOOP_REGNO_NREGS(REGNO, SET_DEST) \
+((REGNO) < FIRST_PSEUDO_REGISTER \
+ ? (int) HARD_REGNO_NREGS ((REGNO), GET_MODE (SET_DEST)) : 1)
+
 
 /* Vector mapping INSN_UIDs to luids.
    The luids are like uids but increase monotonically always.
@@ -77,10 +172,6 @@ struct loop **uid_loop;
 
 int max_uid_for_loop;
 
-/* 1 + luid of last insn.  */
-
-static int max_luid;
-
 /* Number of loops detected in current function.  Used as index to the
    next few tables.  */
 
@@ -92,9 +183,6 @@ unsigned int max_reg_before_loop;
 
 /* The value to pass to the next call of reg_scan_update.  */
 static int loop_max_reg;
-
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
 \f
 /* During the analysis of a loop, a chain of `struct movable's
    is made to record all the movable insns found.
@@ -116,6 +204,9 @@ struct movable
   short savings;               /* Number of insns we can move for this reg,
                                   including other movables that force this
                                   or match this one.  */
+  ENUM_BITFIELD(machine_mode) savemode : 8;   /* Nonzero means it is a mode for 
+                                  a low part that we should avoid changing when
+                                  clearing the rest of the reg.  */
   unsigned int cond : 1;       /* 1 if only conditionally movable */
   unsigned int force : 1;      /* 1 means MUST move this insn */
   unsigned int global : 1;     /* 1 means reg is live outside this loop */
@@ -132,9 +223,9 @@ struct movable
   unsigned int move_insn_first:1;/* Same as above, if this is necessary for the
                                    first insn of a consecutive sets group.  */
   unsigned int is_equiv : 1;   /* 1 means a REG_EQUIV is present on INSN.  */
-  enum machine_mode savemode;   /* Nonzero means it is a mode for a low part
-                                  that we should avoid changing when clearing
-                                  the rest of the reg.  */
+  unsigned int insert_temp : 1;  /* 1 means we copy to a new pseudo and replace
+                                   the original insn with a copy from that
+                                   pseudo, rather than deleting it.  */
   struct movable *match;       /* First entry for same value */
   struct movable *forces;      /* An insn that must be moved if this is */
   struct movable *next;
@@ -145,6 +236,7 @@ FILE *loop_dump_stream;
 
 /* Forward declarations.  */
 
+static void invalidate_loops_containing_label PARAMS ((rtx));
 static void find_and_verify_loops PARAMS ((rtx, struct loops *));
 static void mark_loop_jump PARAMS ((rtx, struct loop *));
 static void prescan_loop PARAMS ((struct loop *));
@@ -208,7 +300,7 @@ static void record_giv PARAMS ((const struct loop *, struct induction *,
                                rtx, rtx, rtx, rtx, rtx, rtx, int,
                                enum g_types, int, int, rtx *));
 static void update_giv_derive PARAMS ((const struct loop *, rtx));
-static void check_ext_dependant_givs PARAMS ((struct iv_class *,
+static void check_ext_dependent_givs PARAMS ((struct iv_class *,
                                              struct loop_info *));
 static int basic_induction_var PARAMS ((const struct loop *, rtx,
                                        enum machine_mode, rtx, rtx,
@@ -236,17 +328,18 @@ static void update_reg_last_use PARAMS ((rtx, rtx));
 static rtx next_insn_in_loop PARAMS ((const struct loop *, rtx));
 static void loop_regs_scan PARAMS ((const struct loop *, int));
 static int count_insns_in_loop PARAMS ((const struct loop *));
+static int find_mem_in_note_1 PARAMS ((rtx *, void *));
+static rtx find_mem_in_note PARAMS ((rtx));
 static void load_mems PARAMS ((const struct loop *));
 static int insert_loop_mem PARAMS ((rtx *, void *));
 static int replace_loop_mem PARAMS ((rtx *, void *));
-static void replace_loop_mems PARAMS ((rtx, rtx, rtx));
+static void replace_loop_mems PARAMS ((rtx, rtx, rtx, int));
 static int replace_loop_reg PARAMS ((rtx *, void *));
 static void replace_loop_regs PARAMS ((rtx insn, rtx, rtx));
 static void note_reg_stored PARAMS ((rtx, rtx, void *));
 static void try_copy_prop PARAMS ((const struct loop *, rtx, unsigned int));
 static void try_swap_copy_prop PARAMS ((const struct loop *, rtx,
                                         unsigned int));
-static int replace_label PARAMS ((rtx *, void *));
 static rtx check_insn_for_givs PARAMS((struct loop *, rtx, int, int));
 static rtx check_insn_for_bivs PARAMS((struct loop *, rtx, int, int));
 static rtx gen_add_mult PARAMS ((rtx, rtx, rtx, rtx));
@@ -262,6 +355,8 @@ static rtx loop_insn_sink_or_swim PARAMS((const struct loop *, rtx));
 
 static void loop_dump_aux PARAMS ((const struct loop *, FILE *, int));
 static void loop_delete_insns PARAMS ((rtx, rtx));
+static HOST_WIDE_INT remove_constant_addition PARAMS ((rtx *));
+static rtx gen_load_of_final_value PARAMS ((rtx, rtx));
 void debug_ivs PARAMS ((const struct loop *));
 void debug_iv_class PARAMS ((const struct iv_class *));
 void debug_biv PARAMS ((const struct induction *));
@@ -269,12 +364,6 @@ void debug_giv PARAMS ((const struct induction *));
 void debug_loop PARAMS ((const struct loop *));
 void debug_loops PARAMS ((const struct loops *));
 
-typedef struct rtx_pair
-{
-  rtx r1;
-  rtx r2;
-} rtx_pair;
-
 typedef struct loop_replace_args
 {
   rtx match;
@@ -405,7 +494,7 @@ loop_optimize (f, dumpfile, flags)
 
   /* Allocate and initialize auxiliary loop information.  */
   loops_info = xcalloc (loops->num, sizeof (struct loop_info));
-  for (i = 0; i < loops->num; i++)
+  for (i = 0; i < (int) loops->num; i++)
     loops->array[i].aux = loops_info + i;
 
   /* Now find all register lifetimes.  This must be done after
@@ -430,7 +519,7 @@ loop_optimize (f, dumpfile, flags)
   /* find_and_verify_loops has already called compute_luids, but it
      might have rearranged code afterwards, so we need to recompute
      the luids now.  */
-  max_luid = compute_luids (f, NULL_RTX, 0);
+  compute_luids (f, NULL_RTX, 0);
 
   /* Don't leave gaps in uid_luid for insns that have been
      deleted.  It is possible that the first or last insn
@@ -461,13 +550,6 @@ loop_optimize (f, dumpfile, flags)
        scan_loop (loop, flags);
     }
 
-  /* 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)
-    reorder_blocks ();
-
   end_alias_analysis ();
 
   /* Clean up.  */
@@ -531,8 +613,6 @@ scan_loop (loop, flags)
   /* 1 if we are scanning insns that might never be executed
      due to a subroutine call which might exit before they are reached.  */
   int call_passed = 0;
-  /* Jump insn that enters the loop, or 0 if control drops in.  */
-  rtx loop_entry_jump = 0;
   /* Number of insns in the loop.  */
   int insn_count;
   int tem;
@@ -548,6 +628,7 @@ scan_loop (loop, flags)
   int threshold;
   /* Nonzero if we are scanning instructions in a sub-loop.  */
   int loop_depth = 0;
+  int in_libcall;
 
   loop->top = 0;
 
@@ -599,24 +680,20 @@ scan_loop (loop, flags)
      Start scan from there.
      But record in LOOP->TOP the place where the end-test jumps
      back to so we can scan that after the end of the loop.  */
-  if (GET_CODE (p) == JUMP_INSN)
-    {
-      loop_entry_jump = p;
-
+  if (GET_CODE (p) == JUMP_INSN
       /* Loop entry must be unconditional jump (and not a RETURN)  */
-      if (any_uncondjump_p (p)
-         && JUMP_LABEL (p) != 0
-         /* Check to see whether the jump actually
-            jumps out of the loop (meaning it's no loop).
-            This case can happen for things like
-            do {..} while (0).  If this label was generated previously
-            by loop, we can't tell anything about it and have to reject
-            the loop.  */
-         && INSN_IN_RANGE_P (JUMP_LABEL (p), loop_start, loop_end))
-       {
-         loop->top = next_label (loop->scan_start);
-         loop->scan_start = JUMP_LABEL (p);
-       }
+      && any_uncondjump_p (p)
+      && JUMP_LABEL (p) != 0
+      /* Check to see whether the jump actually
+        jumps out of the loop (meaning it's no loop).
+        This case can happen for things like
+        do {..} while (0).  If this label was generated previously
+        by loop, we can't tell anything about it and have to reject
+        the loop.  */
+      && INSN_IN_RANGE_P (JUMP_LABEL (p), loop_start, loop_end))
+    {
+      loop->top = next_label (loop->scan_start);
+      loop->scan_start = JUMP_LABEL (p);
     }
 
   /* If LOOP->SCAN_START was an insn created by loop, we don't know its luid
@@ -664,65 +741,73 @@ scan_loop (loop, flags)
      When MAYBE_NEVER is 0, all insns will be executed at least once
      so that is not a problem.  */
 
-  for (p = next_insn_in_loop (loop, loop->scan_start);
+  for (in_libcall = 0, p = next_insn_in_loop (loop, loop->scan_start);
        p != NULL_RTX;
        p = next_insn_in_loop (loop, p))
     {
-      if (GET_CODE (p) == INSN
-         && (set = single_set (p))
-         && GET_CODE (SET_DEST (set)) == REG
-         && ! regs->array[REGNO (SET_DEST (set))].may_not_optimize)
+      if (in_libcall && INSN_P (p) && find_reg_note (p, REG_RETVAL, NULL_RTX))
+       in_libcall--;
+      if (GET_CODE (p) == INSN)
        {
-         int tem1 = 0;
-         int tem2 = 0;
-         int move_insn = 0;
-         rtx src = SET_SRC (set);
-         rtx dependencies = 0;
-
-         /* Figure out what to use as a source of this insn.  If a REG_EQUIV
-            note is given or if a REG_EQUAL note with a constant operand is
-            specified, use it as the source and mark that we should move
-            this insn by calling emit_move_insn rather that duplicating the
-            insn.
-
-            Otherwise, only use the REG_EQUAL contents if a REG_RETVAL note
-            is present.  */
-         temp = find_reg_note (p, REG_EQUIV, NULL_RTX);
+         temp = find_reg_note (p, REG_LIBCALL, NULL_RTX);
          if (temp)
-           src = XEXP (temp, 0), move_insn = 1;
-         else
+           in_libcall++;
+         if (! in_libcall
+             && (set = single_set (p))
+             && GET_CODE (SET_DEST (set)) == REG
+#ifdef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
+             && SET_DEST (set) != pic_offset_table_rtx
+#endif
+             && ! regs->array[REGNO (SET_DEST (set))].may_not_optimize)
            {
-             temp = find_reg_note (p, REG_EQUAL, NULL_RTX);
-             if (temp && CONSTANT_P (XEXP (temp, 0)))
+             int tem1 = 0;
+             int tem2 = 0;
+             int move_insn = 0;
+             int insert_temp = 0;
+             rtx src = SET_SRC (set);
+             rtx dependencies = 0;
+
+             /* Figure out what to use as a source of this insn.  If a
+                REG_EQUIV note is given or if a REG_EQUAL note with a
+                constant operand is specified, use it as the source and
+                mark that we should move this insn by calling
+                emit_move_insn rather that duplicating the insn.
+
+                Otherwise, only use the REG_EQUAL contents if a REG_RETVAL
+                note is present.  */
+             temp = find_reg_note (p, REG_EQUIV, NULL_RTX);
+             if (temp)
                src = XEXP (temp, 0), move_insn = 1;
-             if (temp && find_reg_note (p, REG_RETVAL, NULL_RTX))
+             else
                {
-                 src = XEXP (temp, 0);
-                 /* A libcall block can use regs that don't appear in
-                    the equivalent expression.  To move the libcall,
-                    we must move those regs too.  */
-                 dependencies = libcall_other_reg (p, src);
+                 temp = find_reg_note (p, REG_EQUAL, NULL_RTX);
+                 if (temp && CONSTANT_P (XEXP (temp, 0)))
+                   src = XEXP (temp, 0), move_insn = 1;
+                 if (temp && find_reg_note (p, REG_RETVAL, NULL_RTX))
+                   {
+                     src = XEXP (temp, 0);
+                     /* A libcall block can use regs that don't appear in
+                        the equivalent expression.  To move the libcall,
+                        we must move those regs too.  */
+                     dependencies = libcall_other_reg (p, src);
+                   }
                }
-           }
 
-         /* For parallels, add any possible uses to the depencies, as we can't move
-            the insn without resolving them first.  */
-         if (GET_CODE (PATTERN (p)) == PARALLEL)
-           {
-             for (i = 0; i < XVECLEN (PATTERN (p), 0); i++)
+             /* For parallels, add any possible uses to the dependencies, as
+                we can't move the insn without resolving them first.  */
+             if (GET_CODE (PATTERN (p)) == PARALLEL)
                {
-                 rtx x = XVECEXP (PATTERN (p), 0, i);
-                 if (GET_CODE (x) == USE)
-                   dependencies = gen_rtx_EXPR_LIST (VOIDmode, XEXP (x, 0), dependencies);
+                 for (i = 0; i < XVECLEN (PATTERN (p), 0); i++)
+                   {
+                     rtx x = XVECEXP (PATTERN (p), 0, i);
+                     if (GET_CODE (x) == USE)
+                       dependencies
+                         = gen_rtx_EXPR_LIST (VOIDmode, XEXP (x, 0),
+                                              dependencies);
+                   }
                }
-           }
 
-         /* Don't try to optimize a register that was made
-            by loop-optimization for an inner loop.
-            We don't know its life-span, so we can't compute the benefit.  */
-         if (REGNO (SET_DEST (set)) >= max_reg_before_loop)
-           ;
-         else if (/* The register is used in basic blocks other
+             if (/* The register is used in basic blocks other
                      than the one where it is set (meaning that
                      something after this point in the loop might
                      depend on its value before the set).  */
@@ -731,217 +816,255 @@ scan_loop (loop, flags)
                      the loop starts, or the value before the set is
                      needed before the set occurs...
 
-                     ??? Note we have quadratic behaviour here, mitigated
+                     ??? Note we have quadratic behavior here, mitigated
                      by the fact that the previous test will often fail for
                      large loops.  Rather than re-scanning the entire loop
                      each time for register usage, we should build tables
                      of the register usage and use them here instead.  */
                   && (maybe_never
                       || loop_reg_used_before_p (loop, set, p)))
-           /* It is unsafe to move the set.
-
-              This code used to consider it OK to move a set of a variable
-              which was not created by the user and not used in an exit test.
-              That behavior is incorrect and was removed.  */
-           ;
-         else if ((tem = loop_invariant_p (loop, src))
-                  && (dependencies == 0
-                      || (tem2 = loop_invariant_p (loop, dependencies)) != 0)
-                  && (regs->array[REGNO (SET_DEST (set))].set_in_loop == 1
-                      || (tem1
-                          = consec_sets_invariant_p
-                          (loop, SET_DEST (set),
-                           regs->array[REGNO (SET_DEST (set))].set_in_loop,
-                           p)))
-                  /* If the insn can cause a trap (such as divide by zero),
-                     can't move it unless it's guaranteed to be executed
-                     once loop is entered.  Even a function call might
-                     prevent the trap insn from being reached
-                     (since it might exit!)  */
-                  && ! ((maybe_never || call_passed)
-                        && may_trap_p (src)))
-           {
-             struct movable *m;
-             int regno = REGNO (SET_DEST (set));
-
-             /* A potential lossage is where we have a case where two insns
-                can be combined as long as they are both in the loop, but
-                we move one of them outside the loop.  For large loops,
-                this can lose.  The most common case of this is the address
-                of a function being called.
-
-                Therefore, if this register is marked as being used exactly
-                once if we are in a loop with calls (a "large loop"), see if
-                we can replace the usage of this register with the source
-                of this SET.  If we can, delete this insn.
-
-                Don't do this if P has a REG_RETVAL note or if we have
-                SMALL_REGISTER_CLASSES and SET_SRC is a hard register.  */
-
-             if (loop_info->has_call
-                 && regs->array[regno].single_usage != 0
-                 && regs->array[regno].single_usage != const0_rtx
-                 && REGNO_FIRST_UID (regno) == INSN_UID (p)
-                 && (REGNO_LAST_UID (regno)
-                     == INSN_UID (regs->array[regno].single_usage))
-                 && regs->array[regno].set_in_loop == 1
-                 && GET_CODE (SET_SRC (set)) != ASM_OPERANDS
-                 && ! side_effects_p (SET_SRC (set))
-                 && ! find_reg_note (p, REG_RETVAL, NULL_RTX)
-                 && (! SMALL_REGISTER_CLASSES
-                     || (! (GET_CODE (SET_SRC (set)) == REG
-                            && REGNO (SET_SRC (set)) < FIRST_PSEUDO_REGISTER)))
-                 /* This test is not redundant; SET_SRC (set) might be
-                    a call-clobbered register and the life of REGNO
-                    might span a call.  */
-                 && ! modified_between_p (SET_SRC (set), p,
-                                          regs->array[regno].single_usage)
-                 && no_labels_between_p (p, regs->array[regno].single_usage)
-                 && validate_replace_rtx (SET_DEST (set), SET_SRC (set),
-                                          regs->array[regno].single_usage))
-               {
-                 /* Replace any usage in a REG_EQUAL note.  Must copy the
-                    new source, so that we don't get rtx sharing between the
-                    SET_SOURCE and REG_NOTES of insn p.  */
-                 REG_NOTES (regs->array[regno].single_usage)
-                   = replace_rtx (REG_NOTES (regs->array[regno].single_usage),
-                                  SET_DEST (set), copy_rtx (SET_SRC (set)));
-
-                 delete_insn (p);
-                 regs->array[regno].set_in_loop = 0;
-                 continue;
-               }
-
-             m = (struct movable *) xmalloc (sizeof (struct movable));
-             m->next = 0;
-             m->insn = p;
-             m->set_src = src;
-             m->dependencies = dependencies;
-             m->set_dest = SET_DEST (set);
-             m->force = 0;
-             m->consec = regs->array[REGNO (SET_DEST (set))].set_in_loop - 1;
-             m->done = 0;
-             m->forces = 0;
-             m->partial = 0;
-             m->move_insn = move_insn;
-             m->move_insn_first = 0;
-             m->is_equiv = (find_reg_note (p, REG_EQUIV, NULL_RTX) != 0);
-             m->savemode = VOIDmode;
-             m->regno = regno;
-             /* Set M->cond if either loop_invariant_p
-                or consec_sets_invariant_p returned 2
-                (only conditionally invariant).  */
-             m->cond = ((tem | tem1 | tem2) > 1);
-             m->global =  LOOP_REG_GLOBAL_P (loop, regno);
-             m->match = 0;
-             m->lifetime = LOOP_REG_LIFETIME (loop, regno);
-             m->savings = regs->array[regno].n_times_set;
-             if (find_reg_note (p, REG_RETVAL, NULL_RTX))
-               m->savings += libcall_benefit (p);
-             regs->array[regno].set_in_loop = move_insn ? -2 : -1;
-             /* Add M to the end of the chain MOVABLES.  */
-             loop_movables_add (movables, m);
-
-             if (m->consec > 0)
+               /* It is unsafe to move the set.  However, it may be OK to
+                  move the source into a new pseudo, and substitute a 
+                  reg-to-reg copy for the original insn.
+
+                  This code used to consider it OK to move a set of a variable
+                  which was not created by the user and not used in an exit
+                  test.
+                  That behavior is incorrect and was removed.  */
+               insert_temp = 1;
+
+             /* Don't try to optimize a register that was made
+                by loop-optimization for an inner loop.
+                We don't know its life-span, so we can't compute
+                the benefit.  */
+             if (REGNO (SET_DEST (set)) >= max_reg_before_loop)
+               ;
+             /* Don't move the source and add a reg-to-reg copy:
+                - with -Os (this certainly increases size),
+                - if the mode doesn't support copy operations (obviously),
+                - if the source is already a reg (the motion will gain nothing),
+                - if the source is a legitimate constant (likewise).  */
+             else if (insert_temp 
+                      && (optimize_size
+                          || ! can_copy_p (GET_MODE (SET_SRC (set)))
+                          || GET_CODE (SET_SRC (set)) == REG
+                          || (CONSTANT_P (SET_SRC (set))
+                              && LEGITIMATE_CONSTANT_P (SET_SRC (set)))))
+               ;
+             else if ((tem = loop_invariant_p (loop, src))
+                      && (dependencies == 0
+                          || (tem2
+                              = loop_invariant_p (loop, dependencies)) != 0)
+                      && (regs->array[REGNO (SET_DEST (set))].set_in_loop == 1
+                          || (tem1
+                              = consec_sets_invariant_p
+                              (loop, SET_DEST (set),
+                               regs->array[REGNO (SET_DEST (set))].set_in_loop,
+                               p)))
+                      /* If the insn can cause a trap (such as divide by zero),
+                         can't move it unless it's guaranteed to be executed
+                         once loop is entered.  Even a function call might
+                         prevent the trap insn from being reached
+                         (since it might exit!)  */
+                      && ! ((maybe_never || call_passed)
+                            && may_trap_p (src)))
                {
-                 /* It is possible for the first instruction to have a
-                    REG_EQUAL note but a non-invariant SET_SRC, so we must
-                    remember the status of the first instruction in case
-                    the last instruction doesn't have a REG_EQUAL note.  */
-                 m->move_insn_first = m->move_insn;
-
-                 /* Skip this insn, not checking REG_LIBCALL notes.  */
-                 p = next_nonnote_insn (p);
-                 /* Skip the consecutive insns, if there are any.  */
-                 p = skip_consec_insns (p, m->consec);
-                 /* Back up to the last insn of the consecutive group.  */
-                 p = prev_nonnote_insn (p);
-
-                 /* We must now reset m->move_insn, m->is_equiv, and possibly
-                    m->set_src to correspond to the effects of all the
-                    insns.  */
-                 temp = find_reg_note (p, REG_EQUIV, NULL_RTX);
-                 if (temp)
-                   m->set_src = XEXP (temp, 0), m->move_insn = 1;
-                 else
+                 struct movable *m;
+                 int regno = REGNO (SET_DEST (set));
+
+                 /* A potential lossage is where we have a case where two insns
+                    can be combined as long as they are both in the loop, but
+                    we move one of them outside the loop.  For large loops,
+                    this can lose.  The most common case of this is the address
+                    of a function being called.
+
+                    Therefore, if this register is marked as being used
+                    exactly once if we are in a loop with calls
+                    (a "large loop"), see if we can replace the usage of
+                    this register with the source of this SET.  If we can,
+                    delete this insn.
+
+                    Don't do this if P has a REG_RETVAL note or if we have
+                    SMALL_REGISTER_CLASSES and SET_SRC is a hard register.  */
+
+                 if (loop_info->has_call
+                     && regs->array[regno].single_usage != 0
+                     && regs->array[regno].single_usage != const0_rtx
+                     && REGNO_FIRST_UID (regno) == INSN_UID (p)
+                     && (REGNO_LAST_UID (regno)
+                         == INSN_UID (regs->array[regno].single_usage))
+                     && regs->array[regno].set_in_loop == 1
+                     && GET_CODE (SET_SRC (set)) != ASM_OPERANDS
+                     && ! side_effects_p (SET_SRC (set))
+                     && ! find_reg_note (p, REG_RETVAL, NULL_RTX)
+                     && (! SMALL_REGISTER_CLASSES
+                         || (! (GET_CODE (SET_SRC (set)) == REG
+                                && (REGNO (SET_SRC (set))
+                                    < FIRST_PSEUDO_REGISTER))))
+                     /* This test is not redundant; SET_SRC (set) might be
+                        a call-clobbered register and the life of REGNO
+                        might span a call.  */
+                     && ! modified_between_p (SET_SRC (set), p,
+                                              regs->array[regno].single_usage)
+                     && no_labels_between_p (p,
+                                             regs->array[regno].single_usage)
+                     && validate_replace_rtx (SET_DEST (set), SET_SRC (set),
+                                              regs->array[regno].single_usage))
                    {
-                     temp = find_reg_note (p, REG_EQUAL, NULL_RTX);
-                     if (temp && CONSTANT_P (XEXP (temp, 0)))
-                       m->set_src = XEXP (temp, 0), m->move_insn = 1;
-                     else
-                       m->move_insn = 0;
+                     /* Replace any usage in a REG_EQUAL note.  Must copy
+                        the new source, so that we don't get rtx sharing
+                        between the SET_SOURCE and REG_NOTES of insn p.  */
+                     REG_NOTES (regs->array[regno].single_usage)
+                       = (replace_rtx
+                          (REG_NOTES (regs->array[regno].single_usage),
+                           SET_DEST (set), copy_rtx (SET_SRC (set))));
 
+                     delete_insn (p);
+                     for (i = 0; i < LOOP_REGNO_NREGS (regno, SET_DEST (set));
+                          i++)
+                       regs->array[regno+i].set_in_loop = 0;
+                     continue;
                    }
-                 m->is_equiv = (find_reg_note (p, REG_EQUIV, NULL_RTX) != 0);
-               }
-           }
-         /* If this register is always set within a STRICT_LOW_PART
-            or set to zero, then its high bytes are constant.
-            So clear them outside the loop and within the loop
-            just load the low bytes.
-            We must check that the machine has an instruction to do so.
-            Also, if the value loaded into the register
-            depends on the same register, this cannot be done.  */
-         else if (SET_SRC (set) == const0_rtx
-                  && GET_CODE (NEXT_INSN (p)) == INSN
-                  && (set1 = single_set (NEXT_INSN (p)))
-                  && GET_CODE (set1) == SET
-                  && (GET_CODE (SET_DEST (set1)) == STRICT_LOW_PART)
-                  && (GET_CODE (XEXP (SET_DEST (set1), 0)) == SUBREG)
-                  && (SUBREG_REG (XEXP (SET_DEST (set1), 0))
-                      == SET_DEST (set))
-                  && !reg_mentioned_p (SET_DEST (set), SET_SRC (set1)))
-           {
-             int regno = REGNO (SET_DEST (set));
-             if (regs->array[regno].set_in_loop == 2)
-               {
-                 struct movable *m;
+
                  m = (struct movable *) xmalloc (sizeof (struct movable));
                  m->next = 0;
                  m->insn = p;
+                 m->set_src = src;
+                 m->dependencies = dependencies;
                  m->set_dest = SET_DEST (set);
-                 m->dependencies = 0;
                  m->force = 0;
-                 m->consec = 0;
+                 m->consec
+                   = regs->array[REGNO (SET_DEST (set))].set_in_loop - 1;
                  m->done = 0;
                  m->forces = 0;
-                 m->move_insn = 0;
+                 m->partial = 0;
+                 m->move_insn = move_insn;
                  m->move_insn_first = 0;
-                 m->partial = 1;
-                 /* If the insn may not be executed on some cycles,
-                    we can't clear the whole reg; clear just high part.
-                    Not even if the reg is used only within this loop.
-                    Consider this:
-                    while (1)
-                      while (s != t) {
-                        if (foo ()) x = *s;
-                        use (x);
-                      }
-                    Clearing x before the inner loop could clobber a value
-                    being saved from the last time around the outer loop.
-                    However, if the reg is not used outside this loop
-                    and all uses of the register are in the same
-                    basic block as the store, there is no problem.
-
-                    If this insn was made by loop, we don't know its
-                    INSN_LUID and hence must make a conservative
-                    assumption.  */
-                 m->global = (INSN_UID (p) >= max_uid_for_loop
-                              || LOOP_REG_GLOBAL_P (loop, regno)
-                              || (labels_in_range_p
-                                  (p, REGNO_FIRST_LUID (regno))));
-                 if (maybe_never && m->global)
-                   m->savemode = GET_MODE (SET_SRC (set1));
-                 else
-                   m->savemode = VOIDmode;
+                 m->insert_temp = insert_temp;
+                 m->is_equiv = (find_reg_note (p, REG_EQUIV, NULL_RTX) != 0);
+                 m->savemode = VOIDmode;
                  m->regno = regno;
-                 m->cond = 0;
+                 /* Set M->cond if either loop_invariant_p
+                    or consec_sets_invariant_p returned 2
+                    (only conditionally invariant).  */
+                 m->cond = ((tem | tem1 | tem2) > 1);
+                 m->global =  LOOP_REG_GLOBAL_P (loop, regno);
                  m->match = 0;
                  m->lifetime = LOOP_REG_LIFETIME (loop, regno);
-                 m->savings = 1;
-                 regs->array[regno].set_in_loop = -1;
+                 m->savings = regs->array[regno].n_times_set;
+                 if (find_reg_note (p, REG_RETVAL, NULL_RTX))
+                   m->savings += libcall_benefit (p);
+                 for (i = 0; i < LOOP_REGNO_NREGS (regno, SET_DEST (set)); i++)
+                   regs->array[regno+i].set_in_loop = move_insn ? -2 : -1;
                  /* Add M to the end of the chain MOVABLES.  */
                  loop_movables_add (movables, m);
+
+                 if (m->consec > 0)
+                   {
+                     /* It is possible for the first instruction to have a
+                        REG_EQUAL note but a non-invariant SET_SRC, so we must
+                        remember the status of the first instruction in case
+                        the last instruction doesn't have a REG_EQUAL note.  */
+                     m->move_insn_first = m->move_insn;
+
+                     /* Skip this insn, not checking REG_LIBCALL notes.  */
+                     p = next_nonnote_insn (p);
+                     /* Skip the consecutive insns, if there are any.  */
+                     p = skip_consec_insns (p, m->consec);
+                     /* Back up to the last insn of the consecutive group.  */
+                     p = prev_nonnote_insn (p);
+
+                     /* We must now reset m->move_insn, m->is_equiv, and
+                        possibly m->set_src to correspond to the effects of
+                        all the insns.  */
+                     temp = find_reg_note (p, REG_EQUIV, NULL_RTX);
+                     if (temp)
+                       m->set_src = XEXP (temp, 0), m->move_insn = 1;
+                     else
+                       {
+                         temp = find_reg_note (p, REG_EQUAL, NULL_RTX);
+                         if (temp && CONSTANT_P (XEXP (temp, 0)))
+                           m->set_src = XEXP (temp, 0), m->move_insn = 1;
+                         else
+                           m->move_insn = 0;
+
+                       }
+                     m->is_equiv
+                       = (find_reg_note (p, REG_EQUIV, NULL_RTX) != 0);
+                   }
+               }
+             /* If this register is always set within a STRICT_LOW_PART
+                or set to zero, then its high bytes are constant.
+                So clear them outside the loop and within the loop
+                just load the low bytes.
+                We must check that the machine has an instruction to do so.
+                Also, if the value loaded into the register
+                depends on the same register, this cannot be done.  */
+             else if (SET_SRC (set) == const0_rtx
+                      && GET_CODE (NEXT_INSN (p)) == INSN
+                      && (set1 = single_set (NEXT_INSN (p)))
+                      && GET_CODE (set1) == SET
+                      && (GET_CODE (SET_DEST (set1)) == STRICT_LOW_PART)
+                      && (GET_CODE (XEXP (SET_DEST (set1), 0)) == SUBREG)
+                      && (SUBREG_REG (XEXP (SET_DEST (set1), 0))
+                          == SET_DEST (set))
+                      && !reg_mentioned_p (SET_DEST (set), SET_SRC (set1)))
+               {
+                 int regno = REGNO (SET_DEST (set));
+                 if (regs->array[regno].set_in_loop == 2)
+                   {
+                     struct movable *m;
+                     m = (struct movable *) xmalloc (sizeof (struct movable));
+                     m->next = 0;
+                     m->insn = p;
+                     m->set_dest = SET_DEST (set);
+                     m->dependencies = 0;
+                     m->force = 0;
+                     m->consec = 0;
+                     m->done = 0;
+                     m->forces = 0;
+                     m->move_insn = 0;
+                     m->move_insn_first = 0;
+                     m->insert_temp = insert_temp;
+                     m->partial = 1;
+                     /* If the insn may not be executed on some cycles,
+                        we can't clear the whole reg; clear just high part.
+                        Not even if the reg is used only within this loop.
+                        Consider this:
+                        while (1)
+                          while (s != t) {
+                            if (foo ()) x = *s;
+                            use (x);
+                          }
+                        Clearing x before the inner loop could clobber a value
+                        being saved from the last time around the outer loop.
+                        However, if the reg is not used outside this loop
+                        and all uses of the register are in the same
+                        basic block as the store, there is no problem.
+
+                        If this insn was made by loop, we don't know its
+                        INSN_LUID and hence must make a conservative
+                        assumption.  */
+                     m->global = (INSN_UID (p) >= max_uid_for_loop
+                                  || LOOP_REG_GLOBAL_P (loop, regno)
+                                  || (labels_in_range_p
+                                      (p, REGNO_FIRST_LUID (regno))));
+                     if (maybe_never && m->global)
+                       m->savemode = GET_MODE (SET_SRC (set1));
+                     else
+                       m->savemode = VOIDmode;
+                     m->regno = regno;
+                     m->cond = 0;
+                     m->match = 0;
+                     m->lifetime = LOOP_REG_LIFETIME (loop, regno);
+                     m->savings = 1;
+                     for (i = 0;
+                          i < LOOP_REGNO_NREGS (regno, SET_DEST (set));
+                          i++)
+                       regs->array[regno+i].set_in_loop = -1;
+                     /* Add M to the end of the chain MOVABLES.  */
+                     loop_movables_add (movables, m);
+                   }
                }
            }
        }
@@ -962,7 +1085,7 @@ scan_loop (loop, flags)
                  unconditional jump, otherwise the code at the top of the
                  loop might never be executed.  Unconditional jumps are
                  followed by a barrier then the loop_end.  */
-               && ! (GET_CODE (p) == JUMP_INSN && JUMP_LABEL (p) == loop->top
+              && ! (GET_CODE (p) == JUMP_INSN && JUMP_LABEL (p) == loop->top
                     && NEXT_INSN (NEXT_INSN (p)) == loop_end
                     && any_uncondjump_p (p)))
        maybe_never = 1;
@@ -1001,11 +1124,31 @@ scan_loop (loop, flags)
   /* Now consider each movable insn to decide whether it is worth moving.
      Store 0 in regs->array[I].set_in_loop for each reg I that is moved.
 
-     Generally this increases code size, so do not move moveables when
-     optimizing for code size.  */
+     For machines with few registers this increases code size, so do not
+     move moveables when optimizing for code size on such machines.  
+     (The 18 below is the value for i386.)  */
+
+  if (!optimize_size 
+      || (reg_class_size[GENERAL_REGS] > 18 && !loop_info->has_call))
+    {
+      move_movables (loop, movables, threshold, insn_count);
+
+      /* Recalculate regs->array if move_movables has created new
+        registers.  */
+      if (max_reg_num () > regs->num)
+       {
+         loop_regs_scan (loop, 0);
+         for (update_start = loop_start;
+              PREV_INSN (update_start)
+              && GET_CODE (PREV_INSN (update_start)) != CODE_LABEL;
+              update_start = PREV_INSN (update_start))
+           ;
+         update_end = NEXT_INSN (loop_end);
 
-  if (! optimize_size)
-    move_movables (loop, movables, threshold, insn_count);
+         reg_scan_update (update_start, update_end, loop_max_reg);
+         loop_max_reg = max_reg_num ();
+       }
+    }
 
   /* Now candidates that still are negative are those not moved.
      Change regs->array[I].set_in_loop to indicate that those are not actually
@@ -1331,10 +1474,14 @@ combine_movables (movables, regs)
 
   /* Regs that are set more than once are not allowed to match
      or be matched.  I'm no longer sure why not.  */
+  /* Only pseudo registers are allowed to match or be matched,
+     since move_movables does not validate the change.  */
   /* Perhaps testing m->consec_sets would be more appropriate here?  */
 
   for (m = movables->head; m; m = m->next)
     if (m->match == 0 && regs->array[m->regno].n_times_set == 1
+       && m->regno >= FIRST_PSEUDO_REGISTER
+       && !m->insert_temp
        && !m->partial)
       {
        struct movable *m1;
@@ -1347,7 +1494,9 @@ combine_movables (movables, regs)
           one match any later ones.  So start this loop at m->next.  */
        for (m1 = m->next; m1; m1 = m1->next)
          if (m != m1 && m1->match == 0
+             && !m1->insert_temp
              && regs->array[m1->regno].n_times_set == 1
+             && m1->regno >= FIRST_PSEUDO_REGISTER
              /* A reg used outside the loop mustn't be eliminated.  */
              && !m1->global
              /* A reg used for zero-extending mustn't be eliminated.  */
@@ -1749,6 +1898,10 @@ move_movables (loop, movables, threshold, insn_count)
              int count;
              struct movable *m1;
              rtx first = NULL_RTX;
+             rtx newreg = NULL_RTX;
+
+             if (m->insert_temp)
+               newreg = gen_reg_rtx (GET_MODE (m->set_dest));
 
              /* Now move the insns that set the reg.  */
 
@@ -1792,10 +1945,10 @@ move_movables (loop, movables, threshold, insn_count)
                  for (count = m->consec; count >= 0; count--)
                    {
                      /* If this is the first insn of a library call sequence,
-                        skip to the end.  */
+                        something is very wrong.  */
                      if (GET_CODE (p) != NOTE
                          && (temp = find_reg_note (p, REG_LIBCALL, NULL_RTX)))
-                       p = XEXP (temp, 0);
+                       abort ();
 
                      /* If this is the last insn of a libcall sequence, then
                         delete every insn in the sequence except the last.
@@ -1819,21 +1972,32 @@ move_movables (loop, movables, threshold, insn_count)
                         insn stream.  */
                      while (p && GET_CODE (p) == NOTE)
                        p = NEXT_INSN (temp) = NEXT_INSN (p);
+
+                     if (m->insert_temp)
+                       {
+                         /* Replace the original insn with a move from
+                            our newly created temp.  */
+                         start_sequence ();
+                         emit_move_insn (m->set_dest, newreg);
+                         seq = get_insns ();
+                         end_sequence ();
+                         emit_insn_before (seq, p);
+                       }
                    }
 
                  start_sequence ();
-                 emit_move_insn (m->set_dest, m->set_src);
-                 temp = get_insns ();
-                 seq = gen_sequence ();
+                 emit_move_insn (m->insert_temp ? newreg : m->set_dest, 
+                                 m->set_src);
+                 seq = get_insns ();
                  end_sequence ();
 
-                 add_label_notes (m->set_src, temp);
+                 add_label_notes (m->set_src, seq);
 
                  i1 = loop_insn_hoist (loop, seq);
                  if (! find_reg_note (i1, REG_EQUAL, NULL_RTX))
-                   REG_NOTES (i1)
-                     = gen_rtx_EXPR_LIST (m->is_equiv ? REG_EQUIV : REG_EQUAL,
-                                          m->set_src, REG_NOTES (i1));
+                   set_unique_reg_note (i1,
+                                        m->is_equiv ? REG_EQUIV : REG_EQUAL,
+                                        m->set_src);
 
                  if (loop_dump_stream)
                    fprintf (loop_dump_stream, " moved to %d", INSN_UID (i1));
@@ -1962,7 +2126,7 @@ move_movables (loop, movables, threshold, insn_count)
                            abort ();
                          if (tem != reg)
                            emit_move_insn (reg, tem);
-                         sequence = gen_sequence ();
+                         sequence = get_insns ();
                          end_sequence ();
                          i1 = loop_insn_hoist (loop, sequence);
                        }
@@ -1983,19 +2147,26 @@ move_movables (loop, movables, threshold, insn_count)
                             use the REG_EQUAL note.  */
                          start_sequence ();
                          emit_move_insn (m->set_dest, m->set_src);
-                         temp = get_insns ();
-                         seq = gen_sequence ();
+                         seq = get_insns ();
                          end_sequence ();
 
-                         add_label_notes (m->set_src, temp);
+                         add_label_notes (m->set_src, seq);
 
                          i1 = loop_insn_hoist (loop, seq);
                          if (! find_reg_note (i1, REG_EQUAL, NULL_RTX))
-                           REG_NOTES (i1)
-                             = gen_rtx_EXPR_LIST ((m->is_equiv ? REG_EQUIV
-                                                   : REG_EQUAL),
-                                                  m->set_src, REG_NOTES (i1));
+                           set_unique_reg_note (i1, m->is_equiv ? REG_EQUIV
+                                                    : REG_EQUAL, m->set_src);
                        }
+                     else if (m->insert_temp)
+                       {
+                         rtx *reg_map2 = (rtx *) xcalloc (REGNO (newreg), 
+                               sizeof(rtx));
+                         reg_map2 [m->regno] = newreg;
+
+                         i1 = loop_insn_hoist (loop, copy_rtx (PATTERN (p)));
+                         replace_regs (i1, reg_map2, REGNO (newreg), 1);
+                         free (reg_map2);
+                       }
                      else
                        i1 = loop_insn_hoist (loop, PATTERN (p));
 
@@ -2044,36 +2215,55 @@ move_movables (loop, movables, threshold, insn_count)
                         insn stream.  */
                      while (p && GET_CODE (p) == NOTE)
                        p = NEXT_INSN (temp) = NEXT_INSN (p);
+
+                     if (m->insert_temp)
+                       {
+                         rtx seq;
+                         /* Replace the original insn with a move from
+                            our newly created temp.  */
+                         start_sequence ();
+                         emit_move_insn (m->set_dest, newreg);
+                         seq = get_insns ();
+                         end_sequence ();
+                         emit_insn_before (seq, p);
+                       }
                    }
 
                  /* The more regs we move, the less we like moving them.  */
                  threshold -= 3;
                }
 
-             /* Any other movable that loads the same register
-                MUST be moved.  */
-             already_moved[regno] = 1;
-
-             /* This reg has been moved out of one loop.  */
-             regs->array[regno].moved_once = 1;
+             m->done = 1;
 
-             /* The reg set here is now invariant.  */
-             if (! m->partial)
-               regs->array[regno].set_in_loop = 0;
+             if (!m->insert_temp)
+               {
+                 /* Any other movable that loads the same register
+                    MUST be moved.  */
+                 already_moved[regno] = 1;
 
-             m->done = 1;
+                 /* This reg has been moved out of one loop.  */
+                 regs->array[regno].moved_once = 1;
 
-             /* Change the length-of-life info for the register
-                to say it lives at least the full length of this loop.
-                This will help guide optimizations in outer loops.  */
+                 /* The reg set here is now invariant.  */
+                 if (! m->partial)
+                   {
+                     int i;
+                     for (i = 0; i < LOOP_REGNO_NREGS (regno, m->set_dest); i++)
+                       regs->array[regno+i].set_in_loop = 0;
+                   }
 
-             if (REGNO_FIRST_LUID (regno) > INSN_LUID (loop_start))
-               /* This is the old insn before all the moved insns.
-                  We can't use the moved insn because it is out of range
-                  in uid_luid.  Only the old insns have luids.  */
-               REGNO_FIRST_UID (regno) = INSN_UID (loop_start);
-             if (REGNO_LAST_LUID (regno) < INSN_LUID (loop_end))
-               REGNO_LAST_UID (regno) = INSN_UID (loop_end);
+                 /* Change the length-of-life info for the register
+                    to say it lives at least the full length of this loop.
+                    This will help guide optimizations in outer loops.  */
+
+                 if (REGNO_FIRST_LUID (regno) > INSN_LUID (loop_start))
+                   /* This is the old insn before all the moved insns.
+                      We can't use the moved insn because it is out of range
+                      in uid_luid.  Only the old insns have luids.  */
+                   REGNO_FIRST_UID (regno) = INSN_UID (loop_start);
+                 if (REGNO_LAST_LUID (regno) < INSN_LUID (loop_end))
+                   REGNO_LAST_UID (regno) = INSN_UID (loop_end);
+               }
 
              /* Combine with this moved insn any other matching movables.  */
 
@@ -2119,7 +2309,13 @@ move_movables (loop, movables, threshold, insn_count)
                      /* The reg merged here is now invariant,
                         if the reg it matches is invariant.  */
                      if (! m->partial)
-                       regs->array[m1->regno].set_in_loop = 0;
+                       {
+                         int i;
+                         for (i = 0;
+                              i < LOOP_REGNO_NREGS (regno, m1->set_dest);
+                              i++)
+                           regs->array[m1->regno+i].set_in_loop = 0;
+                       }
                    }
            }
          else if (loop_dump_stream)
@@ -2321,6 +2517,7 @@ prescan_loop (loop)
   loop_info->pre_header_has_call = 0;
   loop_info->has_call = 0;
   loop_info->has_nonconst_call = 0;
+  loop_info->has_prefetch = 0;
   loop_info->has_volatile = 0;
   loop_info->has_tablejump = 0;
   loop_info->has_multiple_exit_targets = 0;
@@ -2332,7 +2529,8 @@ prescan_loop (loop)
   loop_info->first_loop_store_insn = NULL_RTX;
   loop_info->mems_idx = 0;
   loop_info->num_mem_sets = 0;
-
+  /* If loop opts run twice, this was set on 1st pass for 2nd.  */
+  loop_info->preconditioned = NOTE_PRECONDITIONED (end);
 
   for (insn = start; insn && GET_CODE (insn) != CODE_LABEL;
        insn = PREV_INSN (insn))
@@ -2347,8 +2545,9 @@ prescan_loop (loop)
   for (insn = NEXT_INSN (start); insn != NEXT_INSN (end);
        insn = NEXT_INSN (insn))
     {
-      if (GET_CODE (insn) == NOTE)
+      switch (GET_CODE (insn))
        {
+       case NOTE:
          if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
            {
              ++level;
@@ -2356,24 +2555,76 @@ prescan_loop (loop)
              loop->level++;
            }
          else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
-           {
-             --level;
-           }
-       }
-      else if (GET_CODE (insn) == CALL_INSN)
-       {
+           --level;
+         break;
+
+       case CALL_INSN:
          if (! CONST_OR_PURE_CALL_P (insn))
            {
              loop_info->unknown_address_altered = 1;
              loop_info->has_nonconst_call = 1;
            }
+         else if (pure_call_p (insn))
+           loop_info->has_nonconst_call = 1;
          loop_info->has_call = 1;
-       }
-      else if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
-       {
-         rtx label1 = NULL_RTX;
-         rtx label2 = NULL_RTX;
+         if (can_throw_internal (insn))
+           loop_info->has_multiple_exit_targets = 1;
+         break;
+
+       case JUMP_INSN:
+         if (! loop_info->has_multiple_exit_targets)
+           {
+             rtx set = pc_set (insn);
+
+             if (set)
+               {
+                 rtx src = SET_SRC (set);
+                 rtx label1, label2;
+
+                 if (GET_CODE (src) == IF_THEN_ELSE)
+                   {
+                     label1 = XEXP (src, 1);
+                     label2 = XEXP (src, 2);
+                   }
+                 else
+                   {
+                     label1 = src;
+                     label2 = NULL_RTX;
+                   }
+
+                 do
+                   {
+                     if (label1 && label1 != pc_rtx)
+                       {
+                         if (GET_CODE (label1) != LABEL_REF)
+                           {
+                             /* Something tricky.  */
+                             loop_info->has_multiple_exit_targets = 1;
+                             break;
+                           }
+                         else if (XEXP (label1, 0) != exit_target
+                                  && LABEL_OUTSIDE_LOOP_P (label1))
+                           {
+                             /* A jump outside the current loop.  */
+                             loop_info->has_multiple_exit_targets = 1;
+                             break;
+                           }
+                       }
+
+                     label1 = label2;
+                     label2 = NULL_RTX;
+                   }
+                 while (label1);
+               }
+             else
+               {
+                 /* A return, or something tricky.  */
+                 loop_info->has_multiple_exit_targets = 1;
+               }
+           }
+         /* FALLTHRU */
 
+       case INSN:
          if (volatile_refs_p (PATTERN (insn)))
            loop_info->has_volatile = 1;
 
@@ -2386,48 +2637,13 @@ prescan_loop (loop)
          if (! loop_info->first_loop_store_insn && loop_info->store_mems)
            loop_info->first_loop_store_insn = insn;
 
-         if (! loop_info->has_multiple_exit_targets
-             && GET_CODE (insn) == JUMP_INSN
-             && GET_CODE (PATTERN (insn)) == SET
-             && SET_DEST (PATTERN (insn)) == pc_rtx)
-           {
-             if (GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE)
-               {
-                 label1 = XEXP (SET_SRC (PATTERN (insn)), 1);
-                 label2 = XEXP (SET_SRC (PATTERN (insn)), 2);
-               }
-             else
-               {
-                 label1 = SET_SRC (PATTERN (insn));
-               }
-
-             do
-               {
-                 if (label1 && label1 != pc_rtx)
-                   {
-                     if (GET_CODE (label1) != LABEL_REF)
-                       {
-                         /* Something tricky.  */
-                         loop_info->has_multiple_exit_targets = 1;
-                         break;
-                       }
-                     else if (XEXP (label1, 0) != exit_target
-                              && LABEL_OUTSIDE_LOOP_P (label1))
-                       {
-                         /* A jump outside the current loop.  */
-                         loop_info->has_multiple_exit_targets = 1;
-                         break;
-                       }
-                   }
+         if (flag_non_call_exceptions && can_throw_internal (insn))
+           loop_info->has_multiple_exit_targets = 1;
+         break;
 
-                 label1 = label2;
-                 label2 = NULL_RTX;
-               }
-             while (label1);
-           }
+       default:
+         break;
        }
-      else if (GET_CODE (insn) == RETURN)
-       loop_info->has_multiple_exit_targets = 1;
     }
 
   /* Now, rescan the loop, setting up the LOOP_MEMS array.  */
@@ -2466,6 +2682,17 @@ prescan_loop (loop)
     }
 }
 \f
+/* Invalidate all loops containing LABEL.  */
+
+static void
+invalidate_loops_containing_label (label)
+     rtx label;
+{
+  struct loop *loop;
+  for (loop = uid_loop[INSN_UID (label)]; loop; loop = loop->outer)
+    loop->invalid = 1;
+}
+
 /* Scan the function looking for loops.  Record the start and end of each loop.
    Also mark as invalid loops any loops that contain a setjmp or are branched
    to from outside the loop.  */
@@ -2552,23 +2779,12 @@ find_and_verify_loops (f, loops)
 
   /* Any loop containing a label used in an initializer must be invalidated,
      because it can be jumped into from anywhere.  */
-
   for (label = forced_labels; label; label = XEXP (label, 1))
-    {
-      for (loop = uid_loop[INSN_UID (XEXP (label, 0))];
-          loop; loop = loop->outer)
-       loop->invalid = 1;
-    }
+    invalidate_loops_containing_label (XEXP (label, 0));
 
   /* Any loop containing a label used for an exception handler must be
      invalidated, because it can be jumped into from anywhere.  */
-
-  for (label = exception_handler_labels; label; label = XEXP (label, 1))
-    {
-      for (loop = uid_loop[INSN_UID (XEXP (label, 0))];
-          loop; loop = loop->outer)
-       loop->invalid = 1;
-    }
+  for_each_eh_label (invalidate_loops_containing_label);
 
   /* Now scan all insn's in the function.  If any JUMP_INSN branches into a
      loop that it is not contained within, that loop is marked invalid.
@@ -2592,11 +2808,7 @@ find_and_verify_loops (f, loops)
          {
            rtx note = find_reg_note (insn, REG_LABEL, NULL_RTX);
            if (note)
-             {
-               for (loop = uid_loop[INSN_UID (XEXP (note, 0))];
-                    loop; loop = loop->outer)
-                 loop->invalid = 1;
-             }
+             invalidate_loops_containing_label (XEXP (note, 0));
          }
 
        if (GET_CODE (insn) != JUMP_INSN)
@@ -2726,7 +2938,7 @@ find_and_verify_loops (f, loops)
 
                        /* If no suitable BARRIER was found, create a suitable
                           one before TARGET.  Since TARGET is a fall through
-                          path, we'll need to insert an jump around our block
+                          path, we'll need to insert a jump around our block
                           and add a BARRIER before TARGET.
 
                           This creates an extra unconditional jump outside
@@ -2747,7 +2959,8 @@ find_and_verify_loops (f, loops)
 
                        /* Include the BARRIER after INSN and copy the
                           block after LOC.  */
-                       squeeze_notes (&new_label, &last_insn_to_move);
+                       if (squeeze_notes (&new_label, &last_insn_to_move))
+                         abort ();
                        reorder_insns (new_label, last_insn_to_move, loc);
 
                        /* All those insns are now in TARGET_LOOP.  */
@@ -3091,7 +3304,7 @@ loop_invariant_p (loop, x)
 
         We don't know the loop bounds here though, so just fail for all
         labels.  */
-      if (flag_unroll_loops)
+      if (flag_old_unroll_loops)
        return 0;
       else
        return 1;
@@ -3106,7 +3319,7 @@ loop_invariant_p (loop, x)
         since the reg might be set by initialization within the loop.  */
 
       if ((x == frame_pointer_rtx || x == hard_frame_pointer_rtx
-          || x == arg_pointer_rtx)
+          || x == arg_pointer_rtx || x == pic_offset_table_rtx)
          && ! current_function_has_nonlocal_goto)
        return 1;
 
@@ -3114,6 +3327,13 @@ loop_invariant_p (loop, x)
          && REGNO (x) < FIRST_PSEUDO_REGISTER && call_used_regs[REGNO (x)])
        return 0;
 
+      /* Out-of-range regs can occur when we are called from unrolling.
+        These have always been created by the unroller and are set in
+        the loop, hence are never invariant.  */
+
+      if (REGNO (x) >= (unsigned) regs->num)
+       return 0;
+
       if (regs->array[REGNO (x)].set_in_loop < 0)
        return 2;
 
@@ -3289,125 +3509,775 @@ all_sets_invariant_p (reg, insn, table)
            return 0;
        }
     }
-}
-#endif /* 0 */
-\f
-/* Look at all uses (not sets) of registers in X.  For each, if it is
-   the single use, set USAGE[REGNO] to INSN; if there was a previous use in
-   a different insn, set USAGE[REGNO] to const0_rtx.  */
+}
+#endif /* 0 */
+\f
+/* Look at all uses (not sets) of registers in X.  For each, if it is
+   the single use, set USAGE[REGNO] to INSN; if there was a previous use in
+   a different insn, set USAGE[REGNO] to const0_rtx.  */
+
+static void
+find_single_use_in_loop (regs, insn, x)
+     struct loop_regs *regs;
+     rtx insn;
+     rtx x;
+{
+  enum rtx_code code = GET_CODE (x);
+  const char *fmt = GET_RTX_FORMAT (code);
+  int i, j;
+
+  if (code == REG)
+    regs->array[REGNO (x)].single_usage
+      = (regs->array[REGNO (x)].single_usage != 0
+        && regs->array[REGNO (x)].single_usage != insn)
+       ? const0_rtx : insn;
+
+  else if (code == SET)
+    {
+      /* Don't count SET_DEST if it is a REG; otherwise count things
+        in SET_DEST because if a register is partially modified, it won't
+        show up as a potential movable so we don't care how USAGE is set
+        for it.  */
+      if (GET_CODE (SET_DEST (x)) != REG)
+       find_single_use_in_loop (regs, insn, SET_DEST (x));
+      find_single_use_in_loop (regs, insn, SET_SRC (x));
+    }
+  else
+    for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+      {
+       if (fmt[i] == 'e' && XEXP (x, i) != 0)
+         find_single_use_in_loop (regs, insn, XEXP (x, i));
+       else if (fmt[i] == 'E')
+         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+           find_single_use_in_loop (regs, insn, XVECEXP (x, i, j));
+      }
+}
+\f
+/* Count and record any set in X which is contained in INSN.  Update
+   REGS->array[I].MAY_NOT_OPTIMIZE and LAST_SET for any register I set
+   in X.  */
+
+static void
+count_one_set (regs, insn, x, last_set)
+     struct loop_regs *regs;
+     rtx insn, x;
+     rtx *last_set;
+{
+  if (GET_CODE (x) == CLOBBER && GET_CODE (XEXP (x, 0)) == REG)
+    /* Don't move a reg that has an explicit clobber.
+       It's not worth the pain to try to do it correctly.  */
+    regs->array[REGNO (XEXP (x, 0))].may_not_optimize = 1;
+
+  if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
+    {
+      rtx dest = SET_DEST (x);
+      while (GET_CODE (dest) == SUBREG
+            || GET_CODE (dest) == ZERO_EXTRACT
+            || GET_CODE (dest) == SIGN_EXTRACT
+            || GET_CODE (dest) == STRICT_LOW_PART)
+       dest = XEXP (dest, 0);
+      if (GET_CODE (dest) == REG)
+       {
+         int i;
+         int regno = REGNO (dest);
+         for (i = 0; i < LOOP_REGNO_NREGS (regno, dest); i++)
+           {
+             /* If this is the first setting of this reg
+                in current basic block, and it was set before,
+                it must be set in two basic blocks, so it cannot
+                be moved out of the loop.  */
+             if (regs->array[regno].set_in_loop > 0
+                 && last_set == 0)
+               regs->array[regno+i].may_not_optimize = 1;
+             /* If this is not first setting in current basic block,
+                see if reg was used in between previous one and this.
+                If so, neither one can be moved.  */
+             if (last_set[regno] != 0
+                 && reg_used_between_p (dest, last_set[regno], insn))
+               regs->array[regno+i].may_not_optimize = 1;
+             if (regs->array[regno+i].set_in_loop < 127)
+               ++regs->array[regno+i].set_in_loop;
+             last_set[regno+i] = insn;
+           }
+       }
+    }
+}
+\f
+/* Given a loop that is bounded by LOOP->START and LOOP->END and that
+   is entered at LOOP->SCAN_START, return 1 if the register set in SET
+   contained in insn INSN is used by any insn that precedes INSN in
+   cyclic order starting from the loop entry point.
+
+   We don't want to use INSN_LUID here because if we restrict INSN to those
+   that have a valid INSN_LUID, it means we cannot move an invariant out
+   from an inner loop past two loops.  */
+
+static int
+loop_reg_used_before_p (loop, set, insn)
+     const struct loop *loop;
+     rtx set, insn;
+{
+  rtx reg = SET_DEST (set);
+  rtx p;
+
+  /* Scan forward checking for register usage.  If we hit INSN, we
+     are done.  Otherwise, if we hit LOOP->END, wrap around to LOOP->START.  */
+  for (p = loop->scan_start; p != insn; p = NEXT_INSN (p))
+    {
+      if (INSN_P (p) && reg_overlap_mentioned_p (reg, PATTERN (p)))
+       return 1;
+
+      if (p == loop->end)
+       p = loop->start;
+    }
+
+  return 0;
+}
+\f
+
+/* Information we collect about arrays that we might want to prefetch.  */
+struct prefetch_info
+{
+  struct iv_class *class;      /* Class this prefetch is based on.  */
+  struct induction *giv;       /* GIV this prefetch is based on.  */
+  rtx base_address;            /* Start prefetching from this address plus
+                                  index.  */
+  HOST_WIDE_INT index;
+  HOST_WIDE_INT stride;                /* Prefetch stride in bytes in each
+                                  iteration.  */
+  unsigned int bytes_accessed; /* Sum of sizes of all accesses to this
+                                  prefetch area in one iteration.  */
+  unsigned int total_bytes;    /* Total bytes loop will access in this block.
+                                  This is set only for loops with known
+                                  iteration counts and is 0xffffffff
+                                  otherwise.  */
+  int prefetch_in_loop;                /* Number of prefetch insns in loop.  */
+  int prefetch_before_loop;    /* Number of prefetch insns before loop.  */
+  unsigned int write : 1;      /* 1 for read/write prefetches.  */
+};
+
+/* Data used by check_store function.  */
+struct check_store_data
+{
+  rtx mem_address;
+  int mem_write;
+};
+
+static void check_store PARAMS ((rtx, rtx, void *));
+static void emit_prefetch_instructions PARAMS ((struct loop *));
+static int rtx_equal_for_prefetch_p PARAMS ((rtx, rtx));
+
+/* Set mem_write when mem_address is found.  Used as callback to
+   note_stores.  */
+static void
+check_store (x, pat, data)
+     rtx x, pat ATTRIBUTE_UNUSED;
+     void *data;
+{
+  struct check_store_data *d = (struct check_store_data *) data;
+
+  if ((GET_CODE (x) == MEM) && rtx_equal_p (d->mem_address, XEXP (x, 0)))
+    d->mem_write = 1;
+}
+\f
+/* Like rtx_equal_p, but attempts to swap commutative operands.  This is
+   important to get some addresses combined.  Later more sophisticated
+   transformations can be added when necessary.
+
+   ??? Same trick with swapping operand is done at several other places.
+   It can be nice to develop some common way to handle this.  */
+
+static int
+rtx_equal_for_prefetch_p (x, y)
+     rtx x, y;
+{
+  int i;
+  int j;
+  enum rtx_code code = GET_CODE (x);
+  const char *fmt;
+
+  if (x == y)
+    return 1;
+  if (code != GET_CODE (y))
+    return 0;
+
+  code = GET_CODE (x);
+
+  if (GET_RTX_CLASS (code) == 'c')
+    {
+      return ((rtx_equal_for_prefetch_p (XEXP (x, 0), XEXP (y, 0))
+              && rtx_equal_for_prefetch_p (XEXP (x, 1), XEXP (y, 1)))
+             || (rtx_equal_for_prefetch_p (XEXP (x, 0), XEXP (y, 1))
+                 && rtx_equal_for_prefetch_p (XEXP (x, 1), XEXP (y, 0))));
+    }
+  /* Compare the elements.  If any pair of corresponding elements fails to
+     match, return 0 for the whole thing.  */
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      switch (fmt[i])
+       {
+       case 'w':
+         if (XWINT (x, i) != XWINT (y, i))
+           return 0;
+         break;
+
+       case 'i':
+         if (XINT (x, i) != XINT (y, i))
+           return 0;
+         break;
+
+       case 'E':
+         /* Two vectors must have the same length.  */
+         if (XVECLEN (x, i) != XVECLEN (y, i))
+           return 0;
+
+         /* And the corresponding elements must match.  */
+         for (j = 0; j < XVECLEN (x, i); j++)
+           if (rtx_equal_for_prefetch_p (XVECEXP (x, i, j),
+                                         XVECEXP (y, i, j)) == 0)
+             return 0;
+         break;
+
+       case 'e':
+         if (rtx_equal_for_prefetch_p (XEXP (x, i), XEXP (y, i)) == 0)
+           return 0;
+         break;
+
+       case 's':
+         if (strcmp (XSTR (x, i), XSTR (y, i)))
+           return 0;
+         break;
+
+       case 'u':
+         /* These are just backpointers, so they don't matter.  */
+         break;
+
+       case '0':
+         break;
+
+         /* It is believed that rtx's at this level will never
+            contain anything but integers and other rtx's,
+            except for within LABEL_REFs and SYMBOL_REFs.  */
+       default:
+         abort ();
+       }
+    }
+  return 1;
+}
+\f
+/* Remove constant addition value from the expression X (when present)
+   and return it.  */
+
+static HOST_WIDE_INT
+remove_constant_addition (x)
+     rtx *x;
+{
+  HOST_WIDE_INT addval = 0;
+  rtx exp = *x;
+
+  /* Avoid clobbering a shared CONST expression.  */
+  if (GET_CODE (exp) == CONST)
+    {
+      if (GET_CODE (XEXP (exp, 0)) == PLUS
+         && GET_CODE (XEXP (XEXP (exp, 0), 0)) == SYMBOL_REF
+         && GET_CODE (XEXP (XEXP (exp, 0), 1)) == CONST_INT)
+       {
+         *x = XEXP (XEXP (exp, 0), 0);
+         return INTVAL (XEXP (XEXP (exp, 0), 1));
+       }
+      return 0;
+    }
+
+  if (GET_CODE (exp) == CONST_INT)
+    {
+      addval = INTVAL (exp);
+      *x = const0_rtx;
+    }
+
+  /* For plus expression recurse on ourself.  */
+  else if (GET_CODE (exp) == PLUS)
+    {
+      addval += remove_constant_addition (&XEXP (exp, 0));
+      addval += remove_constant_addition (&XEXP (exp, 1));
+
+      /* In case our parameter was constant, remove extra zero from the
+        expression.  */
+      if (XEXP (exp, 0) == const0_rtx)
+       *x = XEXP (exp, 1);
+      else if (XEXP (exp, 1) == const0_rtx)
+       *x = XEXP (exp, 0);
+    }
+
+  return addval;
+}
+
+/* Attempt to identify accesses to arrays that are most likely to cause cache
+   misses, and emit prefetch instructions a few prefetch blocks forward.
+
+   To detect the arrays we use the GIV information that was collected by the
+   strength reduction pass.
+
+   The prefetch instructions are generated after the GIV information is done
+   and before the strength reduction process. The new GIVs are injected into
+   the strength reduction tables, so the prefetch addresses are optimized as
+   well.
+
+   GIVs are split into base address, stride, and constant addition values.
+   GIVs with the same address, stride and close addition values are combined
+   into a single prefetch.  Also writes to GIVs are detected, so that prefetch
+   for write instructions can be used for the block we write to, on machines
+   that support write prefetches.
+
+   Several heuristics are used to determine when to prefetch.  They are
+   controlled by defined symbols that can be overridden for each target.  */
+
+static void
+emit_prefetch_instructions (loop)
+     struct loop *loop;
+{
+  int num_prefetches = 0;
+  int num_real_prefetches = 0;
+  int num_real_write_prefetches = 0;
+  int num_prefetches_before = 0;
+  int num_write_prefetches_before = 0;
+  int ahead = 0;
+  int i;
+  struct iv_class *bl;
+  struct induction *iv;
+  struct prefetch_info info[MAX_PREFETCHES];
+  struct loop_ivs *ivs = LOOP_IVS (loop);
+
+  if (!HAVE_prefetch)
+    return;
+
+  /* Consider only loops w/o calls.  When a call is done, the loop is probably
+     slow enough to read the memory.  */
+  if (PREFETCH_NO_CALL && LOOP_INFO (loop)->has_call)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream, "Prefetch: ignoring loop: has call.\n");
+
+      return;
+    }
+
+  /* Don't prefetch in loops known to have few iterations.  */
+  if (PREFETCH_NO_LOW_LOOPCNT
+      && LOOP_INFO (loop)->n_iterations
+      && LOOP_INFO (loop)->n_iterations <= PREFETCH_LOW_LOOPCNT)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "Prefetch: ignoring loop: not enough iterations.\n");
+      return;
+    }
+
+  /* Search all induction variables and pick those interesting for the prefetch
+     machinery.  */
+  for (bl = ivs->list; bl; bl = bl->next)
+    {
+      struct induction *biv = bl->biv, *biv1;
+      int basestride = 0;
+
+      biv1 = biv;
+
+      /* Expect all BIVs to be executed in each iteration.  This makes our
+        analysis more conservative.  */
+      while (biv1)
+       {
+         /* Discard non-constant additions that we can't handle well yet, and
+            BIVs that are executed multiple times; such BIVs ought to be
+            handled in the nested loop.  We accept not_every_iteration BIVs,
+            since these only result in larger strides and make our
+            heuristics more conservative.  */
+         if (GET_CODE (biv->add_val) != CONST_INT)
+           {
+             if (loop_dump_stream)
+               {
+                 fprintf (loop_dump_stream,
+                   "Prefetch: ignoring biv %d: non-constant addition at insn %d:",
+                          REGNO (biv->src_reg), INSN_UID (biv->insn));
+                 print_rtl (loop_dump_stream, biv->add_val);
+                 fprintf (loop_dump_stream, "\n");
+               }
+             break;
+           }
+
+         if (biv->maybe_multiple)
+           {
+             if (loop_dump_stream)
+               {
+                 fprintf (loop_dump_stream,
+                          "Prefetch: ignoring biv %d: maybe_multiple at insn %i:",
+                          REGNO (biv->src_reg), INSN_UID (biv->insn));
+                 print_rtl (loop_dump_stream, biv->add_val);
+                 fprintf (loop_dump_stream, "\n");
+               }
+             break;
+           }
+
+         basestride += INTVAL (biv1->add_val);
+         biv1 = biv1->next_iv;
+       }
+
+      if (biv1 || !basestride)
+       continue;
+
+      for (iv = bl->giv; iv; iv = iv->next_iv)
+       {
+         rtx address;
+         rtx temp;
+         HOST_WIDE_INT index = 0;
+         int add = 1;
+         HOST_WIDE_INT stride = 0;
+         int stride_sign = 1;
+         struct check_store_data d;
+         const char *ignore_reason = NULL;
+         int size = GET_MODE_SIZE (GET_MODE (iv));
+
+         /* See whether an induction variable is interesting to us and if
+            not, report the reason.  */
+         if (iv->giv_type != DEST_ADDR)
+           ignore_reason = "giv is not a destination address";
+
+         /* We are interested only in constant stride memory references
+            in order to be able to compute density easily.  */
+         else if (GET_CODE (iv->mult_val) != CONST_INT)
+           ignore_reason = "stride is not constant";
+
+         else
+           {
+             stride = INTVAL (iv->mult_val) * basestride;
+             if (stride < 0)
+               {
+                 stride = -stride;
+                 stride_sign = -1;
+               }
+
+             /* On some targets, reversed order prefetches are not
+                worthwhile.  */
+             if (PREFETCH_NO_REVERSE_ORDER && stride_sign < 0)
+               ignore_reason = "reversed order stride";
+
+             /* Prefetch of accesses with an extreme stride might not be
+                worthwhile, either.  */
+             else if (PREFETCH_NO_EXTREME_STRIDE
+                      && stride > PREFETCH_EXTREME_STRIDE)
+               ignore_reason = "extreme stride";
+
+             /* Ignore GIVs with varying add values; we can't predict the
+                value for the next iteration.  */
+             else if (!loop_invariant_p (loop, iv->add_val))
+               ignore_reason = "giv has varying add value";
+
+             /* Ignore GIVs in the nested loops; they ought to have been
+                handled already.  */
+             else if (iv->maybe_multiple)
+               ignore_reason = "giv is in nested loop";
+           }
+
+         if (ignore_reason != NULL)
+           {
+             if (loop_dump_stream)
+               fprintf (loop_dump_stream,
+                        "Prefetch: ignoring giv at %d: %s.\n",
+                        INSN_UID (iv->insn), ignore_reason);
+             continue;
+           }
+
+         /* Determine the pointer to the basic array we are examining.  It is
+            the sum of the BIV's initial value and the GIV's add_val.  */
+         address = copy_rtx (iv->add_val);
+         temp = copy_rtx (bl->initial_value);
+
+         address = simplify_gen_binary (PLUS, Pmode, temp, address);
+         index = remove_constant_addition (&address);
+
+         d.mem_write = 0;
+         d.mem_address = *iv->location;
+
+         /* When the GIV is not always executed, we might be better off by
+            not dirtying the cache pages.  */
+         if (PREFETCH_CONDITIONAL || iv->always_executed)
+           note_stores (PATTERN (iv->insn), check_store, &d);
+         else
+           {
+             if (loop_dump_stream)
+               fprintf (loop_dump_stream, "Prefetch: Ignoring giv at %d: %s\n",
+                        INSN_UID (iv->insn), "in conditional code.");
+             continue;
+           }
+
+         /* Attempt to find another prefetch to the same array and see if we
+            can merge this one.  */
+         for (i = 0; i < num_prefetches; i++)
+           if (rtx_equal_for_prefetch_p (address, info[i].base_address)
+               && stride == info[i].stride)
+             {
+               /* In case both access same array (same location
+                  just with small difference in constant indexes), merge
+                  the prefetches.  Just do the later and the earlier will
+                  get prefetched from previous iteration.
+                  The artificial threshold should not be too small,
+                  but also not bigger than small portion of memory usually
+                  traversed by single loop.  */
+               if (index >= info[i].index
+                   && index - info[i].index < PREFETCH_EXTREME_DIFFERENCE)
+                 {
+                   info[i].write |= d.mem_write;
+                   info[i].bytes_accessed += size;
+                   info[i].index = index;
+                   info[i].giv = iv;
+                   info[i].class = bl;
+                   info[num_prefetches].base_address = address;
+                   add = 0;
+                   break;
+                 }
+
+               if (index < info[i].index
+                   && info[i].index - index < PREFETCH_EXTREME_DIFFERENCE)
+                 {
+                   info[i].write |= d.mem_write;
+                   info[i].bytes_accessed += size;
+                   add = 0;
+                   break;
+                 }
+             }
+
+         /* Merging failed.  */
+         if (add)
+           {
+             info[num_prefetches].giv = iv;
+             info[num_prefetches].class = bl;
+             info[num_prefetches].index = index;
+             info[num_prefetches].stride = stride;
+             info[num_prefetches].base_address = address;
+             info[num_prefetches].write = d.mem_write;
+             info[num_prefetches].bytes_accessed = size;
+             num_prefetches++;
+             if (num_prefetches >= MAX_PREFETCHES)
+               {
+                 if (loop_dump_stream)
+                   fprintf (loop_dump_stream,
+                            "Maximal number of prefetches exceeded.\n");
+                 return;
+               }
+           }
+       }
+    }
+
+  for (i = 0; i < num_prefetches; i++)
+    {
+      int density;
+
+      /* Attempt to calculate the total number of bytes fetched by all
+        iterations of the loop.  Avoid overflow.  */
+      if (LOOP_INFO (loop)->n_iterations
+         && ((unsigned HOST_WIDE_INT) (0xffffffff / info[i].stride)
+             >= LOOP_INFO (loop)->n_iterations))
+       info[i].total_bytes = info[i].stride * LOOP_INFO (loop)->n_iterations;
+      else
+       info[i].total_bytes = 0xffffffff;
+
+      density = info[i].bytes_accessed * 100 / info[i].stride;
+
+      /* Prefetch might be worthwhile only when the loads/stores are dense.  */
+      if (PREFETCH_ONLY_DENSE_MEM)
+       if (density * 256 > PREFETCH_DENSE_MEM * 100
+           && (info[i].total_bytes / PREFETCH_BLOCK
+               >= PREFETCH_BLOCKS_BEFORE_LOOP_MIN))
+         {
+           info[i].prefetch_before_loop = 1;
+           info[i].prefetch_in_loop
+             = (info[i].total_bytes / PREFETCH_BLOCK
+                > PREFETCH_BLOCKS_BEFORE_LOOP_MAX);
+         }
+       else
+         {
+           info[i].prefetch_in_loop = 0, info[i].prefetch_before_loop = 0;
+           if (loop_dump_stream)
+             fprintf (loop_dump_stream,
+                 "Prefetch: ignoring giv at %d: %d%% density is too low.\n",
+                      INSN_UID (info[i].giv->insn), density);
+         }
+      else
+       info[i].prefetch_in_loop = 1, info[i].prefetch_before_loop = 1;
+
+      /* Find how many prefetch instructions we'll use within the loop.  */
+      if (info[i].prefetch_in_loop != 0)
+       {
+         info[i].prefetch_in_loop = ((info[i].stride + PREFETCH_BLOCK - 1)
+                                 / PREFETCH_BLOCK);
+         num_real_prefetches += info[i].prefetch_in_loop;
+         if (info[i].write)
+           num_real_write_prefetches += info[i].prefetch_in_loop;
+       }
+    }
+
+  /* Determine how many iterations ahead to prefetch within the loop, based
+     on how many prefetches we currently expect to do within the loop.  */
+  if (num_real_prefetches != 0)
+    {
+      if ((ahead = SIMULTANEOUS_PREFETCHES / num_real_prefetches) == 0)
+       {
+         if (loop_dump_stream)
+           fprintf (loop_dump_stream,
+                    "Prefetch: ignoring prefetches within loop: ahead is zero; %d < %d\n",
+                    SIMULTANEOUS_PREFETCHES, num_real_prefetches);
+         num_real_prefetches = 0, num_real_write_prefetches = 0;
+       }
+    }
+  /* We'll also use AHEAD to determine how many prefetch instructions to
+     emit before a loop, so don't leave it zero.  */
+  if (ahead == 0)
+    ahead = PREFETCH_BLOCKS_BEFORE_LOOP_MAX;
 
-static void
-find_single_use_in_loop (regs, insn, x)
-     struct loop_regs *regs;
-     rtx insn;
-     rtx x;
-{
-  enum rtx_code code = GET_CODE (x);
-  const char *fmt = GET_RTX_FORMAT (code);
-  int i, j;
+  for (i = 0; i < num_prefetches; i++)
+    {
+      /* Update if we've decided not to prefetch anything within the loop.  */
+      if (num_real_prefetches == 0)
+       info[i].prefetch_in_loop = 0;
 
-  if (code == REG)
-    regs->array[REGNO (x)].single_usage
-      = (regs->array[REGNO (x)].single_usage != 0
-        && regs->array[REGNO (x)].single_usage != insn)
-       ? const0_rtx : insn;
+      /* Find how many prefetch instructions we'll use before the loop.  */
+      if (info[i].prefetch_before_loop != 0)
+       {
+         int n = info[i].total_bytes / PREFETCH_BLOCK;
+         if (n > ahead)
+           n = ahead;
+         info[i].prefetch_before_loop = n;
+         num_prefetches_before += n;
+         if (info[i].write)
+           num_write_prefetches_before += n;
+       }
 
-  else if (code == SET)
-    {
-      /* Don't count SET_DEST if it is a REG; otherwise count things
-        in SET_DEST because if a register is partially modified, it won't
-        show up as a potential movable so we don't care how USAGE is set
-        for it.  */
-      if (GET_CODE (SET_DEST (x)) != REG)
-       find_single_use_in_loop (regs, insn, SET_DEST (x));
-      find_single_use_in_loop (regs, insn, SET_SRC (x));
+      if (loop_dump_stream)
+       {
+         if (info[i].prefetch_in_loop == 0
+             && info[i].prefetch_before_loop == 0)
+           continue;
+         fprintf (loop_dump_stream, "Prefetch insn: %d",
+                  INSN_UID (info[i].giv->insn));
+         fprintf (loop_dump_stream,
+                  "; in loop: %d; before: %d; %s\n",
+                  info[i].prefetch_in_loop,
+                  info[i].prefetch_before_loop,
+                  info[i].write ? "read/write" : "read only");
+         fprintf (loop_dump_stream,
+                  " density: %d%%; bytes_accessed: %u; total_bytes: %u\n",
+                  (int) (info[i].bytes_accessed * 100 / info[i].stride),
+                  info[i].bytes_accessed, info[i].total_bytes);
+         fprintf (loop_dump_stream, " index: ");
+         fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, info[i].index);
+         fprintf (loop_dump_stream, "; stride: ");
+         fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, info[i].stride);
+         fprintf (loop_dump_stream, "; address: ");
+         print_rtl (loop_dump_stream, info[i].base_address);
+         fprintf (loop_dump_stream, "\n");
+       }
     }
-  else
-    for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-      {
-       if (fmt[i] == 'e' && XEXP (x, i) != 0)
-         find_single_use_in_loop (regs, insn, XEXP (x, i));
-       else if (fmt[i] == 'E')
-         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-           find_single_use_in_loop (regs, insn, XVECEXP (x, i, j));
-      }
-}
-\f
-/* Count and record any set in X which is contained in INSN.  Update
-   REGS->array[I].MAY_NOT_OPTIMIZE and LAST_SET for any register I set
-   in X.  */
-
-static void
-count_one_set (regs, insn, x, last_set)
-     struct loop_regs *regs;
-     rtx insn, x;
-     rtx *last_set;
-{
-  if (GET_CODE (x) == CLOBBER && GET_CODE (XEXP (x, 0)) == REG)
-    /* Don't move a reg that has an explicit clobber.
-       It's not worth the pain to try to do it correctly.  */
-    regs->array[REGNO (XEXP (x, 0))].may_not_optimize = 1;
 
-  if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
+  if (num_real_prefetches + num_prefetches_before > 0)
     {
-      rtx dest = SET_DEST (x);
-      while (GET_CODE (dest) == SUBREG
-            || GET_CODE (dest) == ZERO_EXTRACT
-            || GET_CODE (dest) == SIGN_EXTRACT
-            || GET_CODE (dest) == STRICT_LOW_PART)
-       dest = XEXP (dest, 0);
-      if (GET_CODE (dest) == REG)
+      /* Record that this loop uses prefetch instructions.  */
+      LOOP_INFO (loop)->has_prefetch = 1;
+
+      if (loop_dump_stream)
        {
-         int regno = REGNO (dest);
-         /* If this is the first setting of this reg
-            in current basic block, and it was set before,
-            it must be set in two basic blocks, so it cannot
-            be moved out of the loop.  */
-         if (regs->array[regno].set_in_loop > 0
-             && last_set == 0)
-           regs->array[regno].may_not_optimize = 1;
-         /* If this is not first setting in current basic block,
-            see if reg was used in between previous one and this.
-            If so, neither one can be moved.  */
-         if (last_set[regno] != 0
-             && reg_used_between_p (dest, last_set[regno], insn))
-           regs->array[regno].may_not_optimize = 1;
-         if (regs->array[regno].set_in_loop < 127)
-           ++regs->array[regno].set_in_loop;
-         last_set[regno] = insn;
+         fprintf (loop_dump_stream, "Real prefetches needed within loop: %d (write: %d)\n",
+                  num_real_prefetches, num_real_write_prefetches);
+         fprintf (loop_dump_stream, "Real prefetches needed before loop: %d (write: %d)\n",
+                  num_prefetches_before, num_write_prefetches_before);
        }
     }
-}
-\f
-/* Given a loop that is bounded by LOOP->START and LOOP->END and that
-   is entered at LOOP->SCAN_START, return 1 if the register set in SET
-   contained in insn INSN is used by any insn that precedes INSN in
-   cyclic order starting from the loop entry point.
 
-   We don't want to use INSN_LUID here because if we restrict INSN to those
-   that have a valid INSN_LUID, it means we cannot move an invariant out
-   from an inner loop past two loops.  */
+  for (i = 0; i < num_prefetches; i++)
+    {
+      int y;
 
-static int
-loop_reg_used_before_p (loop, set, insn)
-     const struct loop *loop;
-     rtx set, insn;
-{
-  rtx reg = SET_DEST (set);
-  rtx p;
+      for (y = 0; y < info[i].prefetch_in_loop; y++)
+       {
+         rtx loc = copy_rtx (*info[i].giv->location);
+         rtx insn;
+         int bytes_ahead = PREFETCH_BLOCK * (ahead + y);
+         rtx before_insn = info[i].giv->insn;
+         rtx prev_insn = PREV_INSN (info[i].giv->insn);
+         rtx seq;
+
+         /* We can save some effort by offsetting the address on
+            architectures with offsettable memory references.  */
+         if (offsettable_address_p (0, VOIDmode, loc))
+           loc = plus_constant (loc, bytes_ahead);
+         else
+           {
+             rtx reg = gen_reg_rtx (Pmode);
+             loop_iv_add_mult_emit_before (loop, loc, const1_rtx,
+                                           GEN_INT (bytes_ahead), reg,
+                                           0, before_insn);
+             loc = reg;
+           }
 
-  /* Scan forward checking for register usage.  If we hit INSN, we
-     are done.  Otherwise, if we hit LOOP->END, wrap around to LOOP->START.  */
-  for (p = loop->scan_start; p != insn; p = NEXT_INSN (p))
-    {
-      if (INSN_P (p) && reg_overlap_mentioned_p (reg, PATTERN (p)))
-       return 1;
+         start_sequence ();
+         /* Make sure the address operand is valid for prefetch.  */
+         if (! (*insn_data[(int)CODE_FOR_prefetch].operand[0].predicate)
+                 (loc, insn_data[(int)CODE_FOR_prefetch].operand[0].mode))
+           loc = force_reg (Pmode, loc);
+         emit_insn (gen_prefetch (loc, GEN_INT (info[i].write),
+                                  GEN_INT (3)));
+         seq = get_insns ();
+         end_sequence ();
+         emit_insn_before (seq, before_insn);
+
+         /* Check all insns emitted and record the new GIV
+            information.  */
+         insn = NEXT_INSN (prev_insn);
+         while (insn != before_insn)
+           {
+             insn = check_insn_for_givs (loop, insn,
+                                         info[i].giv->always_executed,
+                                         info[i].giv->maybe_multiple);
+             insn = NEXT_INSN (insn);
+           }
+       }
 
-      if (p == loop->end)
-       p = loop->start;
+      if (PREFETCH_BEFORE_LOOP)
+       {
+         /* Emit insns before the loop to fetch the first cache lines or,
+            if we're not prefetching within the loop, everything we expect
+            to need.  */
+         for (y = 0; y < info[i].prefetch_before_loop; y++)
+           {
+             rtx reg = gen_reg_rtx (Pmode);
+             rtx loop_start = loop->start;
+             rtx init_val = info[i].class->initial_value;
+             rtx add_val = simplify_gen_binary (PLUS, Pmode,
+                                                info[i].giv->add_val,
+                                                GEN_INT (y * PREFETCH_BLOCK));
+
+             /* Functions called by LOOP_IV_ADD_EMIT_BEFORE expect a
+                non-constant INIT_VAL to have the same mode as REG, which
+                in this case we know to be Pmode.  */
+             if (GET_MODE (init_val) != Pmode && !CONSTANT_P (init_val))
+               {
+                 rtx seq;
+
+                 start_sequence ();
+                 init_val = convert_to_mode (Pmode, init_val, 0);
+                 seq = get_insns ();
+                 end_sequence ();
+                 loop_insn_emit_before (loop, 0, loop_start, seq);
+               }
+             loop_iv_add_mult_emit_before (loop, init_val,
+                                           info[i].giv->mult_val,
+                                           add_val, reg, 0, loop_start);
+             emit_insn_before (gen_prefetch (reg, GEN_INT (info[i].write),
+                                             GEN_INT (3)),
+                               loop_start);
+           }
+       }
     }
 
-  return 0;
+  return;
 }
 \f
 /* A "basic induction variable" or biv is a pseudo reg that is set
@@ -3422,7 +4292,7 @@ loop_reg_used_before_p (loop, set, insn)
 
 static rtx note_insn;
 
-/* Dummy register to have non-zero DEST_REG for DEST_ADDR type givs.  */
+/* Dummy register to have nonzero DEST_REG for DEST_ADDR type givs.  */
 
 static rtx addr_placeholder;
 
@@ -3457,8 +4327,8 @@ static rtx addr_placeholder;
    LOOP and INSN parameters pass MAYBE_MULTIPLE and NOT_EVERY_ITERATION to the
    callback.
 
-   NOT_EVERY_ITERATION if current insn is not executed at least once for every
-   loop iteration except for the last one.
+   NOT_EVERY_ITERATION is 1 if current insn is not known to be executed at
+   least once for every loop iteration except for the last one.
 
    MAYBE_MULTIPLE is 1 if current insn may be executed more than once for every
    loop iteration.
@@ -3468,8 +4338,6 @@ for_each_insn_in_loop (loop, fncall)
      struct loop *loop;
      loop_insn_callback fncall;
 {
-  /* This is 1 if current insn is not executed at least once for every loop
-     iteration.  */
   int not_every_iteration = 0;
   int maybe_multiple = 0;
   int past_loop_latch = 0;
@@ -3481,8 +4349,7 @@ for_each_insn_in_loop (loop, fncall)
   if (prev_nonnote_insn (loop->scan_start) != prev_nonnote_insn (loop->start))
     maybe_multiple = back_branch_in_range_p (loop, loop->scan_start);
 
-  /* Scan through loop to find all possible bivs.  */
-
+  /* Scan through loop and update NOT_EVERY_ITERATION and MAYBE_MULTIPLE.  */
   for (p = next_insn_in_loop (loop, loop->scan_start);
        p != NULL_RTX;
        p = next_insn_in_loop (loop, p))
@@ -3539,9 +4406,9 @@ for_each_insn_in_loop (loop, fncall)
          This can be any kind of jump, since we want to know if insns
          will be executed if the loop is executed.  */
          && !(JUMP_LABEL (p) == loop->top
-            && ((NEXT_INSN (NEXT_INSN (p)) == loop->end
-                 && any_uncondjump_p (p))
-                || (NEXT_INSN (p) == loop->end && any_condjump_p (p)))))
+              && ((NEXT_INSN (NEXT_INSN (p)) == loop->end
+                   && any_uncondjump_p (p))
+                  || (NEXT_INSN (p) == loop->end && any_condjump_p (p)))))
        {
          rtx label = 0;
 
@@ -3653,7 +4520,7 @@ loop_bivs_find (loop)
 }
 
 
-/* Determine how BIVS are initialised by looking through pre-header
+/* Determine how BIVS are initialized by looking through pre-header
    extended basic block.  */
 static void
 loop_bivs_init_find (loop)
@@ -3797,7 +4664,7 @@ loop_givs_check (loop)
 }
 
 
-/* Return non-zero if it is possible to eliminate the biv BL provided
+/* Return nonzero if it is possible to eliminate the biv BL provided
    all givs are reduced.  This is possible if either the reg is not
    used outside the loop, or we can compute what its final value will
    be.  */
@@ -3956,8 +4823,11 @@ loop_givs_reduce (loop, bl)
            {
              rtx insert_before;
 
+             /* Skip if location is the same as a previous one.  */
+             if (tv->same)
+               continue;
              if (! auto_inc_opt)
-               insert_before = tv->insn;
+               insert_before = NEXT_INSN (tv->insn);
              else if (auto_inc_opt == 1)
                insert_before = NEXT_INSN (v->insn);
              else
@@ -4087,10 +4957,22 @@ loop_givs_rescan (loop, bl, reg_map)
        }
       else
        {
+         rtx original_insn = v->insn;
+         rtx note;
+
          /* Not replaceable; emit an insn to set the original giv reg from
             the reduced giv, same as above.  */
-         loop_insn_emit_after (loop, 0, v->insn,
-                               gen_move_insn (v->dest_reg, v->new_reg));
+         v->insn = loop_insn_emit_after (loop, 0, original_insn,
+                                         gen_move_insn (v->dest_reg,
+                                                        v->new_reg));
+
+         /* The original insn may have a REG_EQUAL note.  This note is
+            now incorrect and may result in invalid substitutions later.
+            The original insn is dead, but may be part of a libcall
+            sequence, which doesn't seem worth the bother of handling.  */
+         note = find_reg_note (original_insn, REG_EQUAL, NULL_RTX);
+         if (note)
+           remove_note (original_insn, note);
        }
 
       /* When a loop is reversed, givs which depend on the reversed
@@ -4104,7 +4986,8 @@ loop_givs_rescan (loop, bl, reg_map)
                               v->mult_val, v->add_val, v->dest_reg);
       else if (v->final_value)
        loop_insn_sink_or_swim (loop,
-                               gen_move_insn (v->dest_reg, v->final_value));
+                               gen_load_of_final_value (v->dest_reg,
+                                                        v->final_value));
 
       if (loop_dump_stream)
        {
@@ -4279,7 +5162,7 @@ strength_reduce (loop, flags)
       return;
     }
 
-  /* Determine how BIVS are initialised by looking through pre-header
+  /* Determine how BIVS are initialized by looking through pre-header
      extended basic block.  */
   loop_bivs_init_find (loop);
 
@@ -4296,6 +5179,11 @@ strength_reduce (loop, flags)
      fail if the iteration variable is a giv.  */
   loop_iterations (loop);
 
+#ifdef HAVE_prefetch
+  if (flags & LOOP_PREFETCH)
+    emit_prefetch_instructions (loop);
+#endif
+
   /* Now for each giv for which we still don't know whether or not it is
      replaceable, check to see if it is replaceable because its final value
      can be calculated.  This must be done after loop_iterations is called,
@@ -4332,7 +5220,7 @@ strength_reduce (loop, flags)
 
       /* Check each extension dependent giv in this class to see if its
         root biv is safe from wrapping in the interior mode.  */
-      check_ext_dependant_givs (bl, loop_info);
+      check_ext_dependent_givs (bl, loop_info);
 
       /* Combine all giv's for this iv_class.  */
       combine_givs (regs, bl);
@@ -4456,13 +5344,19 @@ strength_reduce (loop, flags)
             value, so we don't need another one.  We can't calculate the
             proper final value for such a biv here anyways.  */
          if (bl->final_value && ! bl->reversed)
-             loop_insn_sink_or_swim (loop, gen_move_insn
-                                     (bl->biv->dest_reg, bl->final_value));
+             loop_insn_sink_or_swim (loop,
+                                     gen_load_of_final_value (bl->biv->dest_reg,
+                                                              bl->final_value));
 
          if (loop_dump_stream)
            fprintf (loop_dump_stream, "Reg %d: biv eliminated\n",
                     bl->regno);
        }
+      /* See above note wrt final_value.  But since we couldn't eliminate
+        the biv, we must set the value after the loop instead of before.  */
+      else if (bl->final_value && ! bl->reversed)
+       loop_insn_sink (loop, gen_load_of_final_value (bl->biv->dest_reg,
+                                                      bl->final_value));
     }
 
   /* Go through all the instructions in the loop, making all the
@@ -4509,7 +5403,8 @@ strength_reduce (loop, flags)
      collected.  Always unroll loops that would be as small or smaller
      unrolled than when rolled.  */
   if ((flags & LOOP_UNROLL)
-      || (loop_info->n_iterations > 0
+      || ((flags & LOOP_AUTO_UNROLL)
+         && loop_info->n_iterations > 0
          && unrolled_insn_copies <= insn_count))
     unroll_loop (loop, insn_count, 1);
 
@@ -4521,13 +5416,13 @@ strength_reduce (loop, flags)
   /* In case number of iterations is known, drop branch prediction note
      in the branch.  Do that only in second loop pass, as loop unrolling
      may change the number of iterations performed.  */
-  if ((flags & LOOP_BCT)
-      && loop_info->n_iterations / loop_info->unroll_number > 1)
+  if (flags & LOOP_BCT)
     {
-      int n = loop_info->n_iterations / loop_info->unroll_number;
-      predict_insn (PREV_INSN (loop->end),
-                   PRED_LOOP_ITERATIONS,
-                   REG_BR_PROB_BASE - REG_BR_PROB_BASE / n);
+      unsigned HOST_WIDE_INT n
+       = loop_info->n_iterations / loop_info->unroll_number;
+      if (n > 1)
+       predict_insn (prev_nonnote_insn (loop->end), PRED_LOOP_ITERATIONS,
+                     REG_BR_PROB_BASE - REG_BR_PROB_BASE / n);
     }
 
   if (loop_dump_stream)
@@ -4650,7 +5545,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
 
          record_giv (loop, v, p, src_reg, dest_reg, mult_val, add_val,
                      ext_val, benefit, DEST_REG, not_every_iteration,
-                     maybe_multiple, (rtx*)0);
+                     maybe_multiple, (rtx*) 0);
 
        }
     }
@@ -4715,7 +5610,7 @@ valid_initial_value_p (x, insn, call_seen, loop_start)
    as a possible giv.  INSN is the insn whose pattern X comes from.
    NOT_EVERY_ITERATION is 1 if the insn might not be executed during
    every loop iteration.  MAYBE_MULTIPLE is 1 if the insn might be executed
-   more thanonce in each loop iteration.  */
+   more than once in each loop iteration.  */
 
 static void
 find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
@@ -4832,12 +5727,13 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
   v->dest_reg = dest_reg;
   v->mult_val = mult_val;
   v->add_val = inc_val;
-  v->ext_dependant = NULL_RTX;
+  v->ext_dependent = NULL_RTX;
   v->location = location;
   v->mode = GET_MODE (dest_reg);
   v->always_computable = ! not_every_iteration;
   v->always_executed = ! not_every_iteration;
   v->maybe_multiple = maybe_multiple;
+  v->same = 0;
 
   /* Add this to the reg's iv_class, creating a class
      if this is the first incrementation of the reg.  */
@@ -4875,6 +5771,17 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
       /* Put it in the array of biv register classes.  */
       REG_IV_CLASS (ivs, REGNO (dest_reg)) = bl;
     }
+  else
+    {
+      /* Check if location is the same as a previous one.  */
+      struct induction *induction;
+      for (induction = bl->biv; induction; induction = induction->next_iv)
+       if (location == induction->location)
+         {
+           v->same = induction;
+           break;
+         }
+    }
 
   /* Update IV_CLASS entry for this biv.  */
   v->next_iv = bl->biv;
@@ -4920,7 +5827,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
   rtx set = single_set (insn);
   rtx temp;
 
-  /* Attempt to prove constantness of the values.  Don't let simplity_rtx
+  /* Attempt to prove constantness of the values.  Don't let simplify_rtx
      undo the MULT canonicalization that we performed earlier.  */
   temp = simplify_rtx (add_val);
   if (temp
@@ -4934,7 +5841,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
   v->dest_reg = dest_reg;
   v->mult_val = mult_val;
   v->add_val = add_val;
-  v->ext_dependant = ext_val;
+  v->ext_dependent = ext_val;
   v->benefit = benefit;
   v->location = location;
   v->cant_derive = 0;
@@ -5005,7 +5912,10 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
     abort ();
 
   if (type == DEST_ADDR)
-    v->replaceable = 1;
+    {
+      v->replaceable = 1;
+      v->not_replaceable = 0;
+    }
   else
     {
       /* The giv can be replaced outright by the reduced register only if all
@@ -5040,6 +5950,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
             using this biv anyways.  */
 
          v->replaceable = 1;
+         v->not_replaceable = 0;
          for (b = bl->biv; b; b = b->next_iv)
            {
              if (INSN_UID (b->insn) >= max_uid_for_loop
@@ -5115,12 +6026,8 @@ check_final_value (loop, v)
      const struct loop *loop;
      struct induction *v;
 {
-  struct loop_ivs *ivs = LOOP_IVS (loop);
-  struct iv_class *bl;
   rtx final_value = 0;
 
-  bl = REG_IV_CLASS (ivs, REGNO (v->src_reg));
-
   /* DEST_ADDR givs will never reach here, because they are always marked
      replaceable above in record_giv.  */
 
@@ -5143,13 +6050,15 @@ check_final_value (loop, v)
 #endif
 
   if ((final_value = final_giv_value (loop, v))
-      && (v->always_computable || last_use_this_basic_block (v->dest_reg, v->insn)))
+      && (v->always_executed
+         || last_use_this_basic_block (v->dest_reg, v->insn)))
     {
       int biv_increment_seen = 0, before_giv_insn = 0;
       rtx p = v->insn;
       rtx last_giv_use;
 
       v->replaceable = 1;
+      v->not_replaceable = 0;
 
       /* When trying to determine whether or not a biv increment occurs
         during the lifetime of the giv, we can ignore uses of the variable
@@ -5442,13 +6351,13 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
       return 1;
 
     case SUBREG:
-      /* If this is a SUBREG for a promoted variable, check the inner
-        value.  */
-      if (SUBREG_PROMOTED_VAR_P (x))
-       return basic_induction_var (loop, SUBREG_REG (x),
-                                   GET_MODE (SUBREG_REG (x)),
-                                   dest_reg, p, inc_val, mult_val, location);
-      return 0;
+      /* If what's inside the SUBREG is a BIV, then the SUBREG.  This will
+        handle addition of promoted variables.
+        ??? The comment at the start of this function is wrong: promoted
+        variable increments don't look like it says they do.  */
+      return basic_induction_var (loop, SUBREG_REG (x),
+                                 GET_MODE (SUBREG_REG (x)),
+                                 dest_reg, p, inc_val, mult_val, location);
 
     case REG:
       /* If this register is assigned in a previous insn, look at its
@@ -5510,10 +6419,11 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
     case CONST:
       /* convert_modes aborts if we try to convert to or from CCmode, so just
          exclude that case.  It is very unlikely that a condition code value
-        would be a useful iterator anyways.  */
+        would be a useful iterator anyways.  convert_modes aborts if we try to
+        convert a float mode to non-float or vice versa too.  */
       if (loop->level == 1
-         && GET_MODE_CLASS (mode) != MODE_CC
-         && GET_MODE_CLASS (GET_MODE (dest_reg)) != MODE_CC)
+         && GET_MODE_CLASS (mode) == GET_MODE_CLASS (GET_MODE (dest_reg))
+         && GET_MODE_CLASS (mode) != MODE_CC)
        {
          /* Possible bug here?  Perhaps we don't know the mode of X.  */
          *inc_val = convert_modes (GET_MODE (dest_reg), mode, x, 0);
@@ -5674,7 +6584,7 @@ general_induction_var (loop, x, src_reg, add_val, mult_val, ext_val,
    expression that is neither invariant nor a biv or giv), this routine
    returns 0.
 
-   For a non-zero return, the result will have a code of CONST_INT, USE,
+   For a nonzero return, the result will have a code of CONST_INT, USE,
    REG (for a BIV), PLUS, or MULT.  No other codes will occur.
 
    *BENEFIT will be incremented by the benefit of any sub-giv encountered.  */
@@ -5778,13 +6688,13 @@ simplify_giv_expr (loop, x, ext_val, benefit)
        tem = arg0, arg0 = arg1, arg1 = tem;
 
       if (GET_CODE (arg1) == PLUS)
-         return
-           simplify_giv_expr (loop,
-                              gen_rtx_PLUS (mode,
-                                            gen_rtx_PLUS (mode, arg0,
-                                                          XEXP (arg1, 0)),
-                                            XEXP (arg1, 1)),
-                              ext_val, benefit);
+       return
+         simplify_giv_expr (loop,
+                            gen_rtx_PLUS (mode,
+                                          gen_rtx_PLUS (mode, arg0,
+                                                        XEXP (arg1, 0)),
+                                          XEXP (arg1, 1)),
+                            ext_val, benefit);
 
       /* Now must have MULT + MULT.  Distribute if same biv, else not giv.  */
       if (GET_CODE (arg0) != MULT || GET_CODE (arg1) != MULT)
@@ -5861,7 +6771,7 @@ simplify_giv_expr (loop, x, ext_val, benefit)
                                                                    arg1)),
                                        ext_val, benefit);
            }
-         /* Porpagate the MULT expressions to the intermost nodes.  */
+         /* Propagate the MULT expressions to the intermost nodes.  */
          else if (GET_CODE (arg0) == PLUS)
            {
              /* (invar_0 + invar_1) * invar_2.  Distribute.  */
@@ -5995,12 +6905,12 @@ simplify_giv_expr (loop, x, ext_val, benefit)
            arg0 = simplify_giv_expr (loop, tem, ext_val, benefit);
            if (*ext_val)
              {
-               if (!v->ext_dependant)
+               if (!v->ext_dependent)
                  return arg0;
              }
            else
              {
-               *ext_val = v->ext_dependant;
+               *ext_val = v->ext_dependent;
                return arg0;
              }
            return 0;
@@ -6027,7 +6937,7 @@ simplify_giv_expr (loop, x, ext_val, benefit)
                      return simplify_giv_expr (loop, m->match->set_dest,
                                                ext_val, benefit);
 
-                   /* If consec is non-zero, this is a member of a group of
+                   /* If consec is nonzero, this is a member of a group of
                       instructions that were moved together.  We handle this
                       case only to the point of seeking to the last insn and
                       looking for a REG_EQUAL.  Fail if we don't find one.  */
@@ -6217,7 +7127,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
   v->benefit = first_benefit;
   v->cant_derive = 0;
   v->derive_adjustment = 0;
-  v->ext_dependant = NULL_RTX;
+  v->ext_dependent = NULL_RTX;
 
   REG_IV_TYPE (ivs, REGNO (dest_reg)) = GENERAL_INDUCT;
   REG_IV_INFO (ivs, REGNO (dest_reg)) = v;
@@ -6507,21 +7417,8 @@ combine_givs_p (g1, g2)
      the expression of G2 in terms of G1 can be used.  */
   if (ret != NULL_RTX
       && g2->giv_type == DEST_ADDR
-      && memory_address_p (GET_MODE (g2->mem), ret)
-      /* ??? Looses, especially with -fforce-addr, where *g2->location
-        will always be a register, and so anything more complicated
-        gets discarded.  */
-#if 0
-#ifdef ADDRESS_COST
-      && ADDRESS_COST (tem) <= ADDRESS_COST (*g2->location)
-#else
-      && rtx_cost (tem, MEM) <= rtx_cost (*g2->location, MEM)
-#endif
-#endif
-      )
-    {
-      return ret;
-    }
+      && memory_address_p (GET_MODE (g2->mem), ret))
+    return ret;
 
   return NULL_RTX;
 }
@@ -6531,7 +7428,7 @@ combine_givs_p (g1, g2)
    make the giv illegal.  */
 
 static void
-check_ext_dependant_givs (bl, loop_info)
+check_ext_dependent_givs (bl, loop_info)
      struct iv_class *bl;
      struct loop_info *loop_info;
 {
@@ -6547,7 +7444,7 @@ check_ext_dependant_givs (bl, loop_info)
      constants in order to be certain of no overflow.  */
   /* ??? An unknown iteration count with an increment of +-1
      combined with friendly exit tests of against an invariant
-     value is also ameanable to optimization.  Not implemented.  */
+     value is also amenable to optimization.  Not implemented.  */
   if (loop_info->n_iterations > 0
       && bl->initial_value
       && GET_CODE (bl->initial_value) == CONST_INT
@@ -6569,7 +7466,7 @@ check_ext_dependant_givs (bl, loop_info)
        neg_incr = 1, abs_incr = -abs_incr;
       total_incr = abs_incr * loop_info->n_iterations;
 
-      /* Check for host arithmatic overflow.  */
+      /* Check for host arithmetic overflow.  */
       if (total_incr / loop_info->n_iterations == abs_incr)
        {
          unsigned HOST_WIDE_INT u_max;
@@ -6582,7 +7479,7 @@ check_ext_dependant_givs (bl, loop_info)
 
          /* Check zero extension of biv ok.  */
          if (start_val >= 0
-             /* Check for host arithmatic overflow.  */
+             /* Check for host arithmetic overflow.  */
              && (neg_incr
                  ? u_end_val < u_start_val
                  : u_end_val > u_start_val)
@@ -6600,7 +7497,7 @@ check_ext_dependant_givs (bl, loop_info)
             keep this fact in mind -- myself included on occasion.
             So leave alone with the signed overflow optimizations.  */
          if (start_val >= -s_max - 1
-             /* Check for host arithmatic overflow.  */
+             /* Check for host arithmetic overflow.  */
              && (neg_incr
                  ? s_end_val < start_val
                  : s_end_val > start_val)
@@ -6616,9 +7513,9 @@ check_ext_dependant_givs (bl, loop_info)
 
   /* Invalidate givs that fail the tests.  */
   for (v = bl->giv; v; v = v->next_iv)
-    if (v->ext_dependant)
+    if (v->ext_dependent)
       {
-       enum rtx_code code = GET_CODE (v->ext_dependant);
+       enum rtx_code code = GET_CODE (v->ext_dependent);
        int ok = 0;
 
        switch (code)
@@ -6638,7 +7535,7 @@ check_ext_dependant_givs (bl, loop_info)
               derived GIV.  */
            if (se_ok && ze_ok)
              {
-               enum machine_mode outer_mode = GET_MODE (v->ext_dependant);
+               enum machine_mode outer_mode = GET_MODE (v->ext_dependent);
                unsigned HOST_WIDE_INT max = GET_MODE_MASK (outer_mode) >> 1;
 
                /* We know from the above that both endpoints are nonnegative,
@@ -6697,12 +7594,12 @@ extend_value_for_giv (v, value)
      struct induction *v;
      rtx value;
 {
-  rtx ext_dep = v->ext_dependant;
+  rtx ext_dep = v->ext_dependent;
 
   if (! ext_dep)
     return value;
 
-  /* Recall that check_ext_dependant_givs verified that the known bounds
+  /* Recall that check_ext_dependent_givs verified that the known bounds
      of a biv did not overflow or wrap with respect to the extension for
      the giv.  Therefore, constants need no additional adjustment.  */
   if (CONSTANT_P (value) && GET_MODE (value) == VOIDmode)
@@ -6929,7 +7826,7 @@ gen_add_mult (b, m, a, reg)
   result = expand_mult_add (b, reg, m, a, GET_MODE (reg), 1);
   if (reg != result)
     emit_move_insn (reg, result);
-  seq = gen_sequence ();
+  seq = get_insns ();
   end_sequence ();
 
   return seq;
@@ -6943,24 +7840,29 @@ loop_regs_update (loop, seq)
      const struct loop *loop ATTRIBUTE_UNUSED;
      rtx seq;
 {
+  rtx insn;
+
   /* Update register info for alias analysis.  */
 
-  if (GET_CODE (seq) == SEQUENCE)
+  if (seq == NULL_RTX)
+    return;
+
+  if (INSN_P (seq))
     {
-      int i;
-      for (i = 0; i < XVECLEN (seq, 0); ++i)
+      insn = seq;
+      while (insn != NULL_RTX)
        {
-         rtx set = single_set (XVECEXP (seq, 0, i));
+         rtx set = single_set (insn);
+
          if (set && GET_CODE (SET_DEST (set)) == REG)
            record_base_value (REGNO (SET_DEST (set)), SET_SRC (set), 0);
+
+         insn = NEXT_INSN (insn);
        }
     }
-  else
-    {
-      rtx set = single_set (seq);
-      if (set && GET_CODE (SET_DEST (set)) == REG)
-       record_base_value (REGNO (SET_DEST (set)), SET_SRC (set), 0);
-    }
+  else if (GET_CODE (seq) == SET
+          && GET_CODE (SET_DEST (seq)) == REG)
+    record_base_value (REGNO (SET_DEST (seq)), SET_SRC (seq), 0);
 }
 
 
@@ -6985,7 +7887,7 @@ loop_iv_add_mult_emit_before (loop, b, m, a, reg, before_bb, before_insn)
     }
 
   /* Use copy_rtx to prevent unexpected sharing of these rtx.  */
-  seq = gen_add_mult (copy_rtx (b), m, copy_rtx (a), reg);
+  seq = gen_add_mult (copy_rtx (b), copy_rtx (m), copy_rtx (a), reg);
 
   /* Increase the lifetime of any invariants moved further in code.  */
   update_reg_last_use (a, before_insn);
@@ -7013,7 +7915,7 @@ loop_iv_add_mult_sink (loop, b, m, a, reg)
   rtx seq;
 
   /* Use copy_rtx to prevent unexpected sharing of these rtx.  */
-  seq = gen_add_mult (copy_rtx (b), m, copy_rtx (a), reg);
+  seq = gen_add_mult (copy_rtx (b), copy_rtx (m), copy_rtx (a), reg);
 
   /* Increase the lifetime of any invariants moved further in code.
      ???? Is this really necessary?  */
@@ -7042,7 +7944,7 @@ loop_iv_add_mult_hoist (loop, b, m, a, reg)
   rtx seq;
 
   /* Use copy_rtx to prevent unexpected sharing of these rtx.  */
-  seq = gen_add_mult (copy_rtx (b), m, copy_rtx (a), reg);
+  seq = gen_add_mult (copy_rtx (b), copy_rtx (m), copy_rtx (a), reg);
 
   loop_insn_hoist (loop, seq);
 
@@ -7083,16 +7985,20 @@ iv_add_mult_cost (b, m, a, reg)
 }
 \f
 /* Test whether A * B can be computed without
-   an actual multiply insn.  Value is 1 if so.  */
+   an actual multiply insn.  Value is 1 if so.
+
+  ??? This function stinks because it generates a ton of wasted RTL
+  ??? and as a result fragments GC memory to no end.  There are other
+  ??? places in the compiler which are invoked a lot and do the same
+  ??? thing, generate wasted RTL just to see if something is possible.  */
 
 static int
 product_cheap_p (a, b)
      rtx a;
      rtx b;
 {
-  int i;
   rtx tmp;
-  int win = 1;
+  int win, n_insns;
 
   /* If only one is constant, make it B.  */
   if (GET_CODE (a) == CONST_INT)
@@ -7112,31 +8018,31 @@ product_cheap_p (a, b)
 
   start_sequence ();
   expand_mult (GET_MODE (a), a, b, NULL_RTX, 1);
-  tmp = gen_sequence ();
+  tmp = get_insns ();
   end_sequence ();
 
-  if (GET_CODE (tmp) == SEQUENCE)
+  win = 1;
+  if (INSN_P (tmp))
     {
-      if (XVEC (tmp, 0) == 0)
-       win = 1;
-      else if (XVECLEN (tmp, 0) > 3)
-       win = 0;
-      else
-       for (i = 0; i < XVECLEN (tmp, 0); i++)
-         {
-           rtx insn = XVECEXP (tmp, 0, i);
-
-           if (GET_CODE (insn) != INSN
-               || (GET_CODE (PATTERN (insn)) == SET
-                   && GET_CODE (SET_SRC (PATTERN (insn))) == MULT)
-               || (GET_CODE (PATTERN (insn)) == PARALLEL
-                   && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET
-                   && GET_CODE (SET_SRC (XVECEXP (PATTERN (insn), 0, 0))) == MULT))
-             {
-               win = 0;
-               break;
-             }
-         }
+      n_insns = 0;
+      while (tmp != NULL_RTX)
+       {
+         rtx next = NEXT_INSN (tmp);
+
+         if (++n_insns > 3
+             || GET_CODE (tmp) != INSN
+             || (GET_CODE (PATTERN (tmp)) == SET
+                 && GET_CODE (SET_SRC (PATTERN (tmp))) == MULT)
+             || (GET_CODE (PATTERN (tmp)) == PARALLEL
+                 && GET_CODE (XVECEXP (PATTERN (tmp), 0, 0)) == SET
+                 && GET_CODE (SET_SRC (XVECEXP (PATTERN (tmp), 0, 0))) == MULT))
+           {
+             win = 0;
+             break;
+           }
+
+         tmp = next;
+       }
     }
   else if (GET_CODE (tmp) == SET
           && GET_CODE (SET_SRC (tmp)) == MULT)
@@ -7318,7 +8224,9 @@ check_dbra_loop (loop, insn_count)
         which is reversible.  */
       int reversible_mem_store = 1;
 
-      if (bl->giv_count == 0 && ! loop->exit_count)
+      if (bl->giv_count == 0
+         && !loop->exit_count
+         && !loop_info->has_multiple_exit_targets)
        {
          rtx bivreg = regno_reg_rtx[bl->regno];
          struct iv_class *blt;
@@ -7359,9 +8267,11 @@ check_dbra_loop (loop, insn_count)
                  }
              }
 
-         /* A biv has uses besides counting if it is used to set another biv.  */
+         /* A biv has uses besides counting if it is used to set
+            another biv.  */
          for (blt = ivs->list; blt; blt = blt->next)
-           if (blt->init_set && reg_mentioned_p (bivreg, SET_SRC (blt->init_set)))
+           if (blt->init_set
+               && reg_mentioned_p (bivreg, SET_SRC (blt->init_set)))
              {
                no_use_except_counting = 0;
                break;
@@ -7420,12 +8330,13 @@ check_dbra_loop (loop, insn_count)
 
       if ((num_nonfixed_reads <= 1
           && ! loop_info->has_nonconst_call
+          && ! loop_info->has_prefetch
           && ! loop_info->has_volatile
           && reversible_mem_store
           && (bl->giv_count + bl->biv_count + loop_info->num_mem_sets
               + num_unmoved_movables (loop) + compare_and_branch == insn_count)
           && (bl == ivs->list && bl->next == 0))
-         || no_use_except_counting)
+         || (no_use_except_counting && ! loop_info->has_prefetch))
        {
          rtx tem;
 
@@ -7622,7 +8533,7 @@ check_dbra_loop (loop, insn_count)
                 create a sequence to hold all the insns from expand_inc.  */
              start_sequence ();
              expand_inc (reg, new_add_val);
-             tem = gen_sequence ();
+             tem = get_insns ();
              end_sequence ();
 
              p = loop_insn_emit_before (loop, 0, bl->biv->insn, tem);
@@ -7651,7 +8562,7 @@ check_dbra_loop (loop, insn_count)
              if ((REGNO_LAST_UID (bl->regno) != INSN_UID (first_compare))
                  || ! bl->init_insn
                  || REGNO_FIRST_UID (bl->regno) != INSN_UID (bl->init_insn))
-               loop_insn_sink (loop, gen_move_insn (reg, final_value));
+               loop_insn_sink (loop, gen_load_of_final_value (reg, final_value));
 
              /* Delete compare/branch at end of loop.  */
              delete_related_insns (PREV_INSN (loop_end));
@@ -7661,9 +8572,9 @@ check_dbra_loop (loop, insn_count)
              /* Add new compare/branch insn at end of loop.  */
              start_sequence ();
              emit_cmp_and_jump_insns (reg, const0_rtx, cmp_code, NULL_RTX,
-                                      GET_MODE (reg), 0, 0,
+                                      GET_MODE (reg), 0,
                                       XEXP (jump_label, 0));
-             tem = gen_sequence ();
+             tem = get_insns ();
              end_sequence ();
              emit_jump_insn_before (tem, loop_end);
 
@@ -7748,7 +8659,7 @@ check_dbra_loop (loop, insn_count)
 /* Verify whether the biv BL appears to be eliminable,
    based on the insns in the loop that refer to it.
 
-   If ELIMINATE_P is non-zero, actually do the elimination.
+   If ELIMINATE_P is nonzero, actually do the elimination.
 
    THRESHOLD and INSN_COUNT are from loop_optimize and are used to
    determine whether invariant insns should be placed inside or at the
@@ -7773,11 +8684,12 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
       enum rtx_code code = GET_CODE (p);
       basic_block where_bb = 0;
       rtx where_insn = threshold >= insn_count ? 0 : p;
+      rtx note;
 
       /* If this is a libcall that sets a giv, skip ahead to its end.  */
       if (GET_RTX_CLASS (code) == 'i')
        {
-         rtx note = find_reg_note (p, REG_LIBCALL, NULL_RTX);
+         note = find_reg_note (p, REG_LIBCALL, NULL_RTX);
 
          if (note)
            {
@@ -7795,6 +8707,8 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
                }
            }
        }
+
+      /* Closely examine the insn if the biv is mentioned.  */
       if ((code == INSN || code == JUMP_INSN || code == CALL_INSN)
          && reg_mentioned_p (reg, PATTERN (p))
          && ! maybe_eliminate_biv_1 (loop, PATTERN (p), p, bl,
@@ -7806,6 +8720,12 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
                     bl->regno, INSN_UID (p));
          break;
        }
+
+      /* If we are eliminating, kill REG_EQUAL notes mentioning the biv.  */
+      if (eliminate_p
+         && (note = find_reg_note (p, REG_EQUAL, NULL_RTX)) != NULL_RTX
+         && reg_mentioned_p (reg, XEXP (note, 0)))
+       remove_note (p, note);
     }
 
   if (p == loop->end)
@@ -7820,7 +8740,7 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
 }
 \f
 /* INSN and REFERENCE are instructions in the same insn chain.
-   Return non-zero if INSN is first.  */
+   Return nonzero if INSN is first.  */
 
 int
 loop_insn_first_p (insn, reference)
@@ -7833,9 +8753,9 @@ loop_insn_first_p (insn, reference)
       /* Start with test for not first so that INSN == REFERENCE yields not
          first.  */
       if (q == insn || ! p)
-        return 0;
+       return 0;
       if (p == reference || ! q)
-        return 1;
+       return 1;
 
       /* Either of P or Q might be a NOTE.  Notes have the same LUID as the
          previous insn, hence the <= comparison below does not work if
@@ -7853,7 +8773,7 @@ loop_insn_first_p (insn, reference)
     }
 }
 
-/* We are trying to eliminate BIV in INSN using GIV.  Return non-zero if
+/* We are trying to eliminate BIV in INSN using GIV.  Return nonzero if
    the offset that we have to take into account due to auto-increment /
    div derivation is zero.  */
 static int
@@ -7880,10 +8800,10 @@ biv_elimination_giv_has_0_offset (biv, giv, insn)
 
    If BIV does not appear in X, return 1.
 
-   If ELIMINATE_P is non-zero, actually do the elimination.
+   If ELIMINATE_P is nonzero, actually do the elimination.
    WHERE_INSN/WHERE_BB indicate where extra insns should be added.
    Depending on how many items have been moved out of the loop, it
-   will either be before INSN (when WHERE_INSN is non-zero) or at the
+   will either be before INSN (when WHERE_INSN is nonzero) or at the
    start of the loop (when WHERE_INSN is zero).  */
 
 static int
@@ -8049,6 +8969,22 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where_bb, where_insn)
                if (! biv_elimination_giv_has_0_offset (bl->biv, v, insn))
                  continue;
 
+               /* Don't eliminate if the linear combination that makes up
+                  the giv overflows when it is applied to ARG.  */
+               if (GET_CODE (arg) == CONST_INT)
+                 {
+                   rtx add_val;
+
+                   if (GET_CODE (v->add_val) == CONST_INT)
+                     add_val = v->add_val;
+                   else
+                     add_val = const0_rtx;
+
+                   if (const_mult_add_overflow_p (arg, v->mult_val,
+                                                  add_val, mode, 1))
+                     continue;
+                 }
+
                if (! eliminate_p)
                  return 1;
 
@@ -8059,13 +8995,10 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where_bb, where_insn)
                   the derived constant can be directly placed in the COMPARE,
                   do so.  */
                if (GET_CODE (arg) == CONST_INT
-                   && GET_CODE (v->mult_val) == CONST_INT
                    && GET_CODE (v->add_val) == CONST_INT)
                  {
-                   validate_change (insn, &XEXP (x, arg_operand),
-                                    GEN_INT (INTVAL (arg)
-                                             * INTVAL (v->mult_val)
-                                             + INTVAL (v->add_val)), 1);
+                   tem = expand_mult_add (arg, NULL_RTX, v->mult_val,
+                                          v->add_val, mode, 1);
                  }
                else
                  {
@@ -8074,8 +9007,10 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where_bb, where_insn)
                    loop_iv_add_mult_emit_before (loop, arg,
                                                  v->mult_val, v->add_val,
                                                  tem, where_bb, where_insn);
-                   validate_change (insn, &XEXP (x, arg_operand), tem, 1);
                  }
+
+               validate_change (insn, &XEXP (x, arg_operand), tem, 1);
+
                if (apply_change_group ())
                  return 1;
              }
@@ -8338,14 +9273,14 @@ update_reg_last_use (x, insn)
    If the condition cannot be understood, or is an inequality floating-point
    comparison which needs to be reversed, 0 will be returned.
 
-   If REVERSE is non-zero, then reverse the condition prior to canonizing it.
+   If REVERSE is nonzero, then reverse the condition prior to canonizing it.
 
-   If EARLIEST is non-zero, it is a pointer to a place where the earliest
+   If EARLIEST is nonzero, it is a pointer to a place where the earliest
    insn used in locating the condition was found.  If a replacement test
    of the condition is desired, it should be placed in front of that
    insn and we will be sure that the inputs are still valid.
 
-   If WANT_REG is non-zero, we wish the condition to be relative to that
+   If WANT_REG is nonzero, we wish the condition to be relative to that
    register, if possible.  Therefore, do not canonicalize the condition
    further.  */
 
@@ -8387,7 +9322,7 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
         && op1 == CONST0_RTX (GET_MODE (op0))
         && op0 != want_reg)
     {
-      /* Set non-zero when we find something of interest.  */
+      /* Set nonzero when we find something of interest.  */
       rtx x = 0;
 
 #ifdef HAVE_cc0
@@ -8424,7 +9359,7 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
 
       if ((prev = prev_nonnote_insn (prev)) == 0
          || GET_CODE (prev) != INSN
-         || FIND_REG_INC_NOTE (prev, 0))
+         || FIND_REG_INC_NOTE (prev, NULL_RTX))
        break;
 
       set = set_of (op0, prev);
@@ -8439,6 +9374,9 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
       if (set)
        {
          enum machine_mode inner_mode = GET_MODE (SET_DEST (set));
+#ifdef FLOAT_STORE_FLAG_VALUE
+         REAL_VALUE_TYPE fsfv;
+#endif
 
          /* ??? We may not combine comparisons done in a CCmode with
             comparisons not done in a CCmode.  This is to aid targets
@@ -8466,8 +9404,8 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
 #ifdef FLOAT_STORE_FLAG_VALUE
                     || (code == LT
                         && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
-                        && (REAL_VALUE_NEGATIVE
-                            (FLOAT_STORE_FLAG_VALUE (inner_mode))))
+                        && (fsfv = FLOAT_STORE_FLAG_VALUE (inner_mode),
+                            REAL_VALUE_NEGATIVE (fsfv)))
 #endif
                     ))
                   && GET_RTX_CLASS (GET_CODE (SET_SRC (set))) == '<'))
@@ -8486,8 +9424,8 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
 #ifdef FLOAT_STORE_FLAG_VALUE
                     || (code == GE
                         && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
-                        && (REAL_VALUE_NEGATIVE
-                            (FLOAT_STORE_FLAG_VALUE (inner_mode))))
+                        && (fsfv = FLOAT_STORE_FLAG_VALUE (inner_mode),
+                            REAL_VALUE_NEGATIVE (fsfv)))
 #endif
                     ))
                   && GET_RTX_CLASS (GET_CODE (SET_SRC (set))) == '<'
@@ -8551,7 +9489,7 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
        {
        case LE:
          if ((unsigned HOST_WIDE_INT) const_val != max_val >> 1)
-           code = LT, op1 = GEN_INT (const_val + 1);
+           code = LT, op1 = gen_int_mode (const_val + 1, GET_MODE (op0));
          break;
 
        /* When cross-compiling, const_val might be sign-extended from
@@ -8560,17 +9498,17 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
          if ((HOST_WIDE_INT) (const_val & max_val)
              != (((HOST_WIDE_INT) 1
                   << (GET_MODE_BITSIZE (GET_MODE (op0)) - 1))))
-           code = GT, op1 = GEN_INT (const_val - 1);
+           code = GT, op1 = gen_int_mode (const_val - 1, GET_MODE (op0));
          break;
 
        case LEU:
          if (uconst_val < max_val)
-           code = LTU, op1 = GEN_INT (uconst_val + 1);
+           code = LTU, op1 = gen_int_mode (uconst_val + 1, GET_MODE (op0));
          break;
 
        case GEU:
          if (uconst_val != 0)
-           code = GTU, op1 = GEN_INT (uconst_val - 1);
+           code = GTU, op1 = gen_int_mode (uconst_val - 1, GET_MODE (op0));
          break;
 
        default:
@@ -8578,11 +9516,9 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
        }
     }
 
-#ifdef HAVE_cc0
   /* Never return CC0; return zero instead.  */
-  if (op0 == cc0_rtx)
+  if (CC0_P (op0))
     return 0;
-#endif
 
   return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
 }
@@ -8592,7 +9528,7 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
    inequality floating-point comparison which needs to be reversed, 0 will
    be returned.
 
-   If EARLIEST is non-zero, it is a pointer to a place where the earliest
+   If EARLIEST is nonzero, it is a pointer to a place where the earliest
    insn used in locating the condition was found.  If a replacement test
    of the condition is desired, it should be placed in front of that
    insn and we will be sure that the inputs are still valid.  */
@@ -8631,7 +9567,7 @@ get_condition_for_loop (loop, x)
      const struct loop *loop;
      rtx x;
 {
-  rtx comparison = get_condition (x, (rtx*)0);
+  rtx comparison = get_condition (x, (rtx*) 0);
 
   if (comparison == 0
       || ! loop_invariant_p (loop, XEXP (comparison, 0))
@@ -8819,14 +9755,40 @@ loop_regs_scan (loop, extra_size)
 
       if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN)
        memset (last_set, 0, regs->num * sizeof (rtx));
-    }
 
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    {
-      regs->array[i].may_not_optimize = 1;
-      regs->array[i].set_in_loop = 1;
+      /* Invalidate all registers used for function argument passing.
+        We check rtx_varies_p for the same reason as below, to allow
+        optimizing PIC calculations.  */
+      if (GET_CODE (insn) == CALL_INSN)
+       {
+         rtx link;
+         for (link = CALL_INSN_FUNCTION_USAGE (insn); 
+              link; 
+              link = XEXP (link, 1))
+           {
+             rtx op, reg;
+
+             if (GET_CODE (op = XEXP (link, 0)) == USE
+                 && GET_CODE (reg = XEXP (op, 0)) == REG
+                 && rtx_varies_p (reg, 1))
+               regs->array[REGNO (reg)].may_not_optimize = 1;
+           }
+       }
     }
 
+  /* Invalidate all hard registers clobbered by calls.  With one exception:
+     a call-clobbered PIC register is still function-invariant for our
+     purposes, since we can hoist any PIC calculations out of the loop.
+     Thus the call to rtx_varies_p.  */
+  if (LOOP_INFO (loop)->has_call)
+    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+      if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i)
+         && rtx_varies_p (regno_reg_rtx[i], 1))
+       {
+         regs->array[i].may_not_optimize = 1;
+         regs->array[i].set_in_loop = 1;
+       }
+
 #ifdef AVOID_CCMODE_COPIES
   /* Don't try to move insns which set CC registers if we should not
      create CCmode register copies.  */
@@ -9064,9 +10026,20 @@ load_mems (loop)
                  && rtx_equal_p (SET_DEST (set), mem))
                SET_REGNO_REG_SET (&store_copies, REGNO (SET_SRC (set)));
 
-             /* Replace the memory reference with the shadow register.  */
-             replace_loop_mems (p, loop_info->mems[i].mem,
-                                loop_info->mems[i].reg);
+             /* If this is a call which uses / clobbers this memory
+                location, we must not change the interface here.  */
+             if (GET_CODE (p) == CALL_INSN
+                 && reg_mentioned_p (loop_info->mems[i].mem,
+                                     CALL_INSN_FUNCTION_USAGE (p)))
+               {
+                 cancel_changes (0);
+                 loop_info->mems[i].optimize = 0;
+                 break;
+               }
+             else
+               /* Replace the memory reference with the shadow register.  */
+               replace_loop_mems (p, loop_info->mems[i].mem,
+                                  loop_info->mems[i].reg, written);
            }
 
          if (GET_CODE (p) == CODE_LABEL
@@ -9074,7 +10047,9 @@ load_mems (loop)
            maybe_never = 1;
        }
 
-      if (! apply_change_group ())
+      if (! loop_info->mems[i].optimize)
+       ; /* We found we couldn't do the replacement, so do nothing.  */
+      else if (! apply_change_group ())
        /* We couldn't replace all occurrences of the MEM.  */
        loop_info->mems[i].optimize = 0;
       else
@@ -9136,9 +10111,7 @@ load_mems (loop)
            }
 
          if (const_equiv)
-           REG_NOTES (set) = gen_rtx_EXPR_LIST (REG_EQUAL,
-                                                copy_rtx (const_equiv->loc),
-                                                REG_NOTES (set));
+           set_unique_reg_note (set, REG_EQUAL, copy_rtx (const_equiv->loc));
 
          if (written)
            {
@@ -9185,22 +10158,14 @@ load_mems (loop)
     {
       /* Now, we need to replace all references to the previous exit
         label with the new one.  */
-      rtx_pair rr;
+      replace_label_data rr;
       rr.r1 = end_label;
       rr.r2 = label;
+      rr.update_label_nuses = true;
 
       for (p = loop->start; p != loop->end; p = NEXT_INSN (p))
        {
          for_each_rtx (&p, replace_label, &rr);
-
-         /* If this is a JUMP_INSN, then we also need to fix the JUMP_LABEL
-            field.  This is not handled by for_each_rtx because it doesn't
-            handle unprinted ('0') fields.  We need to update JUMP_LABEL
-            because the immediately following unroll pass will use it.
-            replace_label would not work anyways, because that only handles
-            LABEL_REFs.  */
-         if (GET_CODE (p) == JUMP_INSN && JUMP_LABEL (p) == end_label)
-           JUMP_LABEL (p) = label;
        }
     }
 
@@ -9439,6 +10404,33 @@ try_swap_copy_prop (loop, replacement, regno)
     }
 }
 
+/* Worker function for find_mem_in_note, called via for_each_rtx.  */
+
+static int
+find_mem_in_note_1 (x, data)
+     rtx *x;
+     void *data;
+{
+  if (*x != NULL_RTX && GET_CODE (*x) == MEM)
+    {
+      rtx *res = (rtx *) data;
+      *res = *x;
+      return 1;
+    }
+  return 0;
+}
+
+/* Returns the first MEM found in NOTE by depth-first search.  */
+
+static rtx
+find_mem_in_note (note)
+     rtx note;
+{
+  if (note && for_each_rtx (&note, find_mem_in_note_1, &note))
+    return note;
+  return NULL_RTX;
+}
+  
 /* Replace MEM with its associated pseudo register.  This function is
    called from load_mems via for_each_rtx.  DATA is actually a pointer
    to a structure describing the instruction currently being scanned
@@ -9481,10 +10473,11 @@ replace_loop_mem (mem, data)
 }
 
 static void
-replace_loop_mems (insn, mem, reg)
+replace_loop_mems (insn, mem, reg, written)
      rtx insn;
      rtx mem;
      rtx reg;
+     int written;
 {
   loop_replace_args args;
 
@@ -9493,6 +10486,26 @@ replace_loop_mems (insn, mem, reg)
   args.replacement = reg;
 
   for_each_rtx (&insn, replace_loop_mem, &args);
+
+  /* If we hoist a mem write out of the loop, then REG_EQUAL
+     notes referring to the mem are no longer valid.  */
+  if (written)
+    {
+      rtx note, sub;
+      rtx *link;
+
+      for (link = &REG_NOTES (insn); (note = *link); link = &XEXP (note, 1))
+       {
+         if (REG_NOTE_KIND (note) == REG_EQUAL
+             && (sub = find_mem_in_note (note))
+             && true_dependence (mem, VOIDmode, sub, rtx_varies_p))
+           {
+             /* Remove the note.  */
+             validate_change (NULL_RTX, link, XEXP (note, 1), 1);
+             break;
+           }
+       }
+    }
 }
 
 /* Replace one register with another.  Called through for_each_rtx; PX points
@@ -9530,35 +10543,6 @@ replace_loop_regs (insn, reg, replacement)
 
   for_each_rtx (&insn, replace_loop_reg, &args);
 }
-
-/* Replace occurrences of the old exit label for the loop with the new
-   one.  DATA is an rtx_pair containing the old and new labels,
-   respectively.  */
-
-static int
-replace_label (x, data)
-     rtx *x;
-     void *data;
-{
-  rtx l = *x;
-  rtx old_label = ((rtx_pair *) data)->r1;
-  rtx new_label = ((rtx_pair *) data)->r2;
-
-  if (l == NULL_RTX)
-    return 0;
-
-  if (GET_CODE (l) != LABEL_REF)
-    return 0;
-
-  if (XEXP (l, 0) != old_label)
-    return 0;
-
-  XEXP (l, 0) = new_label;
-  ++LABEL_NUSES (new_label);
-  --LABEL_NUSES (old_label);
-
-  return 0;
-}
 \f
 /* Emit insn for PATTERN after WHERE_INSN in basic block WHERE_BB
    (ignored in the interim).  */
@@ -9574,7 +10558,7 @@ loop_insn_emit_after (loop, where_bb, where_insn, pattern)
 }
 
 
-/* If WHERE_INSN is non-zero emit insn for PATTERN before WHERE_INSN
+/* If WHERE_INSN is nonzero emit insn for PATTERN before WHERE_INSN
    in basic block WHERE_BB (ignored in the interim) within the loop
    otherwise hoist PATTERN into the loop pre-header.  */
 
@@ -9637,6 +10621,21 @@ loop_insn_sink (loop, pattern)
   return loop_insn_emit_before (loop, 0, loop->sink, pattern);
 }
 
+/* bl->final_value can be eighter general_operand or PLUS of general_operand
+   and constant.  Emit sequence of instructions to load it into REG.  */
+static rtx
+gen_load_of_final_value (reg, final_value)
+     rtx reg, final_value;
+{
+  rtx seq;
+  start_sequence ();
+  final_value = force_operand (final_value, reg);
+  if (final_value != reg)
+    emit_move_insn (reg, final_value);
+  seq = get_insns ();
+  end_sequence ();
+  return seq;
+}
 
 /* If the loop has multiple exits, emit insn for PATTERN before the
    loop to ensure that it will always be executed no matter how the
@@ -9736,9 +10735,9 @@ loop_iv_class_dump (bl, file, verbose)
       fprintf (file, " Giv%d: insn %d, benefit %d, ",
               i, INSN_UID (v->insn), v->benefit);
       if (v->giv_type == DEST_ADDR)
-         print_simple_rtl (file, v->mem);
+       print_simple_rtl (file, v->mem);
       else
-         print_simple_rtl (file, single_set (v->insn));
+       print_simple_rtl (file, single_set (v->insn));
       fputc ('\n', file);
     }
 }
@@ -9781,7 +10780,7 @@ loop_giv_dump (v, file, verbose)
 
   if (v->giv_type == DEST_REG)
     fprintf (file, "Giv %d: insn %d",
-            REGNO (v->dest_reg),  INSN_UID (v->insn));
+            REGNO (v->dest_reg), INSN_UID (v->insn));
   else
     fprintf (file, "Dest address: insn %d",
             INSN_UID (v->insn));
@@ -9797,9 +10796,9 @@ loop_giv_dump (v, file, verbose)
   if (v->no_const_addval)
     fprintf (file, " ncav");
 
-  if (v->ext_dependant)
+  if (v->ext_dependent)
     {
-      switch (GET_CODE (v->ext_dependant))
+      switch (GET_CODE (v->ext_dependent))
        {
        case SIGN_EXTEND:
          fprintf (file, " ext se");
@@ -9809,7 +10808,7 @@ loop_giv_dump (v, file, verbose)
          break;
        case TRUNCATE:
          fprintf (file, " ext tr");
-             break;
+         break;
        default:
          abort ();
        }