OSDN Git Service

2004-05-13 Benjamin Kosnik <bkoz@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / loop.c
index b0ce7cd..1b488fe 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, 2002 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -22,8 +22,16 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 /* This is the loop optimization pass of the compiler.
    It finds invariant computations within loops and moves them
    to the beginning of the loop.  Then it identifies basic and
-   general induction variables.  Strength reduction is applied to the general
-   induction variables, and induction variable elimination is applied to
+   general induction variables.
+
+   Basic induction variables (BIVs) are a pseudo registers which are set within
+   a loop only by incrementing or decrementing its value.  General induction
+   variables (GIVs) are pseudo registers with a value which is a linear function
+   of a basic induction variable.  BIVs are recognized by `basic_induction_var';
+   GIVs by `general_induction_var'.
+
+   Once induction variables are identified, strength reduction is applied to the
+   general induction variables, and induction variable elimination is applied to
    the basic induction variables.
 
    It also finds cases where
@@ -56,6 +64,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "predict.h"
 #include "insn-flags.h"
 #include "optabs.h"
+#include "cfgloop.h"
+#include "ggc.h"
 
 /* Not really meaningful values, but at least something.  */
 #ifndef SIMULTANEOUS_PREFETCHES
@@ -70,7 +80,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #define gen_prefetch(a,b,c) (abort(), NULL_RTX)
 #endif
 
-/* Give up the prefetch optimizations once we exceed a given threshhold.
+/* Give up the prefetch optimizations once we exceed a given threshold.
    It is unlikely that we would be able to optimize something in a loop
    with so many detected prefetches.  */
 #define MAX_PREFETCHES 100
@@ -82,7 +92,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #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 architecures.  These can be
+   easily for performance testing on new architectures.  These can be
    defined in target-dependent files.  */
 
 /* Prefetch is worthwhile only when loads/stores are dense.  */
@@ -153,7 +163,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #define LOOP_REGNO_NREGS(REGNO, SET_DEST) \
 ((REGNO) < FIRST_PSEUDO_REGISTER \
- ? (int) HARD_REGNO_NREGS ((REGNO), GET_MODE (SET_DEST)) : 1)
+ ? (int) hard_regno_nregs[(REGNO)][GET_MODE (SET_DEST)] : 1)
 
 
 /* Vector mapping INSN_UIDs to luids.
@@ -203,6 +213,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 */
@@ -219,9 +232,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;
@@ -232,138 +245,123 @@ 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 *));
-static int reg_in_basic_block_p PARAMS ((rtx, rtx));
-static int consec_sets_invariant_p PARAMS ((const struct loop *,
-                                           rtx, int, rtx));
-static int labels_in_range_p PARAMS ((rtx, int));
-static void count_one_set PARAMS ((struct loop_regs *, rtx, rtx, rtx *));
-static void note_addr_stored PARAMS ((rtx, rtx, void *));
-static void note_set_pseudo_multiple_uses PARAMS ((rtx, rtx, void *));
-static int loop_reg_used_before_p PARAMS ((const struct loop *, rtx, rtx));
-static void scan_loop PARAMS ((struct loop*, int));
+static void invalidate_loops_containing_label (rtx);
+static void find_and_verify_loops (rtx, struct loops *);
+static void mark_loop_jump (rtx, struct loop *);
+static void prescan_loop (struct loop *);
+static int reg_in_basic_block_p (rtx, rtx);
+static int consec_sets_invariant_p (const struct loop *, rtx, int, rtx);
+static int labels_in_range_p (rtx, int);
+static void count_one_set (struct loop_regs *, rtx, rtx, rtx *);
+static void note_addr_stored (rtx, rtx, void *);
+static void note_set_pseudo_multiple_uses (rtx, rtx, void *);
+static int loop_reg_used_before_p (const struct loop *, rtx, rtx);
+static rtx find_regs_nested (rtx, rtx);
+static void scan_loop (struct loop*, int);
 #if 0
-static void replace_call_address PARAMS ((rtx, rtx, rtx));
+static void replace_call_address (rtx, rtx, rtx);
 #endif
-static rtx skip_consec_insns PARAMS ((rtx, int));
-static int libcall_benefit PARAMS ((rtx));
-static void ignore_some_movables PARAMS ((struct loop_movables *));
-static void force_movables PARAMS ((struct loop_movables *));
-static void combine_movables PARAMS ((struct loop_movables *,
-                                     struct loop_regs *));
-static int num_unmoved_movables PARAMS ((const struct loop *));
-static int regs_match_p PARAMS ((rtx, rtx, struct loop_movables *));
-static int rtx_equal_for_loop_p PARAMS ((rtx, rtx, struct loop_movables *,
-                                        struct loop_regs *));
-static void add_label_notes PARAMS ((rtx, rtx));
-static void move_movables PARAMS ((struct loop *loop, struct loop_movables *,
-                                  int, int));
-static void loop_movables_add PARAMS((struct loop_movables *,
-                                     struct movable *));
-static void loop_movables_free PARAMS((struct loop_movables *));
-static int count_nonfixed_reads PARAMS ((const struct loop *, rtx));
-static void loop_bivs_find PARAMS((struct loop *));
-static void loop_bivs_init_find PARAMS((struct loop *));
-static void loop_bivs_check PARAMS((struct loop *));
-static void loop_givs_find PARAMS((struct loop *));
-static void loop_givs_check PARAMS((struct loop *));
-static int loop_biv_eliminable_p PARAMS((struct loop *, struct iv_class *,
-                                        int, int));
-static int loop_giv_reduce_benefit PARAMS((struct loop *, struct iv_class *,
-                                          struct induction *, rtx));
-static void loop_givs_dead_check PARAMS((struct loop *, struct iv_class *));
-static void loop_givs_reduce PARAMS((struct loop *, struct iv_class *));
-static void loop_givs_rescan PARAMS((struct loop *, struct iv_class *,
-                                    rtx *));
-static void loop_ivs_free PARAMS((struct loop *));
-static void strength_reduce PARAMS ((struct loop *, int));
-static void find_single_use_in_loop PARAMS ((struct loop_regs *, rtx, rtx));
-static int valid_initial_value_p PARAMS ((rtx, rtx, int, rtx));
-static void find_mem_givs PARAMS ((const struct loop *, rtx, rtx, int, int));
-static void record_biv PARAMS ((struct loop *, struct induction *,
-                               rtx, rtx, rtx, rtx, rtx *,
-                               int, int));
-static void check_final_value PARAMS ((const struct loop *,
-                                      struct induction *));
-static void loop_ivs_dump PARAMS((const struct loop *, FILE *, int));
-static void loop_iv_class_dump PARAMS((const struct iv_class *, FILE *, int));
-static void loop_biv_dump PARAMS((const struct induction *, FILE *, int));
-static void loop_giv_dump PARAMS((const struct induction *, FILE *, int));
-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_dependent_givs PARAMS ((struct iv_class *,
-                                             struct loop_info *));
-static int basic_induction_var PARAMS ((const struct loop *, rtx,
-                                       enum machine_mode, rtx, rtx,
-                                       rtx *, rtx *, rtx **));
-static rtx simplify_giv_expr PARAMS ((const struct loop *, rtx, rtx *, int *));
-static int general_induction_var PARAMS ((const struct loop *loop, rtx, rtx *,
-                                         rtx *, rtx *, rtx *, int, int *,
-                                         enum machine_mode));
-static int consec_sets_giv PARAMS ((const struct loop *, int, rtx,
-                                   rtx, rtx, rtx *, rtx *, rtx *, rtx *));
-static int check_dbra_loop PARAMS ((struct loop *, int));
-static rtx express_from_1 PARAMS ((rtx, rtx, rtx));
-static rtx combine_givs_p PARAMS ((struct induction *, struct induction *));
-static int cmp_combine_givs_stats PARAMS ((const PTR, const PTR));
-static void combine_givs PARAMS ((struct loop_regs *, struct iv_class *));
-static int product_cheap_p PARAMS ((rtx, rtx));
-static int maybe_eliminate_biv PARAMS ((const struct loop *, struct iv_class *,
-                                       int, int, int));
-static int maybe_eliminate_biv_1 PARAMS ((const struct loop *, rtx, rtx,
-                                         struct iv_class *, int,
-                                         basic_block, rtx));
-static int last_use_this_basic_block PARAMS ((rtx, rtx));
-static void record_initial PARAMS ((rtx, rtx, void *));
-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 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 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));
-static void loop_regs_update PARAMS ((const struct loop *, rtx));
-static int iv_add_mult_cost PARAMS ((rtx, rtx, rtx, rtx));
-
-static rtx loop_insn_emit_after PARAMS((const struct loop *, basic_block,
-                                       rtx, rtx));
-static rtx loop_call_insn_emit_before PARAMS((const struct loop *,
-                                             basic_block, rtx, rtx));
-static rtx loop_call_insn_hoist PARAMS((const struct loop *, rtx));
-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 *));
-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;
+static rtx skip_consec_insns (rtx, int);
+static int libcall_benefit (rtx);
+static rtx libcall_other_reg (rtx, rtx);
+static void record_excess_regs (rtx, rtx, rtx *);
+static void ignore_some_movables (struct loop_movables *);
+static void force_movables (struct loop_movables *);
+static void combine_movables (struct loop_movables *, struct loop_regs *);
+static int num_unmoved_movables (const struct loop *);
+static int regs_match_p (rtx, rtx, struct loop_movables *);
+static int rtx_equal_for_loop_p (rtx, rtx, struct loop_movables *,
+                                struct loop_regs *);
+static void add_label_notes (rtx, rtx);
+static void move_movables (struct loop *loop, struct loop_movables *, int,
+                          int);
+static void loop_movables_add (struct loop_movables *, struct movable *);
+static void loop_movables_free (struct loop_movables *);
+static int count_nonfixed_reads (const struct loop *, rtx);
+static void loop_bivs_find (struct loop *);
+static void loop_bivs_init_find (struct loop *);
+static void loop_bivs_check (struct loop *);
+static void loop_givs_find (struct loop *);
+static void loop_givs_check (struct loop *);
+static int loop_biv_eliminable_p (struct loop *, struct iv_class *, int, int);
+static int loop_giv_reduce_benefit (struct loop *, struct iv_class *,
+                                   struct induction *, rtx);
+static void loop_givs_dead_check (struct loop *, struct iv_class *);
+static void loop_givs_reduce (struct loop *, struct iv_class *);
+static void loop_givs_rescan (struct loop *, struct iv_class *, rtx *);
+static void loop_ivs_free (struct loop *);
+static void strength_reduce (struct loop *, int);
+static void find_single_use_in_loop (struct loop_regs *, rtx, rtx);
+static int valid_initial_value_p (rtx, rtx, int, rtx);
+static void find_mem_givs (const struct loop *, rtx, rtx, int, int);
+static void record_biv (struct loop *, struct induction *, rtx, rtx, rtx,
+                       rtx, rtx *, int, int);
+static void check_final_value (const struct loop *, struct induction *);
+static void loop_ivs_dump (const struct loop *, FILE *, int);
+static void loop_iv_class_dump (const struct iv_class *, FILE *, int);
+static void loop_biv_dump (const struct induction *, FILE *, int);
+static void loop_giv_dump (const struct induction *, FILE *, int);
+static void record_giv (const struct loop *, struct induction *, rtx, rtx,
+                       rtx, rtx, rtx, rtx, int, enum g_types, int, int,
+                       rtx *);
+static void update_giv_derive (const struct loop *, rtx);
+static void check_ext_dependent_givs (const struct loop *, struct iv_class *);
+static int basic_induction_var (const struct loop *, rtx, enum machine_mode,
+                               rtx, rtx, rtx *, rtx *, rtx **);
+static rtx simplify_giv_expr (const struct loop *, rtx, rtx *, int *);
+static int general_induction_var (const struct loop *loop, rtx, rtx *, rtx *,
+                                 rtx *, rtx *, int, int *, enum machine_mode);
+static int consec_sets_giv (const struct loop *, int, rtx, rtx, rtx, rtx *,
+                           rtx *, rtx *, rtx *);
+static int check_dbra_loop (struct loop *, int);
+static rtx express_from_1 (rtx, rtx, rtx);
+static rtx combine_givs_p (struct induction *, struct induction *);
+static int cmp_combine_givs_stats (const void *, const void *);
+static void combine_givs (struct loop_regs *, struct iv_class *);
+static int product_cheap_p (rtx, rtx);
+static int maybe_eliminate_biv (const struct loop *, struct iv_class *, int,
+                               int, int);
+static int maybe_eliminate_biv_1 (const struct loop *, rtx, rtx,
+                                 struct iv_class *, int, basic_block, rtx);
+static int last_use_this_basic_block (rtx, rtx);
+static void record_initial (rtx, rtx, void *);
+static void update_reg_last_use (rtx, rtx);
+static rtx next_insn_in_loop (const struct loop *, rtx);
+static void loop_regs_scan (const struct loop *, int);
+static int count_insns_in_loop (const struct loop *);
+static int find_mem_in_note_1 (rtx *, void *);
+static rtx find_mem_in_note (rtx);
+static void load_mems (const struct loop *);
+static int insert_loop_mem (rtx *, void *);
+static int replace_loop_mem (rtx *, void *);
+static void replace_loop_mems (rtx, rtx, rtx, int);
+static int replace_loop_reg (rtx *, void *);
+static void replace_loop_regs (rtx insn, rtx, rtx);
+static void note_reg_stored (rtx, rtx, void *);
+static void try_copy_prop (const struct loop *, rtx, unsigned int);
+static void try_swap_copy_prop (const struct loop *, rtx, unsigned int);
+static rtx check_insn_for_givs (struct loop *, rtx, int, int);
+static rtx check_insn_for_bivs (struct loop *, rtx, int, int);
+static rtx gen_add_mult (rtx, rtx, rtx, rtx);
+static void loop_regs_update (const struct loop *, rtx);
+static int iv_add_mult_cost (rtx, rtx, rtx, rtx);
+
+static rtx loop_insn_emit_after (const struct loop *, basic_block, rtx, rtx);
+static rtx loop_call_insn_emit_before (const struct loop *, basic_block,
+                                      rtx, rtx);
+static rtx loop_call_insn_hoist (const struct loop *, rtx);
+static rtx loop_insn_sink_or_swim (const struct loop *, rtx);
+
+static void loop_dump_aux (const struct loop *, FILE *, int);
+static void loop_delete_insns (rtx, rtx);
+static HOST_WIDE_INT remove_constant_addition (rtx *);
+static rtx gen_load_of_final_value (rtx, rtx);
+void debug_ivs (const struct loop *);
+void debug_iv_class (const struct iv_class *);
+void debug_biv (const struct induction *);
+void debug_giv (const struct induction *);
+void debug_loop (const struct loop *);
+void debug_loops (const struct loops *);
 
 typedef struct loop_replace_args
 {
@@ -380,13 +378,12 @@ typedef struct loop_replace_args
 
 /* Indirect_jump_in_function is computed once per function.  */
 static int indirect_jump_in_function;
-static int indirect_jump_in_function_p PARAMS ((rtx));
+static int indirect_jump_in_function_p (rtx);
 
-static int compute_luids PARAMS ((rtx, rtx, int));
+static int compute_luids (rtx, rtx, int);
 
-static int biv_elimination_giv_has_0_offset PARAMS ((struct induction *,
-                                                    struct induction *,
-                                                    rtx));
+static int biv_elimination_giv_has_0_offset (struct induction *,
+                                            struct induction *, rtx);
 \f
 /* Benefit penalty, if a giv is not replaceable, i.e. must emit an insn to
    copy the value of the strength reduced giv to its original register.  */
@@ -396,7 +393,7 @@ static int copy_cost;
 static int reg_address_cost;
 
 void
-init_loop ()
+init_loop (void)
 {
   rtx reg = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
 
@@ -411,9 +408,7 @@ init_loop ()
    Start at insn START and stop just before END.  Assign LUIDs
    starting with PREV_LUID + 1.  Return the last assigned LUID + 1.  */
 static int
-compute_luids (start, end, prev_luid)
-     rtx start, end;
-     int prev_luid;
+compute_luids (rtx start, rtx end, int prev_luid)
 {
   int i;
   rtx insn;
@@ -440,11 +435,7 @@ compute_luids (start, end, prev_luid)
    (or 0 if none should be output).  */
 
 void
-loop_optimize (f, dumpfile, flags)
-     /* f is the first instruction of a chain of insns for one function */
-     rtx f;
-     FILE *dumpfile;
-     int flags;
+loop_optimize (rtx f, FILE *dumpfile, int flags)
 {
   rtx insn;
   int i;
@@ -481,13 +472,11 @@ loop_optimize (f, dumpfile, flags)
      Leave some space for labels allocated by find_and_verify_loops.  */
   max_uid_for_loop = get_max_uid () + 1 + max_loop_num * 32;
 
-  uid_luid = (int *) xcalloc (max_uid_for_loop, sizeof (int));
-  uid_loop = (struct loop **) xcalloc (max_uid_for_loop,
-                                      sizeof (struct loop *));
+  uid_luid = xcalloc (max_uid_for_loop, sizeof (int));
+  uid_loop = xcalloc (max_uid_for_loop, sizeof (struct loop *));
 
   /* Allocate storage for array of loops.  */
-  loops->array = (struct loop *)
-    xcalloc (loops->num, sizeof (struct loop));
+  loops->array = xcalloc (loops->num, sizeof (struct loop));
 
   /* Find and process each loop.
      First, find them, and record them in order of their beginnings.  */
@@ -495,7 +484,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
@@ -548,12 +537,18 @@ loop_optimize (f, dumpfile, flags)
       struct loop *loop = &loops->array[i];
 
       if (! loop->invalid && loop->end)
-       scan_loop (loop, flags);
+       {
+         scan_loop (loop, flags);
+         ggc_collect ();
+       }
     }
 
   end_alias_analysis ();
 
   /* Clean up.  */
+  for (i = 0; i < (int) loops->num; i++)
+    free (loops_info[i].mems);
+  
   free (uid_luid);
   free (uid_loop);
   free (loops_info);
@@ -567,9 +562,7 @@ loop_optimize (f, dumpfile, flags)
    bottom.  */
 
 static rtx
-next_insn_in_loop (loop, insn)
-     const struct loop *loop;
-     rtx insn;
+next_insn_in_loop (const struct loop *loop, rtx insn)
 {
   insn = NEXT_INSN (insn);
 
@@ -590,6 +583,32 @@ next_insn_in_loop (loop, insn)
   return insn;
 }
 
+/* Find any register references hidden inside X and add them to
+   the dependency list DEPS.  This is used to look inside CLOBBER (MEM
+   when checking whether a PARALLEL can be pulled out of a loop.  */
+
+static rtx
+find_regs_nested (rtx deps, rtx x)
+{
+  enum rtx_code code = GET_CODE (x);
+  if (code == REG)
+    deps = gen_rtx_EXPR_LIST (VOIDmode, x, deps);
+  else
+    {
+      const char *fmt = GET_RTX_FORMAT (code);
+      int i, j;
+      for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+       {
+         if (fmt[i] == 'e')
+           deps = find_regs_nested (deps, XEXP (x, i));
+         else if (fmt[i] == 'E')
+           for (j = 0; j < XVECLEN (x, i); j++)
+             deps = find_regs_nested (deps, XVECEXP (x, i, j));
+       }
+    }
+  return deps;
+}
+
 /* Optimize one loop described by LOOP.  */
 
 /* ??? Could also move memory writes out of loops if the destination address
@@ -599,9 +618,7 @@ next_insn_in_loop (loop, insn)
    write, then we can also mark the memory read as invariant.  */
 
 static void
-scan_loop (loop, flags)
-     struct loop *loop;
-     int flags;
+scan_loop (struct loop *loop, int flags)
 {
   struct loop_info *loop_info = LOOP_INFO (loop);
   struct loop_regs *regs = LOOP_REGS (loop);
@@ -764,6 +781,7 @@ scan_loop (loop, flags)
              int tem1 = 0;
              int tem2 = 0;
              int move_insn = 0;
+             int insert_temp = 0;
              rtx src = SET_SRC (set);
              rtx dependencies = 0;
 
@@ -793,8 +811,10 @@ scan_loop (loop, flags)
                    }
                }
 
-             /* For parallels, add any possible uses to the depencies, as
-                we can't move the insn without resolving them first.  */
+             /* For parallels, add any possible uses to the dependencies, as
+                we can't move the insn without resolving them first.
+                MEMs inside CLOBBERs may also reference registers; these
+                count as implicit uses.  */
              if (GET_CODE (PATTERN (p)) == PARALLEL)
                {
                  for (i = 0; i < XVECLEN (PATTERN (p), 0); i++)
@@ -804,37 +824,62 @@ scan_loop (loop, flags)
                        dependencies
                          = gen_rtx_EXPR_LIST (VOIDmode, XEXP (x, 0),
                                               dependencies);
+                     else if (GET_CODE (x) == CLOBBER 
+                              && GET_CODE (XEXP (x, 0)) == MEM)
+                       dependencies = find_regs_nested (dependencies, 
+                                                 XEXP (XEXP (x, 0), 0));
                    }
                }
 
-             /* 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
-                         than the one where it is set (meaning that
-                         something after this point in the loop might
-                         depend on its value before the set).  */
-                      ! reg_in_basic_block_p (p, SET_DEST (set))
-                      /* And the set is not guaranteed to be executed once
-                         the loop starts, or the value before the set is
-                         needed before the set occurs...
-
-                         ??? 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.
+             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).  */
+                  ! reg_in_basic_block_p (p, SET_DEST (set))
+                  /* And the set is not guaranteed to be executed once
+                     the loop starts, or the value before the set is
+                     needed before the set occurs...
+
+                     ??? 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.  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 MODE_CC set with a constant
+                source.  It probably will be combined with a conditional
+                jump.  */
+             if (GET_MODE_CLASS (GET_MODE (SET_DEST (set))) == MODE_CC
+                 && CONSTANT_P (src))
+               ;
+             /* 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.  */
+             else 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
@@ -911,7 +956,7 @@ scan_loop (loop, flags)
                      continue;
                    }
 
-                 m = (struct movable *) xmalloc (sizeof (struct movable));
+                 m = xmalloc (sizeof (struct movable));
                  m->next = 0;
                  m->insn = p;
                  m->set_src = src;
@@ -925,6 +970,7 @@ scan_loop (loop, flags)
                  m->partial = 0;
                  m->move_insn = move_insn;
                  m->move_insn_first = 0;
+                 m->insert_temp = insert_temp;
                  m->is_equiv = (find_reg_note (p, REG_EQUIV, NULL_RTX) != 0);
                  m->savemode = VOIDmode;
                  m->regno = regno;
@@ -998,7 +1044,7 @@ scan_loop (loop, flags)
                  if (regs->array[regno].set_in_loop == 2)
                    {
                      struct movable *m;
-                     m = (struct movable *) xmalloc (sizeof (struct movable));
+                     m = xmalloc (sizeof (struct movable));
                      m->next = 0;
                      m->insn = p;
                      m->set_dest = SET_DEST (set);
@@ -1009,6 +1055,7 @@ scan_loop (loop, flags)
                      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.
@@ -1107,10 +1154,12 @@ 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)
+  if (!optimize_size
+      || (reg_class_size[GENERAL_REGS] > 18 && !loop_info->has_call))
     {
       move_movables (loop, movables, threshold, insn_count);
 
@@ -1184,10 +1233,8 @@ scan_loop (loop, flags)
 /* Add elements to *OUTPUT to record all the pseudo-regs
    mentioned in IN_THIS but not mentioned in NOT_IN_THIS.  */
 
-void
-record_excess_regs (in_this, not_in_this, output)
-     rtx in_this, not_in_this;
-     rtx *output;
+static void
+record_excess_regs (rtx in_this, rtx not_in_this, rtx *output)
 {
   enum rtx_code code;
   const char *fmt;
@@ -1240,9 +1287,8 @@ record_excess_regs (in_this, not_in_this, output)
    If there are none, return 0.
    If there are one or more, return an EXPR_LIST containing all of them.  */
 
-rtx
-libcall_other_reg (insn, equiv)
-     rtx insn, equiv;
+static rtx
+libcall_other_reg (rtx insn, rtx equiv)
 {
   rtx note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
   rtx p = XEXP (note, 0);
@@ -1266,8 +1312,7 @@ libcall_other_reg (insn, equiv)
    are between INSN and the end of the basic block.  */
 
 static int
-reg_in_basic_block_p (insn, reg)
-     rtx insn, reg;
+reg_in_basic_block_p (rtx insn, rtx reg)
 {
   int regno = REGNO (reg);
   rtx p;
@@ -1320,8 +1365,7 @@ reg_in_basic_block_p (insn, reg)
    value directly or can contain a library call.  */
 
 static int
-libcall_benefit (last)
-     rtx last;
+libcall_benefit (rtx last)
 {
   rtx insn;
   int benefit = 0;
@@ -1344,9 +1388,7 @@ libcall_benefit (last)
 /* Skip COUNT insns from INSN, counting library calls as 1 insn.  */
 
 static rtx
-skip_consec_insns (insn, count)
-     rtx insn;
-     int count;
+skip_consec_insns (rtx insn, int count)
 {
   for (; count > 0; count--)
     {
@@ -1373,8 +1415,7 @@ skip_consec_insns (insn, count)
    was made later and so appears later on the chain.  */
 
 static void
-ignore_some_movables (movables)
-     struct loop_movables *movables;
+ignore_some_movables (struct loop_movables *movables)
 {
   struct movable *m, *m1;
 
@@ -1405,8 +1446,7 @@ ignore_some_movables (movables)
    since the second can be moved only if the first is.  */
 
 static void
-force_movables (movables)
-     struct loop_movables *movables;
+force_movables (struct loop_movables *movables)
 {
   struct movable *m, *m1;
 
@@ -1431,12 +1471,18 @@ force_movables (movables)
          m = 0;
 
        /* Increase the priority of the moving the first insn
-          since it permits the second to be moved as well.  */
+          since it permits the second to be moved as well.
+          Likewise for insns already forced by the first insn.  */
        if (m != 0)
          {
+           struct movable *m2;
+
            m->forces = m1;
-           m1->lifetime += m->lifetime;
-           m1->savings += m->savings;
+           for (m2 = m1; m2; m2 = m2->forces)
+             {
+               m2->lifetime += m->lifetime;
+               m2->savings += m->savings;
+             }
          }
       }
 }
@@ -1445,12 +1491,10 @@ force_movables (movables)
    one register.  */
 
 static void
-combine_movables (movables, regs)
-     struct loop_movables *movables;
-     struct loop_regs *regs;
+combine_movables (struct loop_movables *movables, struct loop_regs *regs)
 {
   struct movable *m;
-  char *matched_regs = (char *) xmalloc (regs->num);
+  char *matched_regs = xmalloc (regs->num);
   enum machine_mode mode;
 
   /* Regs that are set more than once are not allowed to match
@@ -1462,6 +1506,7 @@ combine_movables (movables, regs)
   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;
@@ -1474,6 +1519,7 @@ 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.  */
@@ -1570,8 +1616,7 @@ combine_movables (movables, regs)
    moved outside the loop.  */
 
 static int
-num_unmoved_movables (loop)
-     const struct loop *loop;
+num_unmoved_movables (const struct loop *loop)
 {
   int num = 0;
   struct movable *m;
@@ -1587,9 +1632,7 @@ num_unmoved_movables (loop)
 /* Return 1 if regs X and Y will become the same if moved.  */
 
 static int
-regs_match_p (x, y, movables)
-     rtx x, y;
-     struct loop_movables *movables;
+regs_match_p (rtx x, rtx y, struct loop_movables *movables)
 {
   unsigned int xn = REGNO (x);
   unsigned int yn = REGNO (y);
@@ -1616,10 +1659,8 @@ regs_match_p (x, y, movables)
    equivalent constant, consider them equal.  */
 
 static int
-rtx_equal_for_loop_p (x, y, movables, regs)
-     rtx x, y;
-     struct loop_movables *movables;
-     struct loop_regs *regs;
+rtx_equal_for_loop_p (rtx x, rtx y, struct loop_movables *movables,
+                     struct loop_regs *regs)
 {
   int i;
   int j;
@@ -1735,9 +1776,7 @@ rtx_equal_for_loop_p (x, y, movables, regs)
    references is incremented once for each added note.  */
 
 static void
-add_label_notes (x, insns)
-     rtx x;
-     rtx insns;
+add_label_notes (rtx x, rtx insns)
 {
   enum rtx_code code = GET_CODE (x);
   int i, j;
@@ -1747,7 +1786,7 @@ add_label_notes (x, insns)
   if (code == LABEL_REF && !LABEL_REF_NONLOCAL_P (x))
     {
       /* This code used to ignore labels that referred to dispatch tables to
-         avoid flow generating (slighly) worse code.
+         avoid flow generating (slightly) worse code.
 
          We no longer ignore such label references (see LABEL_REF handling in
          mark_jump_label for additional information).  */
@@ -1777,11 +1816,8 @@ add_label_notes (x, insns)
    other throughout.  */
 
 static void
-move_movables (loop, movables, threshold, insn_count)
-     struct loop *loop;
-     struct loop_movables *movables;
-     int threshold;
-     int insn_count;
+move_movables (struct loop *loop, struct loop_movables *movables,
+              int threshold, int insn_count)
 {
   struct loop_regs *regs = LOOP_REGS (loop);
   int nregs = regs->num;
@@ -1793,8 +1829,8 @@ move_movables (loop, movables, threshold, insn_count)
   /* Map of pseudo-register replacements to handle combining
      when we move several insns that load the same value
      into different pseudo-registers.  */
-  rtx *reg_map = (rtx *) xcalloc (nregs, sizeof (rtx));
-  char *already_moved = (char *) xcalloc (nregs, sizeof (char));
+  rtx *reg_map = xcalloc (nregs, sizeof (rtx));
+  char *already_moved = xcalloc (nregs, sizeof (char));
 
   for (m = movables->head; m; m = m->next)
     {
@@ -1877,6 +1913,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.  */
 
@@ -1947,10 +1987,22 @@ 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);
+                 emit_move_insn (m->insert_temp ? newreg : m->set_dest,
+                                 m->set_src);
                  seq = get_insns ();
                  end_sequence ();
 
@@ -2109,7 +2161,8 @@ move_movables (loop, movables, threshold, insn_count)
                          /* The SET_SRC might not be invariant, so we must
                             use the REG_EQUAL note.  */
                          start_sequence ();
-                         emit_move_insn (m->set_dest, m->set_src);
+                         emit_move_insn (m->insert_temp ? newreg : m->set_dest,
+                                         m->set_src);
                          seq = get_insns ();
                          end_sequence ();
 
@@ -2120,6 +2173,16 @@ move_movables (loop, movables, threshold, insn_count)
                            set_unique_reg_note (i1, m->is_equiv ? REG_EQUIV
                                                     : REG_EQUAL, m->set_src);
                        }
+                     else if (m->insert_temp)
+                       {
+                         rtx *reg_map2 = 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));
 
@@ -2168,40 +2231,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)
+             if (!m->insert_temp)
                {
-                 int i;
-                 for (i = 0; i < LOOP_REGNO_NREGS (regno, m->set_dest); i++)
-                   regs->array[regno+i].set_in_loop = 0;
-               }
+                 /* 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.  */
 
@@ -2233,7 +2311,7 @@ move_movables (loop, movables, threshold, insn_count)
                         and prevent further processing of it.  */
                      m1->done = 1;
 
-                     /* if library call, delete all insns.  */
+                     /* If library call, delete all insns.  */
                      if ((temp = find_reg_note (m1->insn, REG_RETVAL,
                                                 NULL_RTX)))
                        delete_insn_chain (XEXP (temp, 0), m1->insn);
@@ -2287,9 +2365,7 @@ move_movables (loop, movables, threshold, insn_count)
 
 
 static void
-loop_movables_add (movables, m)
-     struct loop_movables *movables;
-     struct movable *m;
+loop_movables_add (struct loop_movables *movables, struct movable *m)
 {
   if (movables->head == 0)
     movables->head = m;
@@ -2300,8 +2376,7 @@ loop_movables_add (movables, m)
 
 
 static void
-loop_movables_free (movables)
-     struct loop_movables *movables;
+loop_movables_free (struct loop_movables *movables)
 {
   struct movable *m;
   struct movable *m_next;
@@ -2318,8 +2393,7 @@ loop_movables_free (movables)
    REG is the address that MEM should have before the replacement.  */
 
 static void
-replace_call_address (x, reg, addr)
-     rtx x, reg, addr;
+replace_call_address (rtx x, rtx reg, rtx addr)
 {
   enum rtx_code code;
   int i;
@@ -2381,9 +2455,7 @@ replace_call_address (x, reg, addr)
    in the rtx X.  */
 
 static int
-count_nonfixed_reads (loop, x)
-     const struct loop *loop;
-     rtx x;
+count_nonfixed_reads (const struct loop *loop, rtx x)
 {
   enum rtx_code code;
   int i;
@@ -2437,8 +2509,7 @@ count_nonfixed_reads (loop, x)
    list `store_mems' in LOOP.  */
 
 static void
-prescan_loop (loop)
-     struct loop *loop;
+prescan_loop (struct loop *loop)
 {
   int level = 1;
   rtx insn;
@@ -2507,6 +2578,30 @@ prescan_loop (loop)
          loop_info->has_call = 1;
          if (can_throw_internal (insn))
            loop_info->has_multiple_exit_targets = 1;
+
+         /* Calls initializing constant objects have CLOBBER of MEM /u in the
+            attached FUNCTION_USAGE expression list, not accounted for by the
+            code above. We should note these to avoid missing dependencies in
+            later references.  */
+         {
+           rtx fusage_entry;
+
+           for (fusage_entry = CALL_INSN_FUNCTION_USAGE (insn);
+                fusage_entry; fusage_entry = XEXP (fusage_entry, 1))
+             {
+               rtx fusage = XEXP (fusage_entry, 0);
+
+               if (GET_CODE (fusage) == CLOBBER
+                   && GET_CODE (XEXP (fusage, 0)) == MEM
+                   && RTX_UNCHANGING_P (XEXP (fusage, 0)))
+                 {
+                   note_stores (fusage, note_addr_stored, loop_info);
+                   if (! loop_info->first_loop_store_insn
+                       && loop_info->store_mems)
+                     loop_info->first_loop_store_insn = insn;
+                 }
+             }
+         }
          break;
 
        case JUMP_INSN:
@@ -2560,7 +2655,7 @@ prescan_loop (loop)
                  loop_info->has_multiple_exit_targets = 1;
                }
            }
-         /* FALLTHRU */
+         /* Fall through.  */
 
        case INSN:
          if (volatile_refs_p (PATTERN (insn)))
@@ -2623,8 +2718,7 @@ prescan_loop (loop)
 /* Invalidate all loops containing LABEL.  */
 
 static void
-invalidate_loops_containing_label (label)
-     rtx label;
+invalidate_loops_containing_label (rtx label)
 {
   struct loop *loop;
   for (loop = uid_loop[INSN_UID (label)]; loop; loop = loop->outer)
@@ -2636,9 +2730,7 @@ invalidate_loops_containing_label (label)
    to from outside the loop.  */
 
 static void
-find_and_verify_loops (f, loops)
-     rtx f;
-     struct loops *loops;
+find_and_verify_loops (rtx f, struct loops *loops)
 {
   rtx insn;
   rtx label;
@@ -2974,9 +3066,7 @@ find_and_verify_loops (f, loops)
    For speed, we assume that X is part of a pattern of a JUMP_INSN.  */
 
 static void
-mark_loop_jump (x, loop)
-     rtx x;
-     struct loop *loop;
+mark_loop_jump (rtx x, struct loop *loop)
 {
   struct loop *dest_loop;
   struct loop *outer_loop;
@@ -3122,9 +3212,7 @@ mark_loop_jump (x, loop)
    been previously created by loop.c).  */
 
 static int
-labels_in_range_p (insn, end)
-     rtx insn;
-     int end;
+labels_in_range_p (rtx insn, int end)
 {
   while (insn && INSN_LUID (insn) <= end)
     {
@@ -3139,10 +3227,8 @@ labels_in_range_p (insn, end)
 /* Record that a memory reference X is being set.  */
 
 static void
-note_addr_stored (x, y, data)
-     rtx x;
-     rtx y ATTRIBUTE_UNUSED;
-     void *data ATTRIBUTE_UNUSED;
+note_addr_stored (rtx x, rtx y ATTRIBUTE_UNUSED,
+                 void *data ATTRIBUTE_UNUSED)
 {
   struct loop_info *loop_info = data;
 
@@ -3174,10 +3260,7 @@ note_addr_stored (x, y, data)
    used more than once.  DATA is a pointer to a loop_regs structure.  */
 
 static void
-note_set_pseudo_multiple_uses (x, y, data)
-     rtx x;
-     rtx y ATTRIBUTE_UNUSED;
-     void *data;
+note_set_pseudo_multiple_uses (rtx x, rtx y ATTRIBUTE_UNUSED, void *data)
 {
   struct loop_regs *regs = (struct loop_regs *) data;
 
@@ -3209,9 +3292,7 @@ note_set_pseudo_multiple_uses (x, y, data)
    with anything stored in `loop_info->store_mems'.  */
 
 int
-loop_invariant_p (loop, x)
-     const struct loop *loop;
-     rtx x;
+loop_invariant_p (const struct loop *loop, rtx x)
 {
   struct loop_info *loop_info = LOOP_INFO (loop);
   struct loop_regs *regs = LOOP_REGS (loop);
@@ -3242,7 +3323,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;
@@ -3266,10 +3347,16 @@ loop_invariant_p (loop, 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) >= regs->num)
+        These registers created by the unroller are set in the loop,
+        hence are never invariant.
+        Other out-of-range regs can be generated by load_mems; those that
+        are written to in the loop are not invariant, while those that are
+        not written to are invariant.  It would be easy for load_mems
+        to set n_times_set correctly for these registers, however, there
+        is no easy way to distinguish them from registers created by the
+        unroller.  */
+
+      if (REGNO (x) >= (unsigned) regs->num)
        return 0;
 
       if (regs->array[REGNO (x)].set_in_loop < 0)
@@ -3349,10 +3436,8 @@ loop_invariant_p (loop, x)
    and that its source is invariant.  */
 
 static int
-consec_sets_invariant_p (loop, reg, n_sets, insn)
-     const struct loop *loop;
-     int n_sets;
-     rtx reg, insn;
+consec_sets_invariant_p (const struct loop *loop, rtx reg, int n_sets,
+                        rtx insn)
 {
   struct loop_regs *regs = LOOP_REGS (loop);
   rtx p = insn;
@@ -3416,49 +3501,13 @@ consec_sets_invariant_p (loop, reg, n_sets, insn)
   /* If loop_invariant_p ever returned 2, we return 2.  */
   return 1 + (value & 2);
 }
-
-#if 0
-/* I don't think this condition is sufficient to allow INSN
-   to be moved, so we no longer test it.  */
-
-/* Return 1 if all insns in the basic block of INSN and following INSN
-   that set REG are invariant according to TABLE.  */
-
-static int
-all_sets_invariant_p (reg, insn, table)
-     rtx reg, insn;
-     short *table;
-{
-  rtx p = insn;
-  int regno = REGNO (reg);
-
-  while (1)
-    {
-      enum rtx_code code;
-      p = NEXT_INSN (p);
-      code = GET_CODE (p);
-      if (code == CODE_LABEL || code == JUMP_INSN)
-       return 1;
-      if (code == INSN && GET_CODE (PATTERN (p)) == SET
-         && GET_CODE (SET_DEST (PATTERN (p))) == REG
-         && REGNO (SET_DEST (PATTERN (p))) == regno)
-       {
-         if (! loop_invariant_p (loop, SET_SRC (PATTERN (p)), 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.  */
 
 static void
-find_single_use_in_loop (regs, insn, x)
-     struct loop_regs *regs;
-     rtx insn;
-     rtx x;
+find_single_use_in_loop (struct loop_regs *regs, rtx insn, rtx x)
 {
   enum rtx_code code = GET_CODE (x);
   const char *fmt = GET_RTX_FORMAT (code);
@@ -3496,10 +3545,7 @@ find_single_use_in_loop (regs, insn, x)
    in X.  */
 
 static void
-count_one_set (regs, insn, x, last_set)
-     struct loop_regs *regs;
-     rtx insn, x;
-     rtx *last_set;
+count_one_set (struct loop_regs *regs, rtx insn, rtx 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.
@@ -3525,7 +3571,7 @@ count_one_set (regs, insn, x, last_set)
                 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)
+                 && last_set[regno] == 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.
@@ -3551,9 +3597,7 @@ count_one_set (regs, insn, x, last_set)
    from an inner loop past two loops.  */
 
 static int
-loop_reg_used_before_p (loop, set, insn)
-     const struct loop *loop;
-     rtx set, insn;
+loop_reg_used_before_p (const struct loop *loop, rtx set, rtx insn)
 {
   rtx reg = SET_DEST (set);
   rtx p;
@@ -3601,16 +3645,14 @@ struct check_store_data
   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));
+static void check_store (rtx, rtx, void *);
+static void emit_prefetch_instructions (struct loop *);
+static int rtx_equal_for_prefetch_p (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;
+check_store (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
 {
   struct check_store_data *d = (struct check_store_data *) data;
 
@@ -3620,14 +3662,13 @@ check_store (x, pat, data)
 \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 necesary.
+   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;
+rtx_equal_for_prefetch_p (rtx x, rtx y)
 {
   int i;
   int j;
@@ -3639,15 +3680,14 @@ rtx_equal_for_prefetch_p (x, y)
   if (code != GET_CODE (y))
     return 0;
 
-  code = GET_CODE (x);
-
-  if (GET_RTX_CLASS (code) == 'c')
+  if (COMMUTATIVE_ARITH_P (x))
     {
       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.  */
 
@@ -3709,8 +3749,7 @@ rtx_equal_for_prefetch_p (x, y)
    and return it.  */
 
 static HOST_WIDE_INT
-remove_constant_addition (x)
-     rtx *x;
+remove_constant_addition (rtx *x)
 {
   HOST_WIDE_INT addval = 0;
   rtx exp = *x;
@@ -3772,8 +3811,7 @@ remove_constant_addition (x)
    controlled by defined symbols that can be overridden for each target.  */
 
 static void
-emit_prefetch_instructions (loop)
-     struct loop *loop;
+emit_prefetch_instructions (struct loop *loop)
 {
   int num_prefetches = 0;
   int num_real_prefetches = 0;
@@ -4105,11 +4143,9 @@ emit_prefetch_instructions (loop)
                   " 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: ");
+         fprintf (loop_dump_stream, " index: " HOST_WIDE_INT_PRINT_DEC
+                  "; stride: " HOST_WIDE_INT_PRINT_DEC "; address: ",
+                  info[i].index, info[i].stride);
          print_rtl (loop_dump_stream, info[i].base_address);
          fprintf (loop_dump_stream, "\n");
        }
@@ -4150,8 +4186,8 @@ emit_prefetch_instructions (loop)
            {
              rtx reg = gen_reg_rtx (Pmode);
              loop_iv_add_mult_emit_before (loop, loc, const1_rtx,
-                                           GEN_INT (bytes_ahead), reg,
-                                           0, before_insn);
+                                           GEN_INT (bytes_ahead), reg,
+                                           0, before_insn);
              loc = reg;
            }
 
@@ -4196,7 +4232,15 @@ emit_prefetch_instructions (loop)
                 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))
-               init_val = convert_to_mode (Pmode, init_val, 0);
+               {
+                 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);
@@ -4210,14 +4254,6 @@ emit_prefetch_instructions (loop)
   return;
 }
 \f
-/* A "basic induction variable" or biv is a pseudo reg that is set
-   (within this loop) only by incrementing or decrementing it.  */
-/* A "general induction variable" or giv is a pseudo reg whose
-   value is a linear function of a biv.  */
-
-/* Bivs are recognized by `basic_induction_var';
-   Givs by `general_induction_var'.  */
-
 /* Communication with routines called via `note_stores'.  */
 
 static rtx note_insn;
@@ -4264,9 +4300,7 @@ static rtx addr_placeholder;
    loop iteration.
  */
 void
-for_each_insn_in_loop (loop, fncall)
-     struct loop *loop;
-     loop_insn_callback fncall;
+for_each_insn_in_loop (struct loop *loop, loop_insn_callback fncall)
 {
   int not_every_iteration = 0;
   int maybe_multiple = 0;
@@ -4404,8 +4438,7 @@ for_each_insn_in_loop (loop, fncall)
 }
 \f
 static void
-loop_bivs_find (loop)
-     struct loop *loop;
+loop_bivs_find (struct loop *loop)
 {
   struct loop_regs *regs = LOOP_REGS (loop);
   struct loop_ivs *ivs = LOOP_IVS (loop);
@@ -4453,8 +4486,7 @@ loop_bivs_find (loop)
 /* Determine how BIVS are initialized by looking through pre-header
    extended basic block.  */
 static void
-loop_bivs_init_find (loop)
-     struct loop *loop;
+loop_bivs_init_find (struct loop *loop)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   /* Temporary list pointers for traversing ivs->list.  */
@@ -4509,8 +4541,7 @@ loop_bivs_init_find (loop)
    initial value from any initializing insns set up above.  (This is done
    in two passes to avoid missing SETs in a PARALLEL.)  */
 static void
-loop_bivs_check (loop)
-     struct loop *loop;
+loop_bivs_check (struct loop *loop)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   /* Temporary list pointers for traversing ivs->list.  */
@@ -4565,8 +4596,7 @@ loop_bivs_check (loop)
 /* Search the loop for general induction variables.  */
 
 static void
-loop_givs_find (loop)
-     struct loop* loop;
+loop_givs_find (struct loop* loop)
 {
   for_each_insn_in_loop (loop, check_insn_for_givs);
 }
@@ -4577,8 +4607,7 @@ loop_givs_find (loop)
    can be calculated.  */
 
 static void
-loop_givs_check (loop)
-     struct loop *loop;
+loop_givs_check (struct loop *loop)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   struct iv_class *bl;
@@ -4600,11 +4629,8 @@ loop_givs_check (loop)
    be.  */
 
 static int
-loop_biv_eliminable_p (loop, bl, threshold, insn_count)
-     struct loop *loop;
-     struct iv_class *bl;
-     int threshold;
-     int insn_count;
+loop_biv_eliminable_p (struct loop *loop, struct iv_class *bl,
+                      int threshold, int insn_count)
 {
   /* For architectures with a decrement_and_branch_until_zero insn,
      don't do this if we put a REG_NONNEG note on the endtest for this
@@ -4652,9 +4678,7 @@ loop_biv_eliminable_p (loop, bl, threshold, insn_count)
 /* Reduce each giv of BL that we have decided to reduce.  */
 
 static void
-loop_givs_reduce (loop, bl)
-     struct loop *loop;
-     struct iv_class *bl;
+loop_givs_reduce (struct loop *loop, struct iv_class *bl)
 {
   struct induction *v;
 
@@ -4753,6 +4777,9 @@ 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 = NEXT_INSN (tv->insn);
              else if (auto_inc_opt == 1)
@@ -4788,9 +4815,7 @@ loop_givs_reduce (loop, bl)
    eliminate a biv.  */
 
 static void
-loop_givs_dead_check (loop, bl)
-     struct loop *loop ATTRIBUTE_UNUSED;
-     struct iv_class *bl;
+loop_givs_dead_check (struct loop *loop ATTRIBUTE_UNUSED, struct iv_class *bl)
 {
   struct induction *v;
 
@@ -4814,10 +4839,7 @@ loop_givs_dead_check (loop, bl)
 
 
 static void
-loop_givs_rescan (loop, bl, reg_map)
-     struct loop *loop;
-     struct iv_class *bl;
-     rtx *reg_map;
+loop_givs_rescan (struct loop *loop, struct iv_class *bl, rtx *reg_map)
 {
   struct induction *v;
 
@@ -4893,13 +4915,13 @@ loop_givs_rescan (loop, bl, reg_map)
                                          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);
+         /* 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
@@ -4928,11 +4950,9 @@ loop_givs_rescan (loop, bl, reg_map)
 
 
 static int
-loop_giv_reduce_benefit (loop, bl, v, test_reg)
-     struct loop *loop ATTRIBUTE_UNUSED;
-     struct iv_class *bl;
-     struct induction *v;
-     rtx test_reg;
+loop_giv_reduce_benefit (struct loop *loop ATTRIBUTE_UNUSED,
+                        struct iv_class *bl, struct induction *v,
+                        rtx test_reg)
 {
   int add_cost;
   int benefit;
@@ -5005,8 +5025,7 @@ loop_giv_reduce_benefit (loop, bl, v, test_reg)
 /* Free IV structures for LOOP.  */
 
 static void
-loop_ivs_free (loop)
-     struct loop *loop;
+loop_ivs_free (struct loop *loop)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   struct iv_class *iv = ivs->list;
@@ -5046,9 +5065,7 @@ loop_ivs_free (loop)
    must check regnos to make sure they are in bounds.  */
 
 static void
-strength_reduce (loop, flags)
-     struct loop *loop;
-     int flags;
+strength_reduce (struct loop *loop, int flags)
 {
   struct loop_info *loop_info = LOOP_INFO (loop);
   struct loop_regs *regs = LOOP_REGS (loop);
@@ -5072,7 +5089,7 @@ strength_reduce (loop, flags)
   addr_placeholder = gen_reg_rtx (Pmode);
 
   ivs->n_regs = max_reg_before_loop;
-  ivs->regs = (struct iv *) xcalloc (ivs->n_regs, sizeof (struct iv));
+  ivs->regs = xcalloc (ivs->n_regs, sizeof (struct iv));
 
   /* Find all BIVs in loop.  */
   loop_bivs_find (loop);
@@ -5126,7 +5143,7 @@ strength_reduce (loop, flags)
      Some givs might have been made from biv increments, so look at
      ivs->reg_iv_type for a suitable size.  */
   reg_map_size = ivs->n_regs;
-  reg_map = (rtx *) xcalloc (reg_map_size, sizeof (rtx));
+  reg_map = xcalloc (reg_map_size, sizeof (rtx));
 
   /* Examine each iv class for feasibility of strength reduction/induction
      variable elimination.  */
@@ -5147,7 +5164,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_dependent_givs (bl, loop_info);
+      check_ext_dependent_givs (loop, bl);
 
       /* Combine all giv's for this iv_class.  */
       combine_givs (regs, bl);
@@ -5335,23 +5352,6 @@ strength_reduce (loop, flags)
          && unrolled_insn_copies <= insn_count))
     unroll_loop (loop, insn_count, 1);
 
-#ifdef HAVE_doloop_end
-  if (HAVE_doloop_end && (flags & LOOP_BCT) && flag_branch_on_count_reg)
-    doloop_optimize (loop);
-#endif  /* HAVE_doloop_end  */
-
-  /* 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)
-    {
-      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)
     fprintf (loop_dump_stream, "\n");
 
@@ -5362,11 +5362,8 @@ strength_reduce (loop, flags)
 \f
 /*Record all basic induction variables calculated in the insn.  */
 static rtx
-check_insn_for_bivs (loop, p, not_every_iteration, maybe_multiple)
-     struct loop *loop;
-     rtx p;
-     int not_every_iteration;
-     int maybe_multiple;
+check_insn_for_bivs (struct loop *loop, rtx p, int not_every_iteration,
+                    int maybe_multiple)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   rtx set;
@@ -5392,8 +5389,7 @@ check_insn_for_bivs (loop, p, not_every_iteration, maybe_multiple)
              /* It is a possible basic induction variable.
                 Create and initialize an induction structure for it.  */
 
-             struct induction *v
-               = (struct induction *) xmalloc (sizeof (struct induction));
+             struct induction *v = xmalloc (sizeof (struct induction));
 
              record_biv (loop, v, p, dest_reg, inc_val, mult_val, location,
                          not_every_iteration, maybe_multiple);
@@ -5410,11 +5406,8 @@ check_insn_for_bivs (loop, p, not_every_iteration, maybe_multiple)
    A register is a giv if: it is only set once, it is a function of a
    biv and a constant (or invariant), and it is not a biv.  */
 static rtx
-check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
-     struct loop *loop;
-     rtx p;
-     int not_every_iteration;
-     int maybe_multiple;
+check_insn_for_givs (struct loop *loop, rtx p, int not_every_iteration,
+                    int maybe_multiple)
 {
   struct loop_regs *regs = LOOP_REGS (loop);
 
@@ -5459,8 +5452,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
                                             &add_val, &mult_val, &ext_val,
                                             &last_consec_insn))))
        {
-         struct induction *v
-           = (struct induction *) xmalloc (sizeof (struct induction));
+         struct induction *v = xmalloc (sizeof (struct induction));
 
          /* If this is a library call, increase benefit.  */
          if (find_reg_note (p, REG_RETVAL, NULL_RTX))
@@ -5477,14 +5469,10 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
        }
     }
 
-#ifndef DONT_REDUCE_ADDR
   /* Look for givs which are memory addresses.  */
-  /* This resulted in worse code on a VAX 8600.  I wonder if it
-     still does.  */
   if (GET_CODE (p) == INSN)
     find_mem_givs (loop, PATTERN (p), p, not_every_iteration,
                   maybe_multiple);
-#endif
 
   /* Update the status of whether giv can derive other givs.  This can
      change when we pass a label or an insn that updates a biv.  */
@@ -5503,11 +5491,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
    INSN is the insn containing X.  */
 
 static int
-valid_initial_value_p (x, insn, call_seen, loop_start)
-     rtx x;
-     rtx insn;
-     int call_seen;
-     rtx loop_start;
+valid_initial_value_p (rtx x, rtx insn, int call_seen, rtx loop_start)
 {
   if (CONSTANT_P (x))
     return 1;
@@ -5537,14 +5521,11 @@ 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)
-     const struct loop *loop;
-     rtx x;
-     rtx insn;
-     int not_every_iteration, maybe_multiple;
+find_mem_givs (const struct loop *loop, rtx x, rtx insn,
+              int not_every_iteration, int maybe_multiple)
 {
   int i, j;
   enum rtx_code code;
@@ -5588,8 +5569,7 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
                                   GET_MODE (x)))
          {
            /* Found one; record it.  */
-           struct induction *v
-             = (struct induction *) xmalloc (sizeof (struct induction));
+           struct induction *v = xmalloc (sizeof (struct induction));
 
            record_giv (loop, v, insn, src_reg, addr_placeholder, mult_val,
                        add_val, ext_val, benefit, DEST_ADDR,
@@ -5634,17 +5614,9 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
    executed exactly once per iteration.  */
 
 static void
-record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
-           not_every_iteration, maybe_multiple)
-     struct loop *loop;
-     struct induction *v;
-     rtx insn;
-     rtx dest_reg;
-     rtx inc_val;
-     rtx mult_val;
-     rtx *location;
-     int not_every_iteration;
-     int maybe_multiple;
+record_biv (struct loop *loop, struct induction *v, rtx insn, rtx dest_reg,
+           rtx inc_val, rtx mult_val, rtx *location,
+           int not_every_iteration, int maybe_multiple)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   struct iv_class *bl;
@@ -5660,6 +5632,7 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
   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.  */
@@ -5669,7 +5642,7 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
     {
       /* Create and initialize new iv_class.  */
 
-      bl = (struct iv_class *) xmalloc (sizeof (struct iv_class));
+      bl = xmalloc (sizeof (struct iv_class));
 
       bl->regno = REGNO (dest_reg);
       bl->biv = 0;
@@ -5680,7 +5653,7 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
       /* Set initial value to the reg itself.  */
       bl->initial_value = dest_reg;
       bl->final_value = 0;
-      /* We haven't seen the initializing insn yet */
+      /* We haven't seen the initializing insn yet */
       bl->init_insn = 0;
       bl->init_set = 0;
       bl->initial_test = 0;
@@ -5697,6 +5670,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;
@@ -5723,18 +5707,10 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location,
    LOCATION points to the place where this giv's value appears in INSN.  */
 
 static void
-record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
-           benefit, type, not_every_iteration, maybe_multiple, location)
-     const struct loop *loop;
-     struct induction *v;
-     rtx insn;
-     rtx src_reg;
-     rtx dest_reg;
-     rtx mult_val, add_val, ext_val;
-     int benefit;
-     enum g_types type;
-     int not_every_iteration, maybe_multiple;
-     rtx *location;
+record_giv (const struct loop *loop, struct induction *v, rtx insn,
+           rtx src_reg, rtx dest_reg, rtx mult_val, rtx add_val,
+           rtx ext_val, int benefit, enum g_types type,
+           int not_every_iteration, int maybe_multiple, rtx *location)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   struct induction *b;
@@ -5742,7 +5718,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
@@ -5937,9 +5913,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
    have been identified.  */
 
 static void
-check_final_value (loop, v)
-     const struct loop *loop;
-     struct induction *v;
+check_final_value (const struct loop *loop, struct induction *v)
 {
   rtx final_value = 0;
 
@@ -6087,9 +6061,7 @@ check_final_value (loop, v)
    The cases we look at are when a label or an update to a biv is passed.  */
 
 static void
-update_giv_derive (loop, p)
-     const struct loop *loop;
-     rtx p;
+update_giv_derive (const struct loop *loop, rtx p)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   struct iv_class *bl;
@@ -6129,6 +6101,10 @@ update_giv_derive (loop, p)
       if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN
          || biv->insn == p)
        {
+         /* Skip if location is the same as a previous one.  */
+         if (biv->same)
+           continue;
+
          for (giv = bl->giv; giv; giv = giv->next_iv)
            {
              /* If cant_derive is already true, there is no point in
@@ -6199,7 +6175,7 @@ update_giv_derive (loop, p)
    *MULT_VAL to CONST0_RTX, and store the invariant into *INC_VAL.
 
    We also want to detect a BIV when it corresponds to a variable
-   whose mode was promoted via PROMOTED_MODE.  In that case, an increment
+   whose mode was promoted.  In that case, an increment
    of the variable may be a PLUS that adds a SUBREG of that variable to
    an invariant and then sign- or zero-extends the result of the PLUS
    into the variable.
@@ -6220,19 +6196,13 @@ update_giv_derive (loop, p)
    If we cannot find a biv, we return 0.  */
 
 static int
-basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
-     const struct loop *loop;
-     rtx x;
-     enum machine_mode mode;
-     rtx dest_reg;
-     rtx p;
-     rtx *inc_val;
-     rtx *mult_val;
-     rtx **location;
+basic_induction_var (const struct loop *loop, rtx x, enum machine_mode mode,
+                    rtx dest_reg, rtx p, rtx *inc_val, rtx *mult_val,
+                    rtx **location)
 {
   enum rtx_code code;
   rtx *argp, arg;
-  rtx insn, set = 0;
+  rtx insn, set = 0, last, inc;
 
   code = GET_CODE (x);
   *location = NULL;
@@ -6260,7 +6230,26 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
       if (loop_invariant_p (loop, arg) != 1)
        return 0;
 
-      *inc_val = convert_modes (GET_MODE (dest_reg), GET_MODE (x), arg, 0);
+      /* convert_modes can emit new instructions, e.g. when arg is a loop
+        invariant MEM and dest_reg has a different mode.
+        These instructions would be emitted after the end of the function
+        and then *inc_val would be an uninitialized pseudo.
+        Detect this and bail in this case.
+        Other alternatives to solve this can be introducing a convert_modes
+        variant which is allowed to fail but not allowed to emit new
+        instructions, emit these instructions before loop start and let
+        it be garbage collected if *inc_val is never used or saving the
+        *inc_val initialization sequence generated here and when *inc_val
+        is going to be actually used, emit it at some suitable place.  */
+      last = get_last_insn ();
+      inc = convert_modes (GET_MODE (dest_reg), GET_MODE (x), arg, 0);
+      if (get_last_insn () != last)
+       {
+         delete_insns_since (last);
+         return 0;
+       }
+
+      *inc_val = inc;
       *mult_val = const1_rtx;
       *location = argp;
       return 1;
@@ -6341,7 +6330,15 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
          && 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);
+         last = get_last_insn ();
+         inc = convert_modes (GET_MODE (dest_reg), mode, x, 0);
+         if (get_last_insn () != last)
+           {
+             delete_insns_since (last);
+             return 0;
+           }
+
+         *inc_val = inc;
          *mult_val = const0_rtx;
          return 1;
        }
@@ -6349,6 +6346,9 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
        return 0;
 
     case SIGN_EXTEND:
+      /* Ignore this BIV if signed arithmetic overflow is defined.  */
+      if (flag_wrapv)
+       return 0;
       return basic_induction_var (loop, XEXP (x, 0), GET_MODE (XEXP (x, 0)),
                                  dest_reg, p, inc_val, mult_val, location);
 
@@ -6395,17 +6395,10 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
      such that the value of X is biv * mult + add;  */
 
 static int
-general_induction_var (loop, x, src_reg, add_val, mult_val, ext_val,
-                      is_addr, pbenefit, addr_mode)
-     const struct loop *loop;
-     rtx x;
-     rtx *src_reg;
-     rtx *add_val;
-     rtx *mult_val;
-     rtx *ext_val;
-     int is_addr;
-     int *pbenefit;
-     enum machine_mode addr_mode;
+general_induction_var (const struct loop *loop, rtx x, rtx *src_reg,
+                      rtx *add_val, rtx *mult_val, rtx *ext_val,
+                      int is_addr, int *pbenefit,
+                      enum machine_mode addr_mode)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   rtx orig_x = x;
@@ -6504,15 +6497,11 @@ general_induction_var (loop, x, src_reg, add_val, mult_val, ext_val,
 
    *BENEFIT will be incremented by the benefit of any sub-giv encountered.  */
 
-static rtx sge_plus PARAMS ((enum machine_mode, rtx, rtx));
-static rtx sge_plus_constant PARAMS ((rtx, rtx));
+static rtx sge_plus (enum machine_mode, rtx, rtx);
+static rtx sge_plus_constant (rtx, rtx);
 
 static rtx
-simplify_giv_expr (loop, x, ext_val, benefit)
-     const struct loop *loop;
-     rtx x;
-     rtx *ext_val;
-     int *benefit;
+simplify_giv_expr (const struct loop *loop, rtx x, rtx *ext_val, int *benefit)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   struct loop_regs *regs = LOOP_REGS (loop);
@@ -6686,7 +6675,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 innermost nodes.  */
          else if (GET_CODE (arg0) == PLUS)
            {
              /* (invar_0 + invar_1) * invar_2.  Distribute.  */
@@ -6937,8 +6926,7 @@ simplify_giv_expr (loop, x, ext_val, benefit)
    CONST_INT in the summation.  It is only used by simplify_giv_expr.  */
 
 static rtx
-sge_plus_constant (x, c)
-     rtx x, c;
+sge_plus_constant (rtx x, rtx c)
 {
   if (GET_CODE (x) == CONST_INT)
     return GEN_INT (INTVAL (x) + INTVAL (c));
@@ -6963,9 +6951,7 @@ sge_plus_constant (x, c)
 }
 
 static rtx
-sge_plus (mode, x, y)
-     enum machine_mode mode;
-     rtx x, y;
+sge_plus (enum machine_mode mode, rtx x, rtx y)
 {
   while (GET_CODE (y) == PLUS)
     {
@@ -7003,17 +6989,9 @@ sge_plus (mode, x, y)
    *MULT_VAL and *ADD_VAL.  */
 
 static int
-consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
-                add_val, mult_val, ext_val, last_consec_insn)
-     const struct loop *loop;
-     int first_benefit;
-     rtx p;
-     rtx src_reg;
-     rtx dest_reg;
-     rtx *add_val;
-     rtx *mult_val;
-     rtx *ext_val;
-     rtx *last_consec_insn;
+consec_sets_giv (const struct loop *loop, int first_benefit, rtx p,
+                rtx src_reg, rtx dest_reg, rtx *add_val, rtx *mult_val,
+                rtx *ext_val, rtx *last_consec_insn)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   struct loop_regs *regs = LOOP_REGS (loop);
@@ -7035,7 +7013,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
   if (REG_IV_TYPE (ivs, REGNO (dest_reg)) != UNKNOWN_INDUCT)
     return 0;
 
-  v = (struct induction *) alloca (sizeof (struct induction));
+  v = alloca (sizeof (struct induction));
   v->src_reg = src_reg;
   v->mult_val = *mult_val;
   v->add_val = *add_val;
@@ -7119,8 +7097,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
    subtracting variables.  */
 
 static rtx
-express_from_1 (a, b, mult)
-     rtx a, b, mult;
+express_from_1 (rtx a, rtx b, rtx mult)
 {
   /* If MULT is zero, then A*MULT is zero, and our expression is B.  */
 
@@ -7218,8 +7195,7 @@ express_from_1 (a, b, mult)
 }
 
 rtx
-express_from (g1, g2)
-     struct induction *g1, *g2;
+express_from (struct induction *g1, struct induction *g2)
 {
   rtx mult, add;
 
@@ -7230,6 +7206,9 @@ express_from (g1, g2)
       && GET_CODE (g2->mult_val) == CONST_INT)
     {
       if (g1->mult_val == const0_rtx
+         || (g1->mult_val == constm1_rtx
+             && INTVAL (g2->mult_val)
+                == (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1))
          || INTVAL (g2->mult_val) % INTVAL (g1->mult_val) != 0)
        return NULL_RTX;
       mult = GEN_INT (INTVAL (g2->mult_val) / INTVAL (g1->mult_val));
@@ -7300,8 +7279,7 @@ express_from (g1, g2)
    used to represent G1.  */
 
 static rtx
-combine_givs_p (g1, g2)
-     struct induction *g1, *g2;
+combine_givs_p (struct induction *g1, struct induction *g2)
 {
   rtx comb, ret;
 
@@ -7332,21 +7310,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;
 }
@@ -7356,10 +7321,9 @@ combine_givs_p (g1, g2)
    make the giv illegal.  */
 
 static void
-check_ext_dependent_givs (bl, loop_info)
-     struct iv_class *bl;
-     struct loop_info *loop_info;
+check_ext_dependent_givs (const struct loop *loop, struct iv_class *bl)
 {
+  struct loop_info *loop_info = LOOP_INFO (loop);
   int ze_ok = 0, se_ok = 0, info_ok = 0;
   enum machine_mode biv_mode = GET_MODE (bl->biv->src_reg);
   HOST_WIDE_INT start_val;
@@ -7370,9 +7334,6 @@ check_ext_dependent_givs (bl, loop_info)
 
   /* Make sure the iteration data is available.  We must have
      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.  */
   if (loop_info->n_iterations > 0
       && bl->initial_value
       && GET_CODE (bl->initial_value) == CONST_INT
@@ -7394,7 +7355,7 @@ check_ext_dependent_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;
@@ -7407,7 +7368,7 @@ check_ext_dependent_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)
@@ -7425,7 +7386,7 @@ check_ext_dependent_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)
@@ -7439,6 +7400,37 @@ check_ext_dependent_givs (bl, loop_info)
        }
     }
 
+  /* If we know the BIV is compared at run-time against an 
+     invariant value, and the increment is +/- 1, we may also 
+     be able to prove that the BIV cannot overflow.  */
+  else if (bl->biv->src_reg == loop_info->iteration_var
+           && loop_info->comparison_value
+           && loop_invariant_p (loop, loop_info->comparison_value)
+           && (incr = biv_total_increment (bl))
+           && GET_CODE (incr) == CONST_INT)
+    {
+      /* If the increment is +1, and the exit test is a <,
+         the BIV cannot overflow.  (For <=, we have the 
+         problematic case that the comparison value might
+         be the maximum value of the range.)  */
+       if (INTVAL (incr) == 1)
+         {
+           if (loop_info->comparison_code == LT)
+             se_ok = ze_ok = 1;
+           else if (loop_info->comparison_code == LTU)
+             ze_ok = 1;
+         }
+
+       /* Likewise for increment -1 and exit test >.  */
+       if (INTVAL (incr) == -1)
+         {
+           if (loop_info->comparison_code == GT)
+             se_ok = ze_ok = 1;
+           else if (loop_info->comparison_code == GTU)
+             ze_ok = 1;
+         }
+    }
+
   /* Invalidate givs that fail the tests.  */
   for (v = bl->giv; v; v = v->next_iv)
     if (v->ext_dependent)
@@ -7460,8 +7452,9 @@ check_ext_dependent_givs (bl, loop_info)
               signed or unsigned, so to safely truncate we must satisfy
               both.  The initial check here verifies the BIV itself;
               once that is successful we may check its range wrt the
-              derived GIV.  */
-           if (se_ok && ze_ok)
+              derived GIV.  This works only if we were able to determine
+              constant start and end values above.  */
+           if (se_ok && ze_ok && info_ok)
              {
                enum machine_mode outer_mode = GET_MODE (v->ext_dependent);
                unsigned HOST_WIDE_INT max = GET_MODE_MASK (outer_mode) >> 1;
@@ -7518,9 +7511,7 @@ check_ext_dependent_givs (bl, loop_info)
 /* Generate a version of VALUE in a mode appropriate for initializing V.  */
 
 rtx
-extend_value_for_giv (v, value)
-     struct induction *v;
-     rtx value;
+extend_value_for_giv (struct induction *v, rtx value)
 {
   rtx ext_dep = v->ext_dependent;
 
@@ -7545,9 +7536,7 @@ struct combine_givs_stats
 };
 
 static int
-cmp_combine_givs_stats (xp, yp)
-     const PTR xp;
-     const PTR yp;
+cmp_combine_givs_stats (const void *xp, const void *yp)
 {
   const struct combine_givs_stats * const x =
     (const struct combine_givs_stats *) xp;
@@ -7567,9 +7556,7 @@ cmp_combine_givs_stats (xp, yp)
    giv.  Also, update BENEFIT and related fields for cost/benefit analysis.  */
 
 static void
-combine_givs (regs, bl)
-     struct loop_regs *regs;
-     struct iv_class *bl;
+combine_givs (struct loop_regs *regs, struct iv_class *bl)
 {
   /* Additional benefit to add for being combined multiple times.  */
   const int extra_benefit = 3;
@@ -7585,15 +7572,14 @@ combine_givs (regs, bl)
     if (!g1->ignore)
       giv_count++;
 
-  giv_array
-    = (struct induction **) alloca (giv_count * sizeof (struct induction *));
+  giv_array = alloca (giv_count * sizeof (struct induction *));
   i = 0;
   for (g1 = bl->giv; g1; g1 = g1->next_iv)
     if (!g1->ignore)
       giv_array[i++] = g1;
 
-  stats = (struct combine_givs_stats *) xcalloc (giv_count, sizeof (*stats));
-  can_combine = (rtx *) xcalloc (giv_count, giv_count * sizeof (rtx));
+  stats = xcalloc (giv_count, sizeof (*stats));
+  can_combine = xcalloc (giv_count, giv_count * sizeof (rtx));
 
   for (i = 0; i < giv_count; i++)
     {
@@ -7737,14 +7723,12 @@ restart:
   free (can_combine);
 }
 \f
-/* Generate sequence for REG = B * M + A.  */
+/* Generate sequence for REG = B * M + A.  B is the initial value of
+   the basic induction variable, M a multiplicative constant, A an
+   additive constant and REG the destination register.  */
 
 static rtx
-gen_add_mult (b, m, a, reg)
-     rtx b;          /* initial value of basic induction variable */
-     rtx m;          /* multiplicative constant */
-     rtx a;          /* additive constant */
-     rtx reg;        /* destination register */
+gen_add_mult (rtx b,  rtx m, rtx a, rtx reg)
 {
   rtx seq;
   rtx result;
@@ -7764,47 +7748,33 @@ gen_add_mult (b, m, a, reg)
 /* Update registers created in insn sequence SEQ.  */
 
 static void
-loop_regs_update (loop, seq)
-     const struct loop *loop ATTRIBUTE_UNUSED;
-     rtx seq;
+loop_regs_update (const struct loop *loop ATTRIBUTE_UNUSED, rtx seq)
 {
   rtx insn;
 
   /* Update register info for alias analysis.  */
 
-  if (seq == NULL_RTX)
-    return;
-
-  if (INSN_P (seq))
+  insn = seq;
+  while (insn != NULL_RTX)
     {
-      insn = seq;
-      while (insn != NULL_RTX)
-       {
-         rtx set = single_set (insn);
+      rtx set = single_set (insn);
 
-         if (set && GET_CODE (SET_DEST (set)) == REG)
-           record_base_value (REGNO (SET_DEST (set)), SET_SRC (set), 0);
+      if (set && GET_CODE (SET_DEST (set)) == REG)
+       record_base_value (REGNO (SET_DEST (set)), SET_SRC (set), 0);
 
-         insn = NEXT_INSN (insn);
-       }
+      insn = NEXT_INSN (insn);
     }
-  else if (GET_CODE (seq) == SET
-          && GET_CODE (SET_DEST (seq)) == REG)
-    record_base_value (REGNO (SET_DEST (seq)), SET_SRC (seq), 0);
 }
 
 
-/* EMIT code before BEFORE_BB/BEFORE_INSN to set REG = B * M + A.  */
+/* EMIT code before BEFORE_BB/BEFORE_INSN to set REG = B * M + A.  B
+   is the initial value of the basic induction variable, M a
+   multiplicative constant, A an additive constant and REG the
+   destination register.  */
 
 void
-loop_iv_add_mult_emit_before (loop, b, m, a, reg, before_bb, before_insn)
-     const struct loop *loop;
-     rtx b;          /* initial value of basic induction variable */
-     rtx m;          /* multiplicative constant */
-     rtx a;          /* additive constant */
-     rtx reg;        /* destination register */
-     basic_block before_bb;
-     rtx before_insn;
+loop_iv_add_mult_emit_before (const struct loop *loop, rtx b, rtx m, rtx a,
+                             rtx reg, basic_block before_bb, rtx before_insn)
 {
   rtx seq;
 
@@ -7822,23 +7792,22 @@ loop_iv_add_mult_emit_before (loop, b, m, a, reg, before_bb, before_insn)
   update_reg_last_use (b, before_insn);
   update_reg_last_use (m, before_insn);
 
-  loop_insn_emit_before (loop, before_bb, before_insn, seq);
-
   /* It is possible that the expansion created lots of new registers.
-     Iterate over the sequence we just created and record them all.  */
+     Iterate over the sequence we just created and record them all.  We
+     must do this before inserting the sequence.  */
   loop_regs_update (loop, seq);
+
+  loop_insn_emit_before (loop, before_bb, before_insn, seq);
 }
 
 
-/* Emit insns in loop pre-header to set REG = B * M + A.  */
+/* Emit insns in loop pre-header to set REG = B * M + A.  B is the
+   initial value of the basic induction variable, M a multiplicative
+   constant, A an additive constant and REG the destination
+   register.  */
 
 void
-loop_iv_add_mult_sink (loop, b, m, a, reg)
-     const struct loop *loop;
-     rtx b;          /* initial value of basic induction variable */
-     rtx m;          /* multiplicative constant */
-     rtx a;          /* additive constant */
-     rtx reg;        /* destination register */
+loop_iv_add_mult_sink (const struct loop *loop, rtx b, rtx m, rtx a, rtx reg)
 {
   rtx seq;
 
@@ -7851,34 +7820,33 @@ loop_iv_add_mult_sink (loop, b, m, a, reg)
   update_reg_last_use (b, loop->sink);
   update_reg_last_use (m, loop->sink);
 
-  loop_insn_sink (loop, seq);
-
   /* It is possible that the expansion created lots of new registers.
-     Iterate over the sequence we just created and record them all.  */
+     Iterate over the sequence we just created and record them all.  We
+     must do this before inserting the sequence.  */
   loop_regs_update (loop, seq);
+
+  loop_insn_sink (loop, seq);
 }
 
 
-/* Emit insns after loop to set REG = B * M + A.  */
+/* Emit insns after loop to set REG = B * M + A.  B is the initial
+   value of the basic induction variable, M a multiplicative constant,
+   A an additive constant and REG the destination register.  */
 
 void
-loop_iv_add_mult_hoist (loop, b, m, a, reg)
-     const struct loop *loop;
-     rtx b;          /* initial value of basic induction variable */
-     rtx m;          /* multiplicative constant */
-     rtx a;          /* additive constant */
-     rtx reg;        /* destination register */
+loop_iv_add_mult_hoist (const struct loop *loop, rtx b, rtx m, rtx a, rtx reg)
 {
   rtx seq;
 
   /* Use copy_rtx to prevent unexpected sharing of these rtx.  */
   seq = gen_add_mult (copy_rtx (b), copy_rtx (m), copy_rtx (a), reg);
 
-  loop_insn_hoist (loop, seq);
-
   /* It is possible that the expansion created lots of new registers.
-     Iterate over the sequence we just created and record them all.  */
+     Iterate over the sequence we just created and record them all.  We
+     must do this before inserting the sequence.  */
   loop_regs_update (loop, seq);
+
+  loop_insn_hoist (loop, seq);
 }
 
 
@@ -7887,11 +7855,7 @@ loop_iv_add_mult_hoist (loop, b, m, a, reg)
    sequence.  */
 
 static int
-iv_add_mult_cost (b, m, a, reg)
-     rtx b;          /* initial value of basic induction variable */
-     rtx m;          /* multiplicative constant */
-     rtx a;          /* additive constant */
-     rtx reg;        /* destination register */
+iv_add_mult_cost (rtx b, rtx m, rtx a, rtx reg)
 {
   int cost = 0;
   rtx last, result;
@@ -7921,9 +7885,7 @@ iv_add_mult_cost (b, m, a, reg)
   ??? thing, generate wasted RTL just to see if something is possible.  */
 
 static int
-product_cheap_p (a, b)
-     rtx a;
-     rtx b;
+product_cheap_p (rtx a, rtx b)
 {
   rtx tmp;
   int win, n_insns;
@@ -7999,15 +7961,14 @@ product_cheap_p (a, b)
    final_[bg]iv_value.  */
 
 static int
-check_dbra_loop (loop, insn_count)
-     struct loop *loop;
-     int insn_count;
+check_dbra_loop (struct loop *loop, int insn_count)
 {
   struct loop_info *loop_info = LOOP_INFO (loop);
   struct loop_regs *regs = LOOP_REGS (loop);
   struct loop_ivs *ivs = LOOP_IVS (loop);
   struct iv_class *bl;
   rtx reg;
+  enum machine_mode mode;
   rtx jump_label;
   rtx final_value;
   rtx start_value;
@@ -8033,7 +7994,7 @@ check_dbra_loop (loop, insn_count)
 
   /* Try to compute whether the compare/branch at the loop end is one or
      two instructions.  */
-  get_condition (jump, &first_compare);
+  get_condition (jump, &first_compare, false);
   if (first_compare == jump)
     compare_and_branch = 1;
   else if (first_compare == prev_nonnote_insn (jump))
@@ -8070,6 +8031,22 @@ check_dbra_loop (loop, insn_count)
        break;
     }
 
+  /* Try swapping the comparison to identify a suitable biv.  */
+  if (!bl)
+    for (bl = ivs->list; bl; bl = bl->next)
+      if (bl->biv_count == 1
+         && ! bl->biv->maybe_multiple
+         && bl->biv->dest_reg == XEXP (comparison, 1)
+         && ! reg_used_between_p (regno_reg_rtx[bl->regno], bl->biv->insn,
+                                  first_compare))
+       {
+         comparison = gen_rtx_fmt_ee (swap_condition (GET_CODE (comparison)),
+                                      VOIDmode,
+                                      XEXP (comparison, 1),
+                                      XEXP (comparison, 0));
+         break;
+       }
+
   if (! bl)
     return 0;
 
@@ -8078,9 +8055,7 @@ check_dbra_loop (loop, insn_count)
      In this case, add a reg_note REG_NONNEG, which allows the
      m68k DBRA instruction to be used.  */
 
-  if (((GET_CODE (comparison) == GT
-       && GET_CODE (XEXP (comparison, 1)) == CONST_INT
-       && INTVAL (XEXP (comparison, 1)) == -1)
+  if (((GET_CODE (comparison) == GT && XEXP (comparison, 1) == constm1_rtx)
        || (GET_CODE (comparison) == NE && XEXP (comparison, 1) == const0_rtx))
       && GET_CODE (bl->biv->add_val) == CONST_INT
       && INTVAL (bl->biv->add_val) < 0)
@@ -8094,7 +8069,7 @@ check_dbra_loop (loop, insn_count)
          && (INTVAL (bl->initial_value)
              % (-INTVAL (bl->biv->add_val))) == 0)
        {
-         /* register always nonnegative, add REG_NOTE to branch */
+         /* Register always nonnegative, add REG_NOTE to branch.  */
          if (! find_reg_note (jump, REG_NONNEG, NULL_RTX))
            REG_NOTES (jump)
              = gen_rtx_EXPR_LIST (REG_NONNEG, bl->biv->dest_reg,
@@ -8116,7 +8091,8 @@ check_dbra_loop (loop, insn_count)
          before_comparison = get_condition_for_loop (loop, p);
          if (before_comparison
              && XEXP (before_comparison, 0) == bl->biv->dest_reg
-             && GET_CODE (before_comparison) == LT
+             && (GET_CODE (before_comparison) == LT
+                 || GET_CODE (before_comparison) == LTU)
              && XEXP (before_comparison, 1) == const0_rtx
              && ! reg_set_between_p (bl->biv->dest_reg, p, loop_start)
              && INTVAL (bl->biv->add_val) == -1)
@@ -8172,9 +8148,11 @@ check_dbra_loop (loop, insn_count)
                    && REGNO (SET_DEST (set)) == bl->regno)
                  /* An insn that sets the biv is okay.  */
                  ;
-               else if ((p == prev_nonnote_insn (prev_nonnote_insn (loop_end))
-                         || p == prev_nonnote_insn (loop_end))
-                        && reg_mentioned_p (bivreg, PATTERN (p)))
+               else if (!reg_mentioned_p (bivreg, PATTERN (p)))
+                 /* An insn that doesn't mention the biv is okay.  */
+                 ;
+               else if (p == prev_nonnote_insn (prev_nonnote_insn (loop_end))
+                        || p == prev_nonnote_insn (loop_end))
                  {
                    /* If either of these insns uses the biv and sets a pseudo
                       that has more than one usage, then the biv has uses
@@ -8188,7 +8166,7 @@ check_dbra_loop (loop, insn_count)
                        break;
                      }
                  }
-               else if (reg_mentioned_p (bivreg, PATTERN (p)))
+               else
                  {
                    no_use_except_counting = 0;
                    break;
@@ -8285,7 +8263,8 @@ check_dbra_loop (loop, insn_count)
              /* for constants, LE gets turned into LT */
              && (GET_CODE (comparison) == LT
                  || (GET_CODE (comparison) == LE
-                     && no_use_except_counting)))
+                     && no_use_except_counting) 
+                 || GET_CODE (comparison) == LTU))
            {
              HOST_WIDE_INT add_val, add_adjust, comparison_val = 0;
              rtx initial_value, comparison_value;
@@ -8410,6 +8389,7 @@ check_dbra_loop (loop, insn_count)
 
              /* Save some info needed to produce the new insns.  */
              reg = bl->biv->dest_reg;
+             mode = GET_MODE (reg);
              jump_label = condjump_label (PREV_INSN (loop_end));
              new_add_val = GEN_INT (-INTVAL (bl->biv->add_val));
 
@@ -8421,12 +8401,12 @@ check_dbra_loop (loop, insn_count)
              if (initial_value == const0_rtx
                  && GET_CODE (comparison_value) == CONST_INT)
                {
-                 start_value = GEN_INT (comparison_val - add_adjust);
+                 start_value
+                   = gen_int_mode (comparison_val - add_adjust, mode);
                  loop_insn_hoist (loop, gen_move_insn (reg, start_value));
                }
              else if (GET_CODE (initial_value) == CONST_INT)
                {
-                 enum machine_mode mode = GET_MODE (reg);
                  rtx offset = GEN_INT (-INTVAL (initial_value) - add_adjust);
                  rtx add_insn = gen_add3_insn (reg, comparison_value, offset);
 
@@ -8442,7 +8422,6 @@ check_dbra_loop (loop, insn_count)
                }
              else if (! add_adjust)
                {
-                 enum machine_mode mode = GET_MODE (reg);
                  rtx sub_insn = gen_sub3_insn (reg, comparison_value,
                                                initial_value);
 
@@ -8500,7 +8479,7 @@ 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,
+                                      mode, 0,
                                       XEXP (jump_label, 0));
              tem = get_insns ();
              end_sequence ();
@@ -8594,11 +8573,8 @@ check_dbra_loop (loop, insn_count)
    start of the loop.  */
 
 static int
-maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
-     const struct loop *loop;
-     struct iv_class *bl;
-     int eliminate_p;
-     int threshold, insn_count;
+maybe_eliminate_biv (const struct loop *loop, struct iv_class *bl,
+                    int eliminate_p, int threshold, int insn_count)
 {
   struct loop_ivs *ivs = LOOP_IVS (loop);
   rtx reg = bl->biv->dest_reg;
@@ -8615,7 +8591,7 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
       rtx note;
 
       /* If this is a libcall that sets a giv, skip ahead to its end.  */
-      if (GET_RTX_CLASS (code) == 'i')
+      if (INSN_P (p))
        {
          note = find_reg_note (p, REG_LIBCALL, NULL_RTX);
 
@@ -8671,8 +8647,7 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count)
    Return nonzero if INSN is first.  */
 
 int
-loop_insn_first_p (insn, reference)
-     rtx insn, reference;
+loop_insn_first_p (rtx insn, rtx reference)
 {
   rtx p, q;
 
@@ -8705,9 +8680,8 @@ loop_insn_first_p (insn, reference)
    the offset that we have to take into account due to auto-increment /
    div derivation is zero.  */
 static int
-biv_elimination_giv_has_0_offset (biv, giv, insn)
-     struct induction *biv, *giv;
-     rtx insn;
+biv_elimination_giv_has_0_offset (struct induction *biv,
+                                 struct induction *giv, rtx insn)
 {
   /* If the giv V had the auto-inc address optimization applied
      to it, and INSN occurs between the giv insn and the biv
@@ -8735,13 +8709,9 @@ biv_elimination_giv_has_0_offset (biv, giv, insn)
    start of the loop (when WHERE_INSN is zero).  */
 
 static int
-maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where_bb, where_insn)
-     const struct loop *loop;
-     rtx x, insn;
-     struct iv_class *bl;
-     int eliminate_p;
-     basic_block where_bb;
-     rtx where_insn;
+maybe_eliminate_biv_1 (const struct loop *loop, rtx x, rtx insn,
+                      struct iv_class *bl, int eliminate_p,
+                      basic_block where_bb, rtx where_insn)
 {
   enum rtx_code code = GET_CODE (x);
   rtx reg = bl->biv->dest_reg;
@@ -9110,9 +9080,7 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where_bb, where_insn)
    is in an insn following INSN in the same basic block.  */
 
 static int
-last_use_this_basic_block (reg, insn)
-     rtx reg;
-     rtx insn;
+last_use_this_basic_block (rtx reg, rtx insn)
 {
   rtx n;
   for (n = insn;
@@ -9129,10 +9097,7 @@ last_use_this_basic_block (reg, insn)
    just record the location of the set and process it later.  */
 
 static void
-record_initial (dest, set, data)
-     rtx dest;
-     rtx set;
-     void *data ATTRIBUTE_UNUSED;
+record_initial (rtx dest, rtx set, void *data ATTRIBUTE_UNUSED)
 {
   struct loop_ivs *ivs = (struct loop_ivs *) data;
   struct iv_class *bl;
@@ -9158,9 +9123,7 @@ record_initial (dest, set, data)
    use it.  X must be a source expression only.  */
 
 static void
-update_reg_last_use (x, insn)
-     rtx x;
-     rtx insn;
+update_reg_last_use (rtx x, rtx insn)
 {
   /* Check for the case where INSN does not have a valid luid.  In this case,
      there is no need to modify the regno_last_uid, as this can only happen
@@ -9210,15 +9173,12 @@ update_reg_last_use (x, insn)
 
    If WANT_REG is nonzero, we wish the condition to be relative to that
    register, if possible.  Therefore, do not canonicalize the condition
-   further.  */
+   further.  If ALLOW_CC_MODE is nonzero, allow the condition returned 
+   to be a compare to a CC mode register.  */
 
 rtx
-canonicalize_condition (insn, cond, reverse, earliest, want_reg)
-     rtx insn;
-     rtx cond;
-     int reverse;
-     rtx *earliest;
-     rtx want_reg;
+canonicalize_condition (rtx insn, rtx cond, int reverse, rtx *earliest,
+                       rtx want_reg, int allow_cc_mode)
 {
   enum rtx_code code;
   rtx prev = insn;
@@ -9246,7 +9206,8 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
      the same tests as a function of STORE_FLAG_VALUE as find_comparison_args
      in cse.c  */
 
-  while (GET_RTX_CLASS (code) == '<'
+  while ((GET_RTX_CLASS (code) == RTX_COMPARE
+         || GET_RTX_CLASS (code) == RTX_COMM_COMPARE)
         && op1 == CONST0_RTX (GET_MODE (op0))
         && op0 != want_reg)
     {
@@ -9336,7 +9297,7 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
                             REAL_VALUE_NEGATIVE (fsfv)))
 #endif
                     ))
-                  && GET_RTX_CLASS (GET_CODE (SET_SRC (set))) == '<'))
+                  && COMPARISON_P (SET_SRC (set))))
              && (((GET_MODE_CLASS (mode) == MODE_CC)
                   == (GET_MODE_CLASS (inner_mode) == MODE_CC))
                  || mode == VOIDmode || inner_mode == VOIDmode))
@@ -9356,7 +9317,7 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
                             REAL_VALUE_NEGATIVE (fsfv)))
 #endif
                     ))
-                  && GET_RTX_CLASS (GET_CODE (SET_SRC (set))) == '<'
+                  && COMPARISON_P (SET_SRC (set))
                   && (((GET_MODE_CLASS (mode) == MODE_CC)
                        == (GET_MODE_CLASS (inner_mode) == MODE_CC))
                       || mode == VOIDmode || inner_mode == VOIDmode))
@@ -9375,7 +9336,7 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
 
       if (x)
        {
-         if (GET_RTX_CLASS (GET_CODE (x)) == '<')
+         if (COMPARISON_P (x))
            code = GET_CODE (x);
          if (reverse_code)
            {
@@ -9397,14 +9358,16 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
 
   /* If OP0 is the result of a comparison, we weren't able to find what
      was really being compared, so fail.  */
-  if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
+  if (!allow_cc_mode
+      && GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
     return 0;
 
   /* Canonicalize any ordered comparison with integers involving equality
      if we can do computations in the relevant mode and we do not
      overflow.  */
 
-  if (GET_CODE (op1) == CONST_INT
+  if (GET_MODE_CLASS (GET_MODE (op0)) != MODE_CC
+      && GET_CODE (op1) == CONST_INT
       && GET_MODE (op0) != VOIDmode
       && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
     {
@@ -9444,11 +9407,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);
 }
@@ -9461,12 +9422,13 @@ canonicalize_condition (insn, cond, reverse, earliest, want_reg)
    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.  */
+   insn and we will be sure that the inputs are still valid.  
+
+   If ALLOW_CC_MODE is nonzero, allow the condition returned to be a
+   compare CC mode register.  */
 
 rtx
-get_condition (jump, earliest)
-     rtx jump;
-     rtx *earliest;
+get_condition (rtx jump, rtx *earliest, int allow_cc_mode)
 {
   rtx cond;
   int reverse;
@@ -9486,18 +9448,17 @@ get_condition (jump, earliest)
     = GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
       && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (jump);
 
-  return canonicalize_condition (jump, cond, reverse, earliest, NULL_RTX);
+  return canonicalize_condition (jump, cond, reverse, earliest, NULL_RTX,
+                                allow_cc_mode);
 }
 
 /* Similar to above routine, except that we also put an invariant last
    unless both operands are invariants.  */
 
 rtx
-get_condition_for_loop (loop, x)
-     const struct loop *loop;
-     rtx x;
+get_condition_for_loop (const struct loop *loop, rtx x)
 {
-  rtx comparison = get_condition (x, (rtx*) 0);
+  rtx comparison = get_condition (x, (rtx*) 0, false);
 
   if (comparison == 0
       || ! loop_invariant_p (loop, XEXP (comparison, 0))
@@ -9513,8 +9474,7 @@ get_condition_for_loop (loop, x)
    This is taken mostly from flow.c; similar code exists elsewhere
    in the compiler.  It may be useful to put this into rtlanal.c.  */
 static int
-indirect_jump_in_function_p (start)
-     rtx start;
+indirect_jump_in_function_p (rtx start)
 {
   rtx insn;
 
@@ -9530,9 +9490,7 @@ indirect_jump_in_function_p (start)
    This function is called from prescan_loop via for_each_rtx.  */
 
 static int
-insert_loop_mem (mem, data)
-     rtx *mem;
-     void *data ATTRIBUTE_UNUSED;
+insert_loop_mem (rtx *mem, void *data ATTRIBUTE_UNUSED)
 {
   struct loop_info *loop_info = data;
   int i;
@@ -9568,6 +9526,8 @@ insert_loop_mem (mem, data)
   for (i = 0; i < loop_info->mems_idx; ++i)
     if (rtx_equal_p (m, loop_info->mems[i].mem))
       {
+       if (MEM_VOLATILE_P (m) && !MEM_VOLATILE_P (loop_info->mems[i].mem))
+         loop_info->mems[i].mem = m;
        if (GET_MODE (m) != GET_MODE (loop_info->mems[i].mem))
          /* The modes of the two memory accesses are different.  If
             this happens, something tricky is going on, and we just
@@ -9585,9 +9545,8 @@ insert_loop_mem (mem, data)
       else
        loop_info->mems_allocated = 32;
 
-      loop_info->mems = (loop_mem_info *)
-       xrealloc (loop_info->mems,
-                 loop_info->mems_allocated * sizeof (loop_mem_info));
+      loop_info->mems = xrealloc (loop_info->mems,
+                                 loop_info->mems_allocated * sizeof (loop_mem_info));
     }
 
   /* Actually insert the MEM.  */
@@ -9620,9 +9579,7 @@ insert_loop_mem (mem, data)
    optimize register I.  */
 
 static void
-loop_regs_scan (loop, extra_size)
-     const struct loop *loop;
-     int extra_size;
+loop_regs_scan (const struct loop *loop, int extra_size)
 {
   struct loop_regs *regs = LOOP_REGS (loop);
   int old_nregs;
@@ -9640,8 +9597,7 @@ loop_regs_scan (loop, extra_size)
     {
       regs->size = regs->num + extra_size;
 
-      regs->array = (struct loop_reg *)
-       xrealloc (regs->array, regs->size * sizeof (*regs->array));
+      regs->array = xrealloc (regs->array, regs->size * sizeof (*regs->array));
 
       /* Zero the new elements.  */
       memset (regs->array + old_nregs, 0,
@@ -9656,7 +9612,7 @@ loop_regs_scan (loop, extra_size)
       regs->array[i].single_usage = NULL_RTX;
     }
 
-  last_set = (rtx *) xcalloc (regs->num, sizeof (rtx));
+  last_set = xcalloc (regs->num, sizeof (rtx));
 
   /* Scan the loop, recording register usage.  */
   for (insn = loop->top ? loop->top : loop->start; insn != loop->end;
@@ -9692,8 +9648,8 @@ loop_regs_scan (loop, extra_size)
       if (GET_CODE (insn) == CALL_INSN)
        {
          rtx link;
-         for (link = CALL_INSN_FUNCTION_USAGE (insn); 
-              link; 
+         for (link = CALL_INSN_FUNCTION_USAGE (insn);
+              link;
               link = XEXP (link, 1))
            {
              rtx op, reg;
@@ -9737,8 +9693,7 @@ loop_regs_scan (loop, extra_size)
 /* Returns the number of real INSNs in the LOOP.  */
 
 static int
-count_insns_in_loop (loop)
-     const struct loop *loop;
+count_insns_in_loop (const struct loop *loop)
 {
   int count = 0;
   rtx insn;
@@ -9754,8 +9709,7 @@ count_insns_in_loop (loop)
 /* Move MEMs into registers for the duration of the loop.  */
 
 static void
-load_mems (loop)
-     const struct loop *loop;
+load_mems (const struct loop *loop)
 {
   struct loop_info *loop_info = LOOP_INFO (loop);
   struct loop_regs *regs = LOOP_REGS (loop);
@@ -9828,7 +9782,7 @@ load_mems (loop)
     ;
   prev_ebb_head = p;
 
-  cselib_init ();
+  cselib_init (true);
 
   /* Build table of mems that get set to constant values before the
      loop.  */
@@ -9969,7 +9923,7 @@ load_mems (loop)
              else
                /* Replace the memory reference with the shadow register.  */
                replace_loop_mems (p, loop_info->mems[i].mem,
-                                  loop_info->mems[i].reg);
+                                  loop_info->mems[i].reg, written);
            }
 
          if (GET_CODE (p) == CODE_LABEL
@@ -10084,28 +10038,12 @@ load_mems (loop)
        }
     }
 
+  /* Now, we need to replace all references to the previous exit
+     label with the new one.  */
   if (label != NULL_RTX && end_label != NULL_RTX)
-    {
-      /* Now, we need to replace all references to the previous exit
-        label with the new one.  */
-      rtx_pair rr;
-      rr.r1 = end_label;
-      rr.r2 = label;
-
-      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;
-       }
-    }
+    for (p = loop->start; p != loop->end; p = NEXT_INSN (p))
+      if (GET_CODE (p) == JUMP_INSN && JUMP_LABEL (p) == end_label)
+       redirect_jump (p, label, false);
 
   cselib_finish ();
 }
@@ -10120,9 +10058,7 @@ struct note_reg_stored_arg
 /* Called via note_stores, record in SET_SEEN whether X, which is written,
    is equal to ARG.  */
 static void
-note_reg_stored (x, setter, arg)
-     rtx x, setter ATTRIBUTE_UNUSED;
-     void *arg;
+note_reg_stored (rtx x, rtx setter ATTRIBUTE_UNUSED, void *arg)
 {
   struct note_reg_stored_arg *t = (struct note_reg_stored_arg *) arg;
   if (t->reg == x)
@@ -10135,10 +10071,7 @@ note_reg_stored (x, setter, arg)
    is not used after the loop.  */
 
 static void
-try_copy_prop (loop, replacement, regno)
-     const struct loop *loop;
-     rtx replacement;
-     unsigned int regno;
+try_copy_prop (const struct loop *loop, rtx replacement, unsigned int regno)
 {
   /* This is the reg that we are copying from.  */
   rtx reg_rtx = regno_reg_rtx[regno];
@@ -10235,9 +10168,7 @@ try_copy_prop (loop, replacement, regno)
    with NOTE_INSN_DELETED notes.  */
 
 static void
-loop_delete_insns (first, last)
-     rtx first;
-     rtx last;
+loop_delete_insns (rtx first, rtx last)
 {
   while (1)
     {
@@ -10261,10 +10192,8 @@ loop_delete_insns (first, last)
    this pseudo followed immediately by a move insn that sets
    REPLACEMENT with REGNO.  */
 static void
-try_swap_copy_prop (loop, replacement, regno)
-     const struct loop *loop;
-     rtx replacement;
-     unsigned int regno;
+try_swap_copy_prop (const struct loop *loop, rtx replacement,
+                   unsigned int regno)
 {
   rtx insn;
   rtx set = NULL_RTX;
@@ -10342,15 +10271,37 @@ 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 (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 (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
    and the MEM we are currently replacing.  */
 
 static int
-replace_loop_mem (mem, data)
-     rtx *mem;
-     void *data;
+replace_loop_mem (rtx *mem, void *data)
 {
   loop_replace_args *args = (loop_replace_args *) data;
   rtx m = *mem;
@@ -10384,10 +10335,7 @@ replace_loop_mem (mem, data)
 }
 
 static void
-replace_loop_mems (insn, mem, reg)
-     rtx insn;
-     rtx mem;
-     rtx reg;
+replace_loop_mems (rtx insn, rtx mem, rtx reg, int written)
 {
   loop_replace_args args;
 
@@ -10396,6 +10344,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
@@ -10403,9 +10371,7 @@ replace_loop_mems (insn, mem, reg)
    a structure of arguments.  */
 
 static int
-replace_loop_reg (px, data)
-     rtx *px;
-     void *data;
+replace_loop_reg (rtx *px, void *data)
 {
   rtx x = *px;
   loop_replace_args *args = (loop_replace_args *) data;
@@ -10420,10 +10386,7 @@ replace_loop_reg (px, data)
 }
 
 static void
-replace_loop_regs (insn, reg, replacement)
-     rtx insn;
-     rtx reg;
-     rtx replacement;
+replace_loop_regs (rtx insn, rtx reg, rtx replacement)
 {
   loop_replace_args args;
 
@@ -10433,45 +10396,14 @@ 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).  */
 
 static rtx
-loop_insn_emit_after (loop, where_bb, where_insn, pattern)
-     const struct loop *loop ATTRIBUTE_UNUSED;
-     basic_block where_bb ATTRIBUTE_UNUSED;
-     rtx where_insn;
-     rtx pattern;
+loop_insn_emit_after (const struct loop *loop ATTRIBUTE_UNUSED,
+                     basic_block where_bb ATTRIBUTE_UNUSED, rtx where_insn,
+                     rtx pattern)
 {
   return emit_insn_after (pattern, where_insn);
 }
@@ -10482,11 +10414,9 @@ loop_insn_emit_after (loop, where_bb, where_insn, pattern)
    otherwise hoist PATTERN into the loop pre-header.  */
 
 rtx
-loop_insn_emit_before (loop, where_bb, where_insn, pattern)
-     const struct loop *loop;
-     basic_block where_bb ATTRIBUTE_UNUSED;
-     rtx where_insn;
-     rtx pattern;
+loop_insn_emit_before (const struct loop *loop,
+                      basic_block where_bb ATTRIBUTE_UNUSED,
+                      rtx where_insn, rtx pattern)
 {
   if (! where_insn)
     return loop_insn_hoist (loop, pattern);
@@ -10498,11 +10428,9 @@ loop_insn_emit_before (loop, where_bb, where_insn, pattern)
    WHERE_BB (ignored in the interim) within the loop.  */
 
 static rtx
-loop_call_insn_emit_before (loop, where_bb, where_insn, pattern)
-     const struct loop *loop ATTRIBUTE_UNUSED;
-     basic_block where_bb ATTRIBUTE_UNUSED;
-     rtx where_insn;
-     rtx pattern;
+loop_call_insn_emit_before (const struct loop *loop ATTRIBUTE_UNUSED,
+                           basic_block where_bb ATTRIBUTE_UNUSED,
+                           rtx where_insn, rtx pattern)
 {
   return emit_call_insn_before (pattern, where_insn);
 }
@@ -10511,9 +10439,7 @@ loop_call_insn_emit_before (loop, where_bb, where_insn, pattern)
 /* Hoist insn for PATTERN into the loop pre-header.  */
 
 rtx
-loop_insn_hoist (loop, pattern)
-     const struct loop *loop;
-     rtx pattern;
+loop_insn_hoist (const struct loop *loop, rtx pattern)
 {
   return loop_insn_emit_before (loop, 0, loop->start, pattern);
 }
@@ -10522,9 +10448,7 @@ loop_insn_hoist (loop, pattern)
 /* Hoist call insn for PATTERN into the loop pre-header.  */
 
 static rtx
-loop_call_insn_hoist (loop, pattern)
-     const struct loop *loop;
-     rtx pattern;
+loop_call_insn_hoist (const struct loop *loop, rtx pattern)
 {
   return loop_call_insn_emit_before (loop, 0, loop->start, pattern);
 }
@@ -10533,18 +10457,15 @@ loop_call_insn_hoist (loop, pattern)
 /* Sink insn for PATTERN after the loop end.  */
 
 rtx
-loop_insn_sink (loop, pattern)
-     const struct loop *loop;
-     rtx pattern;
+loop_insn_sink (const struct loop *loop, rtx 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 intructions to load it into REG  */
+/* bl->final_value can be either 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;
+gen_load_of_final_value (rtx reg, rtx final_value)
 {
   rtx seq;
   start_sequence ();
@@ -10562,9 +10483,7 @@ gen_load_of_final_value (reg, final_value)
    since this is slightly more efficient.  */
 
 static rtx
-loop_insn_sink_or_swim (loop, pattern)
-     const struct loop *loop;
-     rtx pattern;
+loop_insn_sink_or_swim (const struct loop *loop, rtx pattern)
 {
   if (loop->exit_count)
     return loop_insn_hoist (loop, pattern);
@@ -10573,10 +10492,7 @@ loop_insn_sink_or_swim (loop, pattern)
 }
 \f
 static void
-loop_ivs_dump (loop, file, verbose)
-     const struct loop *loop;
-     FILE *file;
-     int verbose;
+loop_ivs_dump (const struct loop *loop, FILE *file, int verbose)
 {
   struct iv_class *bl;
   int iv_num = 0;
@@ -10598,10 +10514,8 @@ loop_ivs_dump (loop, file, verbose)
 
 
 static void
-loop_iv_class_dump (bl, file, verbose)
-     const struct iv_class *bl;
-     FILE *file;
-     int verbose ATTRIBUTE_UNUSED;
+loop_iv_class_dump (const struct iv_class *bl, FILE *file,
+                   int verbose ATTRIBUTE_UNUSED)
 {
   struct induction *v;
   rtx incr;
@@ -10663,10 +10577,7 @@ loop_iv_class_dump (bl, file, verbose)
 
 
 static void
-loop_biv_dump (v, file, verbose)
-     const struct induction *v;
-     FILE *file;
-     int verbose;
+loop_biv_dump (const struct induction *v, FILE *file, int verbose)
 {
   if (! v || ! file)
     return;
@@ -10689,10 +10600,7 @@ loop_biv_dump (v, file, verbose)
 
 
 static void
-loop_giv_dump (v, file, verbose)
-     const struct induction *v;
-     FILE *file;
-     int verbose;
+loop_giv_dump (const struct induction *v, FILE *file, int verbose)
 {
   if (! v || ! file)
     return;
@@ -10753,32 +10661,28 @@ loop_giv_dump (v, file, verbose)
 
 
 void
-debug_ivs (loop)
-     const struct loop *loop;
+debug_ivs (const struct loop *loop)
 {
   loop_ivs_dump (loop, stderr, 1);
 }
 
 
 void
-debug_iv_class (bl)
-     const struct iv_class *bl;
+debug_iv_class (const struct iv_class *bl)
 {
   loop_iv_class_dump (bl, stderr, 1);
 }
 
 
 void
-debug_biv (v)
-     const struct induction *v;
+debug_biv (const struct induction *v)
 {
   loop_biv_dump (v, stderr, 1);
 }
 
 
 void
-debug_giv (v)
-     const struct induction *v;
+debug_giv (const struct induction *v)
 {
   loop_giv_dump (v, stderr, 1);
 }
@@ -10797,10 +10701,8 @@ debug_giv (v)
 #define LOOP_INSN_UID(INSN) ((INSN) ? INSN_UID (INSN) : -1)
 
 static void
-loop_dump_aux (loop, file, verbose)
-     const struct loop *loop;
-     FILE *file;
-     int verbose ATTRIBUTE_UNUSED;
+loop_dump_aux (const struct loop *loop, FILE *file,
+              int verbose ATTRIBUTE_UNUSED)
 {
   rtx label;
 
@@ -10809,18 +10711,18 @@ loop_dump_aux (loop, file, verbose)
 
   /* Print diagnostics to compare our concept of a loop with
      what the loop notes say.  */
-  if (! PREV_INSN (loop->first->head)
-      || GET_CODE (PREV_INSN (loop->first->head)) != NOTE
-      || NOTE_LINE_NUMBER (PREV_INSN (loop->first->head))
+  if (! PREV_INSN (BB_HEAD (loop->first))
+      || GET_CODE (PREV_INSN (BB_HEAD (loop->first))) != NOTE
+      || NOTE_LINE_NUMBER (PREV_INSN (BB_HEAD (loop->first)))
       != NOTE_INSN_LOOP_BEG)
     fprintf (file, ";;  No NOTE_INSN_LOOP_BEG at %d\n",
-            INSN_UID (PREV_INSN (loop->first->head)));
-  if (! NEXT_INSN (loop->last->end)
-      || GET_CODE (NEXT_INSN (loop->last->end)) != NOTE
-      || NOTE_LINE_NUMBER (NEXT_INSN (loop->last->end))
+            INSN_UID (PREV_INSN (BB_HEAD (loop->first))));
+  if (! NEXT_INSN (BB_END (loop->last))
+      || GET_CODE (NEXT_INSN (BB_END (loop->last))) != NOTE
+      || NOTE_LINE_NUMBER (NEXT_INSN (BB_END (loop->last)))
       != NOTE_INSN_LOOP_END)
     fprintf (file, ";;  No NOTE_INSN_LOOP_END at %d\n",
-            INSN_UID (NEXT_INSN (loop->last->end)));
+            INSN_UID (NEXT_INSN (BB_END (loop->last))));
 
   if (loop->start)
     {
@@ -10864,8 +10766,7 @@ loop_dump_aux (loop, file, verbose)
 /* Call this function from the debugger to dump LOOP.  */
 
 void
-debug_loop (loop)
-     const struct loop *loop;
+debug_loop (const struct loop *loop)
 {
   flow_loop_dump (loop, stderr, loop_dump_aux, 1);
 }
@@ -10873,8 +10774,7 @@ debug_loop (loop)
 /* Call this function from the debugger to dump LOOPS.  */
 
 void
-debug_loops (loops)
-     const struct loops *loops;
+debug_loops (const struct loops *loops)
 {
   flow_loops_dump (loops, stderr, loop_dump_aux, 1);
 }