* loop.c (insert_bct): Ensure loop_iteration_var non-zero before use.
[gcc.git] / gcc / loop.c
index 86782d7292de245ca3b4f7d563d7dd3cadd2c27e..556877feff9dfb5351a3f29219a03f97e2afb8d4 100644 (file)
@@ -82,26 +82,11 @@ static rtx *loop_number_loop_starts, *loop_number_loop_ends;
 
 int *loop_outer_loop;
 
-#ifdef HAIFA
-/* The main output of analyze_loop_iterations is placed here */
-
-int *loop_can_insert_bct;
-
-/* For each loop, determines whether some of its inner loops has used
-   count register */
+#ifdef HAVE_decrement_and_branch_on_count
+/* Records whether resource in use by inner loop.  */
 
 int *loop_used_count_register;
-
-/* loop parameters for arithmetic loops. These loops have a loop variable
-   which is initialized to loop_start_value, incremented in each iteration
-   by "loop_increment".  At the end of the iteration the loop variable is
-   compared to the loop_comparison_value (using loop_comparison_code).  */
-
-rtx *loop_increment;
-rtx *loop_comparison_value;
-rtx *loop_start_value;
-enum rtx_code *loop_comparison_code;
-#endif  /* HAIFA */
+#endif  /* HAVE_decrement_and_branch_on_count */
 
 /* For each loop, keep track of its unrolling factor.
    Potential values:
@@ -168,18 +153,18 @@ static rtx loop_continue;
    Therefore, at all times, == 0 indicates an invariant register;
    < 0 a conditionally invariant one.  */
 
-static int *n_times_set;
+static varray_type n_times_set;
 
 /* Original value of n_times_set; same except that this value
    is not set negative for a reg whose sets have been made candidates
    and not set to 0 for a reg that is moved.  */
 
-static int *n_times_used;
+static varray_type n_times_used;
 
 /* Index by register number, 1 indicates that the register
    cannot be moved or strength reduced.  */
 
-static char *may_not_optimize;
+static varray_type may_not_optimize;
 
 /* Nonzero means reg N has already been moved out of one loop.
    This reduces the desire to move it out of another.  */
@@ -306,10 +291,13 @@ static int reg_in_basic_block_p PROTO((rtx, rtx));
 static int consec_sets_invariant_p PROTO((rtx, int, rtx));
 static rtx libcall_other_reg PROTO((rtx, rtx));
 static int labels_in_range_p PROTO((rtx, int));
-static void count_loop_regs_set PROTO((rtx, rtx, char *, rtx *, int *, int));
+static void count_one_set PROTO((rtx, rtx, varray_type, rtx *));
+
+static void count_loop_regs_set PROTO((rtx, rtx, varray_type, varray_type,
+                                      int *, int)); 
 static void note_addr_stored PROTO((rtx, rtx));
 static int loop_reg_used_before_p PROTO((rtx, rtx, rtx, rtx, rtx));
-static void scan_loop PROTO((rtx, rtx, int));
+static void scan_loop PROTO((rtx, rtx, int, int));
 #if 0
 static void replace_call_address PROTO((rtx, rtx, rtx));
 #endif
@@ -323,8 +311,8 @@ static int rtx_equal_for_loop_p PROTO((rtx, rtx, struct movable *));
 static void add_label_notes PROTO((rtx, rtx));
 static void move_movables PROTO((struct movable *, int, int, rtx, rtx, int));
 static int count_nonfixed_reads PROTO((rtx));
-static void strength_reduce PROTO((rtx, rtx, rtx, int, rtx, rtx, int));
-static void find_single_use_in_loop PROTO((rtx, rtx, rtx *));
+static void strength_reduce PROTO((rtx, rtx, rtx, int, rtx, rtx, int, int));
+static void find_single_use_in_loop PROTO((rtx, rtx, varray_type));
 static int valid_initial_value_p PROTO((rtx, rtx, int, rtx));
 static void find_mem_givs PROTO((rtx, rtx, int, rtx, rtx));
 static void record_biv PROTO((struct induction *, rtx, rtx, rtx, rtx, int, int));
@@ -348,7 +336,8 @@ static void record_initial PROTO((rtx, rtx));
 static void update_reg_last_use PROTO((rtx, rtx));
 static rtx next_insn_in_loop PROTO((rtx, rtx, rtx, rtx));
 static void load_mems_and_recount_loop_regs_set PROTO((rtx, rtx, rtx,
-                                                      rtx, rtx *, int *));
+                                                      rtx, varray_type, 
+                                                      int *));
 static void load_mems PROTO((rtx, rtx, rtx, rtx));
 static int insert_loop_mem PROTO((rtx *, void *));
 static int replace_loop_mem PROTO((rtx *, void *));
@@ -370,20 +359,13 @@ typedef struct rtx_pair {
    && INSN_LUID (INSN) >= INSN_LUID (START)    \
    && INSN_LUID (INSN) <= INSN_LUID (END))
 
-#ifdef HAIFA
-/* This is extern from unroll.c */
-extern void iteration_info PROTO((rtx, rtx *, rtx *, rtx, rtx));
-
-/* Two main functions for implementing bct:
-   first - to be called before loop unrolling, and the second - after */
 #ifdef HAVE_decrement_and_branch_on_count
-static void analyze_loop_iterations PROTO((rtx, rtx));
+/* Test whether BCT applicable and safe.  */
 static void insert_bct PROTO((rtx, rtx));
 
-/* Auxiliary function that inserts the bct pattern into the loop */
+/* Auxiliary function that inserts the BCT pattern into the loop.  */
 static void instrument_loop_bct PROTO((rtx, rtx, rtx));
 #endif /* HAVE_decrement_and_branch_on_count */
-#endif  /* HAIFA */
 
 /* Indirect_jump_in_function is computed once per function.  */
 int indirect_jump_in_function = 0;
@@ -438,11 +420,11 @@ init_loop ()
    (or 0 if none should be output).  */
 
 void
-loop_optimize (f, dumpfile, unroll_p)
+loop_optimize (f, dumpfile, unroll_p, bct_p)
      /* f is the first instruction of a chain of insns for one function */
      rtx f;
      FILE *dumpfile;
-     int unroll_p;
+     int unroll_p, bct_p;
 {
   register rtx insn;
   register int i;
@@ -498,25 +480,11 @@ loop_optimize (f, dumpfile, unroll_p)
   loop_unroll_factor = (int *) alloca (max_loop_num *sizeof (int));
   bzero ((char *) loop_unroll_factor, max_loop_num * sizeof (int));
 
-#ifdef HAIFA
+#ifdef HAVE_decrement_and_branch_on_count
   /* Allocate for BCT optimization */
-  loop_can_insert_bct = (int *) alloca (max_loop_num * sizeof (int));
-  bzero ((char *) loop_can_insert_bct, max_loop_num * sizeof (int));
-
   loop_used_count_register = (int *) alloca (max_loop_num * sizeof (int));
   bzero ((char *) loop_used_count_register, max_loop_num * sizeof (int));
-
-  loop_increment = (rtx *) alloca (max_loop_num * sizeof (rtx));
-  loop_comparison_value = (rtx *) alloca (max_loop_num * sizeof (rtx));
-  loop_start_value = (rtx *) alloca (max_loop_num * sizeof (rtx));
-  bzero ((char *) loop_increment, max_loop_num * sizeof (rtx));
-  bzero ((char *) loop_comparison_value, max_loop_num * sizeof (rtx));
-  bzero ((char *) loop_start_value, max_loop_num * sizeof (rtx));
-
-  loop_comparison_code 
-    = (enum rtx_code *) alloca (max_loop_num * sizeof (enum rtx_code));
-  bzero ((char *) loop_comparison_code, max_loop_num * sizeof (enum rtx_code));
-#endif  /* HAIFA */
+#endif  /* HAVE_decrement_and_branch_on_count */
 
   /* Find and process each loop.
      First, find them, and record them in order of their beginnings.  */
@@ -587,7 +555,7 @@ loop_optimize (f, dumpfile, unroll_p)
   for (i = max_loop_num-1; i >= 0; i--)
     if (! loop_invalid[i] && loop_number_loop_ends[i])
       scan_loop (loop_number_loop_starts[i], loop_number_loop_ends[i],
-                unroll_p);
+                unroll_p, bct_p);
 
   /* If debugging and unrolling loops, we must replicate the tree nodes
      corresponding to the blocks inside the loop, so that the original one
@@ -641,9 +609,9 @@ next_insn_in_loop (insn, start, end, loop_top)
    write, then we can also mark the memory read as invariant.  */
 
 static void
-scan_loop (loop_start, end, unroll_p)
+scan_loop (loop_start, end, unroll_p, bct_p)
      rtx loop_start, end;
-     int unroll_p;
+     int unroll_p, bct_p;
 {
   register int i;
   rtx p;
@@ -678,7 +646,7 @@ scan_loop (loop_start, end, unroll_p)
   /* If we have calls, contains the insn in which a register was used
      if it was used exactly once; contains const0_rtx if it was used more
      than once.  */
-  rtx *reg_single_usage = 0;
+  varray_type reg_single_usage = 0;
   /* Nonzero if we are scanning instructions in a sub-loop.  */
   int loop_depth = 0;
   int nregs;
@@ -757,31 +725,42 @@ scan_loop (loop_start, end, unroll_p)
     }
 
   /* Count number of times each reg is set during this loop.
-     Set may_not_optimize[I] if it is not safe to move out
+     Set VARRAY_CHAR (may_not_optimize, I) if it is not safe to move out
      the setting of register I.  If this loop has calls, set
-     reg_single_usage[I].  */
+     VARRAY_RTX (reg_single_usage, I).  */
   
   /* Allocate extra space for REGS that might be created by
-     load_mems.  */
-  nregs = max_reg_num () + loop_mems_idx;
-  n_times_set = (int *) alloca (nregs * sizeof (int));
-  n_times_used = (int *) alloca (nregs * sizeof (int));
-  may_not_optimize = (char *) alloca (nregs);
-  bzero ((char *) n_times_set, nregs * sizeof (int));
-  bzero (may_not_optimize, nregs);
+     load_mems.  We allocate a little extra slop as well, in the hopes
+     that even after the moving of movables creates some new registers
+     we won't have to reallocate these arrays.  However, we do grow
+     the arrays, if necessary, in load_mems_recount_loop_regs_set.  */
+  nregs = max_reg_num () + loop_mems_idx + 16;
+  VARRAY_INT_INIT (n_times_set, nregs, "n_times_set");
+  VARRAY_INT_INIT (n_times_used, nregs, "n_times_used");
+  VARRAY_CHAR_INIT (may_not_optimize, nregs, "may_not_optimize");
 
   if (loop_has_call)
-    {
-      reg_single_usage = (rtx *) alloca (nregs * sizeof (rtx));
-      bzero ((char *) reg_single_usage, nregs * sizeof (rtx));
-    }
+    VARRAY_RTX_INIT (reg_single_usage, nregs, "reg_single_usage");
 
   count_loop_regs_set (loop_top ? loop_top : loop_start, end,
                       may_not_optimize, reg_single_usage, &insn_count, nregs);
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    may_not_optimize[i] = 1, n_times_set[i] = 1;
-  bcopy ((char *) n_times_set, (char *) n_times_used, nregs * sizeof (int));
+    {
+      VARRAY_CHAR (may_not_optimize, i) = 1;
+      VARRAY_INT (n_times_set, i) = 1;
+    }
+
+#ifdef AVOID_CCMODE_COPIES
+  /* Don't try to move insns which set CC registers if we should not
+     create CCmode register copies.  */
+  for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
+    if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
+      VARRAY_CHAR (may_not_optimize, i) = 1;
+#endif
+
+  bcopy ((char *) &n_times_set->data, 
+        (char *) &n_times_used->data, nregs * sizeof (int));
 
   if (loop_dump_stream)
     {
@@ -819,7 +798,7 @@ scan_loop (loop_start, end, unroll_p)
       if (GET_CODE (p) == INSN
          && (set = single_set (p))
          && GET_CODE (SET_DEST (set)) == REG
-         && ! may_not_optimize[REGNO (SET_DEST (set))])
+         && ! VARRAY_CHAR (may_not_optimize, REGNO (SET_DEST (set))))
        {
          int tem1 = 0;
          int tem2 = 0;
@@ -858,28 +837,42 @@ scan_loop (loop_start, end, unroll_p)
             We don't know its life-span, so we can't compute the benefit.  */
          if (REGNO (SET_DEST (set)) >= max_reg_before_loop)
            ;
-         /* In order to move a register, we need to have one of three cases:
-            (1) it is used only in the same basic block as the set
-            (2) it is not a user variable and it is not used in the
-                exit test (this can cause the variable to be used
-                before it is set just like a user-variable).
-            (3) the set is guaranteed to be executed once the loop starts,
-                and the reg is not used until after that.  */
-         else if (! ((! maybe_never
-                      && ! loop_reg_used_before_p (set, p, loop_start,
-                                                   scan_start, end))
-                     || (! REG_USERVAR_P (SET_DEST (set))
-                         && ! REG_LOOP_TEST_P (SET_DEST (set)))
-                     || reg_in_basic_block_p (p, SET_DEST (set))))
+         else if (/* The set is a user-variable or it is used in
+                     the exit test (this can cause the variable to be
+                     used before it is set just like a
+                     user-variable)...  */
+                  (REG_USERVAR_P (SET_DEST (set))
+                   || REG_LOOP_TEST_P (SET_DEST (set)))
+                  /* And the set is not guaranteed to be executed one
+                     the loop starts, or the value before the set is
+                     needed before the set occurs... */
+                  && (maybe_never
+                      || loop_reg_used_before_p (set, p, loop_start,
+                                                 scan_start, end))
+                  /* And 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)))
+           /* It is unsafe to move the set.  The fact that these
+              three conditions are considered in conjunction means
+              that we are assuming various conditions, such as:
+
+                o It's OK to move a set of a variable which was not
+                  created by the user and is not used in an exit test
+                  even if that point in the set would not be reached
+                  during execution of the loop.  */
            ;
          else if ((tem = invariant_p (src))
                   && (dependencies == 0
                       || (tem2 = invariant_p (dependencies)) != 0)
-                  && (n_times_set[REGNO (SET_DEST (set))] == 1
+                  && (VARRAY_INT (n_times_set, 
+                                  REGNO (SET_DEST (set))) == 1
                       || (tem1
-                          = consec_sets_invariant_p (SET_DEST (set),
-                                                     n_times_set[REGNO (SET_DEST (set))],
-                                                     p)))
+                          = consec_sets_invariant_p 
+                          (SET_DEST (set),
+                           VARRAY_INT (n_times_set, REGNO (SET_DEST (set))),
+                           p)))
                   /* If the insn can cause a trap (such as divide by zero),
                      can't move it unless it's guaranteed to be executed
                      once loop is entered.  Even a function call might
@@ -905,12 +898,12 @@ scan_loop (loop_start, end, unroll_p)
                 Don't do this if P has a REG_RETVAL note or if we have
                 SMALL_REGISTER_CLASSES and SET_SRC is a hard register.  */
 
-             if (reg_single_usage && reg_single_usage[regno] != 0
-                 && reg_single_usage[regno] != const0_rtx
+             if (reg_single_usage && VARRAY_RTX (reg_single_usage, regno) != 0
+                 && VARRAY_RTX (reg_single_usage, regno) != const0_rtx
                  && REGNO_FIRST_UID (regno) == INSN_UID (p)
                  && (REGNO_LAST_UID (regno)
-                     == INSN_UID (reg_single_usage[regno]))
-                 && n_times_set[REGNO (SET_DEST (set))] == 1
+                     == INSN_UID (VARRAY_RTX (reg_single_usage, regno)))
+                 && VARRAY_INT (n_times_set, regno) == 1
                  && ! side_effects_p (SET_SRC (set))
                  && ! find_reg_note (p, REG_RETVAL, NULL_RTX)
                  && (! SMALL_REGISTER_CLASSES
@@ -920,22 +913,25 @@ scan_loop (loop_start, end, unroll_p)
                     a call-clobbered register and the life of REGNO
                     might span a call.  */
                  && ! modified_between_p (SET_SRC (set), p,
-                                          reg_single_usage[regno])
-                 && no_labels_between_p (p, reg_single_usage[regno])
+                                          VARRAY_RTX
+                                          (reg_single_usage, regno)) 
+                 && no_labels_between_p (p, VARRAY_RTX (reg_single_usage, regno))
                  && validate_replace_rtx (SET_DEST (set), SET_SRC (set),
-                                          reg_single_usage[regno]))
+                                          VARRAY_RTX
+                                          (reg_single_usage, regno))) 
                {
                  /* Replace any usage in a REG_EQUAL note.  Must copy the
                     new source, so that we don't get rtx sharing between the
                     SET_SOURCE and REG_NOTES of insn p.  */
-                 REG_NOTES (reg_single_usage[regno])
-                   = replace_rtx (REG_NOTES (reg_single_usage[regno]),
+                 REG_NOTES (VARRAY_RTX (reg_single_usage, regno))
+                   = replace_rtx (REG_NOTES (VARRAY_RTX
+                                             (reg_single_usage, regno)), 
                                   SET_DEST (set), copy_rtx (SET_SRC (set)));
                                   
                  PUT_CODE (p, NOTE);
                  NOTE_LINE_NUMBER (p) = NOTE_INSN_DELETED;
                  NOTE_SOURCE_FILE (p) = 0;
-                 n_times_set[regno] = 0;
+                 VARRAY_INT (n_times_set, regno) = 0;
                  continue;
                }
 
@@ -946,7 +942,8 @@ scan_loop (loop_start, end, unroll_p)
              m->dependencies = dependencies;
              m->set_dest = SET_DEST (set);
              m->force = 0;
-             m->consec = n_times_set[REGNO (SET_DEST (set))] - 1;
+             m->consec = VARRAY_INT (n_times_set, 
+                                     REGNO (SET_DEST (set))) - 1;
              m->done = 0;
              m->forces = 0;
              m->partial = 0;
@@ -963,10 +960,10 @@ scan_loop (loop_start, end, unroll_p)
              m->match = 0;
              m->lifetime = (uid_luid[REGNO_LAST_UID (regno)]
                             - uid_luid[REGNO_FIRST_UID (regno)]);
-             m->savings = n_times_used[regno];
+             m->savings = VARRAY_INT (n_times_used, regno);
              if (find_reg_note (p, REG_RETVAL, NULL_RTX))
                m->savings += libcall_benefit (p);
-             n_times_set[regno] = move_insn ? -2 : -1;
+             VARRAY_INT (n_times_set, regno) = move_insn ? -2 : -1;
              /* Add M to the end of the chain MOVABLES.  */
              if (movables == 0)
                movables = m;
@@ -1025,7 +1022,7 @@ scan_loop (loop_start, end, unroll_p)
                   && !reg_mentioned_p (SET_DEST (set), SET_SRC (set1)))
            {
              register int regno = REGNO (SET_DEST (set));
-             if (n_times_set[regno] == 2)
+             if (VARRAY_INT (n_times_set, regno) == 2)
                {
                  register struct movable *m;
                  m = (struct movable *) alloca (sizeof (struct movable));
@@ -1075,7 +1072,7 @@ scan_loop (loop_start, end, unroll_p)
                  m->lifetime = (uid_luid[REGNO_LAST_UID (regno)]
                                 - uid_luid[REGNO_FIRST_UID (regno)]);
                  m->savings = 1;
-                 n_times_set[regno] = -1;
+                 VARRAY_INT (n_times_set, regno) = -1;
                  /* Add M to the end of the chain MOVABLES.  */
                  if (movables == 0)
                    movables = m;
@@ -1152,8 +1149,8 @@ scan_loop (loop_start, end, unroll_p)
   /* Now candidates that still are negative are those not moved.
      Change n_times_set to indicate that those are not actually invariant.  */
   for (i = 0; i < nregs; i++)
-    if (n_times_set[i] < 0)
-      n_times_set[i] = n_times_used[i];
+    if (VARRAY_INT (n_times_set, i) < 0)
+      VARRAY_INT (n_times_set, i) = VARRAY_INT (n_times_used, i);
 
   /* Now that we've moved some things out of the loop, we able to
      hoist even more memory references.  There's no need to pass
@@ -1166,8 +1163,13 @@ scan_loop (loop_start, end, unroll_p)
     {
       the_movables = movables;
       strength_reduce (scan_start, end, loop_top,
-                      insn_count, loop_start, end, unroll_p);
+                      insn_count, loop_start, end, unroll_p, bct_p);
     }
+
+  VARRAY_FREE (n_times_set);
+  VARRAY_FREE (n_times_used);
+  VARRAY_FREE (may_not_optimize);
+  VARRAY_FREE (reg_single_usage);
 }
 \f
 /* Add elements to *OUTPUT to record all the pseudo-regs
@@ -1441,7 +1443,7 @@ combine_movables (movables, nregs)
   /* Perhaps testing m->consec_sets would be more appropriate here?  */
 
   for (m = movables; m; m = m->next)
-    if (m->match == 0 && n_times_used[m->regno] == 1 && !m->partial)
+    if (m->match == 0 && VARRAY_INT (n_times_used, m->regno) == 1 && !m->partial)
       {
        register struct movable *m1;
        int regno = m->regno;
@@ -1452,7 +1454,7 @@ combine_movables (movables, nregs)
        /* We want later insns to match the first one.  Don't make the first
           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 && n_times_used[m1->regno] == 1
+         if (m != m1 && m1->match == 0 && VARRAY_INT (n_times_used, m1->regno) == 1
              /* A reg used outside the loop mustn't be eliminated.  */
              && !m1->global
              /* A reg used for zero-extending mustn't be eliminated.  */
@@ -1589,7 +1591,7 @@ rtx_equal_for_loop_p (x, y, movables)
 
   /* If we have a register and a constant, they may sometimes be
      equal.  */
-  if (GET_CODE (x) == REG && n_times_set[REGNO (x)] == -2
+  if (GET_CODE (x) == REG && VARRAY_INT (n_times_set, REGNO (x)) == -2
       && CONSTANT_P (y))
     {
       for (m = movables; m; m = m->next)
@@ -1597,7 +1599,7 @@ rtx_equal_for_loop_p (x, y, movables)
            && rtx_equal_p (m->set_src, y))
          return 1;
     }
-  else if (GET_CODE (y) == REG && n_times_set[REGNO (y)] == -2
+  else if (GET_CODE (y) == REG && VARRAY_INT (n_times_set, REGNO (y)) == -2
           && CONSTANT_P (x))
     {
       for (m = movables; m; m = m->next)
@@ -1803,13 +1805,8 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
          if (loop_dump_stream)
            fprintf (loop_dump_stream, "savings %d ", savings);
 
-         if (moved_once[regno])
-           {
-             insn_count *= 2;
-
-             if (loop_dump_stream)
-               fprintf (loop_dump_stream, "halved since already moved ");
-           }
+         if (moved_once[regno] && loop_dump_stream)
+           fprintf (loop_dump_stream, "halved since already moved ");
 
          /* An insn MUST be moved if we already moved something else
             which is safe only if this one is moved too: that is,
@@ -1826,9 +1823,10 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
 
          if (already_moved[regno]
              || flag_move_all_movables
-             || (threshold * savings * m->lifetime) >= insn_count
+             || (threshold * savings * m->lifetime) >=
+                (moved_once[regno] ? insn_count * 2 : insn_count)
              || (m->forces && m->forces->done
-                 && n_times_used[m->forces->regno] == 1))
+                 && VARRAY_INT (n_times_used, m->forces->regno) == 1))
            {
              int count;
              register struct movable *m1;
@@ -1892,9 +1890,17 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
                            temp = delete_insn (temp);
                        }
 
+                     temp = p;
                      p = delete_insn (p);
+
+                     /* simplify_giv_expr expects that it can walk the insns
+                        at m->insn forwards and see this old sequence we are
+                        tossing here.  delete_insn does preserve the next
+                        pointers, but when we skip over a NOTE we must fix
+                        it up.  Otherwise that code walks into the non-deleted
+                        insn stream.  */
                      while (p && GET_CODE (p) == NOTE)
-                       p = NEXT_INSN (p);
+                       p = NEXT_INSN (temp) = NEXT_INSN (p);
                    }
 
                  start_sequence ();
@@ -2101,9 +2107,18 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
                          XEXP (temp, 0) = i1;
                        }
 
+                     temp = p;
                      delete_insn (p);
-                     do p = NEXT_INSN (p);
-                     while (p && GET_CODE (p) == NOTE);
+                     p = NEXT_INSN (p);
+
+                     /* simplify_giv_expr expects that it can walk the insns
+                        at m->insn forwards and see this old sequence we are
+                        tossing here.  delete_insn does preserve the next
+                        pointers, but when we skip over a NOTE we must fix
+                        it up.  Otherwise that code walks into the non-deleted
+                        insn stream.  */
+                     while (p && GET_CODE (p) == NOTE)
+                       p = NEXT_INSN (temp) = NEXT_INSN (p);
                    }
 
                  /* The more regs we move, the less we like moving them.  */
@@ -2119,7 +2134,7 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
 
              /* The reg set here is now invariant.  */
              if (! m->partial)
-               n_times_set[regno] = 0;
+               VARRAY_INT (n_times_set, regno) = 0;
 
              m->done = 1;
 
@@ -2176,7 +2191,7 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
                      /* The reg merged here is now invariant,
                         if the reg it matches is invariant.  */
                      if (! m->partial)
-                       n_times_set[m1->regno] = 0;
+                       VARRAY_INT (n_times_set, m1->regno) = 0;
                    }
            }
          else if (loop_dump_stream)
@@ -2940,10 +2955,10 @@ mark_loop_jump (x, loop_num)
 
       if (loop_num != -1)
        {
-#ifdef HAIFA
+#ifdef HAVE_decrement_and_branch_on_count
          LABEL_OUTSIDE_LOOP_P (x) = 1;
          LABEL_NEXTREF (x) = loop_number_exit_labels[loop_num];
-#endif  /* HAIFA */
+#endif  /* HAVE_decrement_and_branch_on_count */
 
          loop_number_exit_labels[loop_num] = x;
 
@@ -3078,10 +3093,10 @@ invariant_p (x)
          && REGNO (x) < FIRST_PSEUDO_REGISTER && call_used_regs[REGNO (x)])
        return 0;
 
-      if (n_times_set[REGNO (x)] < 0)
+      if (VARRAY_INT (n_times_set, REGNO (x)) < 0)
        return 2;
 
-      return n_times_set[REGNO (x)] == 0;
+      return VARRAY_INT (n_times_set, REGNO (x)) == 0;
 
     case MEM:
       /* Volatile memory references must be rejected.  Do this before
@@ -3169,7 +3184,7 @@ consec_sets_invariant_p (reg, n_sets, insn)
   rtx temp;
   /* Number of sets we have to insist on finding after INSN.  */
   int count = n_sets - 1;
-  int old = n_times_set[regno];
+  int old = VARRAY_INT (n_times_set, regno);
   int value = 0;
   int this;
 
@@ -3177,7 +3192,7 @@ consec_sets_invariant_p (reg, n_sets, insn)
   if (n_sets == 127)
     return 0;
 
-  n_times_set[regno] = 0;
+  VARRAY_INT (n_times_set, regno) = 0;
 
   while (count > 0)
     {
@@ -3216,12 +3231,12 @@ consec_sets_invariant_p (reg, n_sets, insn)
        count--;
       else if (code != NOTE)
        {
-         n_times_set[regno] = old;
+         VARRAY_INT (n_times_set, regno) = old;
          return 0;
        }
     }
 
-  n_times_set[regno] = old;
+  VARRAY_INT (n_times_set, regno) = old;
   /* If invariant_p ever returned 2, we return 2.  */
   return 1 + (value & 2);
 }
@@ -3267,15 +3282,16 @@ static void
 find_single_use_in_loop (insn, x, usage)
      rtx insn;
      rtx x;
-     rtx *usage;
+     varray_type usage;
 {
   enum rtx_code code = GET_CODE (x);
   char *fmt = GET_RTX_FORMAT (code);
   int i, j;
 
   if (code == REG)
-    usage[REGNO (x)]
-      = (usage[REGNO (x)] != 0 && usage[REGNO (x)] != insn)
+    VARRAY_RTX (usage, REGNO (x))
+      = (VARRAY_RTX (usage, REGNO (x)) != 0 
+        && VARRAY_RTX (usage, REGNO (x)) != insn)
        ? const0_rtx : insn;
 
   else if (code == SET)
@@ -3299,6 +3315,51 @@ find_single_use_in_loop (insn, x, usage)
       }
 }
 \f
+/* Count and record any set in X which is contained in INSN.  Update
+   MAY_NOT_MOVE and LAST_SET for any register set in X.  */
+
+static void
+count_one_set (insn, x, may_not_move, last_set)
+     rtx insn, x;
+     varray_type may_not_move;
+     rtx *last_set;
+{
+  if (GET_CODE (x) == CLOBBER && GET_CODE (XEXP (x, 0)) == REG)
+    /* Don't move a reg that has an explicit clobber.
+       It's not worth the pain to try to do it correctly.  */
+    VARRAY_CHAR (may_not_move, REGNO (XEXP (x, 0))) = 1;
+
+  if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
+    {
+      rtx dest = SET_DEST (x);
+      while (GET_CODE (dest) == SUBREG
+            || GET_CODE (dest) == ZERO_EXTRACT
+            || GET_CODE (dest) == SIGN_EXTRACT
+            || GET_CODE (dest) == STRICT_LOW_PART)
+       dest = XEXP (dest, 0);
+      if (GET_CODE (dest) == REG)
+       {
+         register int regno = REGNO (dest);
+         /* If this is the first setting of this reg
+            in current basic block, and it was set before,
+            it must be set in two basic blocks, so it cannot
+            be moved out of the loop.  */
+         if (VARRAY_INT (n_times_set, regno) > 0 
+             && last_set[regno] == 0)
+           VARRAY_CHAR (may_not_move, regno) = 1;
+         /* If this is not first setting in current basic block,
+            see if reg was used in between previous one and this.
+            If so, neither one can be moved.  */
+         if (last_set[regno] != 0
+             && reg_used_between_p (dest, last_set[regno], insn))
+           VARRAY_CHAR (may_not_move, regno) = 1;
+         if (VARRAY_INT (n_times_set, regno) < 127)
+           ++VARRAY_INT (n_times_set, regno);
+         last_set[regno] = insn;
+       }
+    }
+}
+
 /* Increment N_TIMES_SET at the index of each register
    that is modified by an insn between FROM and TO.
    If the value of an element of N_TIMES_SET becomes 127 or more,
@@ -3318,8 +3379,8 @@ find_single_use_in_loop (insn, x, usage)
 static void
 count_loop_regs_set (from, to, may_not_move, single_usage, count_ptr, nregs)
      register rtx from, to;
-     char *may_not_move;
-     rtx *single_usage;
+     varray_type may_not_move;
+     varray_type single_usage;
      int *count_ptr;
      int nregs;
 {
@@ -3345,74 +3406,15 @@ count_loop_regs_set (from, to, may_not_move, single_usage, count_ptr, nregs)
                find_single_use_in_loop (insn, REG_NOTES (insn), single_usage);
            }
 
-         if (GET_CODE (PATTERN (insn)) == CLOBBER
-             && GET_CODE (XEXP (PATTERN (insn), 0)) == REG)
-           /* Don't move a reg that has an explicit clobber.
-              We might do so sometimes, but it's not worth the pain.  */
-           may_not_move[REGNO (XEXP (PATTERN (insn), 0))] = 1;
-
          if (GET_CODE (PATTERN (insn)) == SET
              || GET_CODE (PATTERN (insn)) == CLOBBER)
-           {
-             dest = SET_DEST (PATTERN (insn));
-             while (GET_CODE (dest) == SUBREG
-                    || GET_CODE (dest) == ZERO_EXTRACT
-                    || GET_CODE (dest) == SIGN_EXTRACT
-                    || GET_CODE (dest) == STRICT_LOW_PART)
-               dest = XEXP (dest, 0);
-             if (GET_CODE (dest) == REG)
-               {
-                 register int regno = REGNO (dest);
-                 /* If this is the first setting of this reg
-                    in current basic block, and it was set before,
-                    it must be set in two basic blocks, so it cannot
-                    be moved out of the loop.  */
-                 if (n_times_set[regno] > 0 && last_set[regno] == 0)
-                   may_not_move[regno] = 1;
-                 /* If this is not first setting in current basic block,
-                    see if reg was used in between previous one and this.
-                    If so, neither one can be moved.  */
-                 if (last_set[regno] != 0
-                     && reg_used_between_p (dest, last_set[regno], insn))
-                   may_not_move[regno] = 1;
-                 if (n_times_set[regno] < 127)
-                   ++n_times_set[regno];
-                 last_set[regno] = insn;
-               }
-           }
+           count_one_set (insn, PATTERN (insn), may_not_move, last_set);
          else if (GET_CODE (PATTERN (insn)) == PARALLEL)
            {
              register int i;
              for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
-               {
-                 register rtx x = XVECEXP (PATTERN (insn), 0, i);
-                 if (GET_CODE (x) == CLOBBER && GET_CODE (XEXP (x, 0)) == REG)
-                   /* Don't move a reg that has an explicit clobber.
-                      It's not worth the pain to try to do it correctly.  */
-                   may_not_move[REGNO (XEXP (x, 0))] = 1;
-
-                 if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
-                   {
-                     dest = SET_DEST (x);
-                     while (GET_CODE (dest) == SUBREG
-                            || GET_CODE (dest) == ZERO_EXTRACT
-                            || GET_CODE (dest) == SIGN_EXTRACT
-                            || GET_CODE (dest) == STRICT_LOW_PART)
-                       dest = XEXP (dest, 0);
-                     if (GET_CODE (dest) == REG)
-                       {
-                         register int regno = REGNO (dest);
-                         if (n_times_set[regno] > 0 && last_set[regno] == 0)
-                           may_not_move[regno] = 1;
-                         if (last_set[regno] != 0
-                             && reg_used_between_p (dest, last_set[regno], insn))
-                           may_not_move[regno] = 1;
-                         if (n_times_set[regno] < 127)
-                           ++n_times_set[regno];
-                         last_set[regno] = insn;
-                       }
-                   }
-               }
+               count_one_set (insn, XVECEXP (PATTERN (insn), 0, i),
+                              may_not_move, last_set);
            }
        }
 
@@ -3535,14 +3537,14 @@ static rtx addr_placeholder;
 
 static void
 strength_reduce (scan_start, end, loop_top, insn_count,
-                loop_start, loop_end, unroll_p)
+                loop_start, loop_end, unroll_p, bct_p)
      rtx scan_start;
      rtx end;
      rtx loop_top;
      int insn_count;
      rtx loop_start;
      rtx loop_end;
-     int unroll_p;
+     int unroll_p, bct_p;
 {
   rtx p;
   rtx set;
@@ -3736,7 +3738,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
       if (reg_iv_type[bl->regno] != BASIC_INDUCT
          /* Above happens if register modified by subreg, etc.  */
          /* Make sure it is not recognized as a basic induction var: */
-         || n_times_set[bl->regno] != bl->biv_count
+         || VARRAY_INT (n_times_set, bl->regno) != bl->biv_count
          /* If never incremented, it is invariant that we decided not to
             move.  So leave it alone.  */
          || ! bl->incremented)
@@ -3897,7 +3899,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
       if (GET_CODE (p) == INSN
          && (set = single_set (p))
          && GET_CODE (SET_DEST (set)) == REG
-         && ! may_not_optimize[REGNO (SET_DEST (set))])
+         && ! VARRAY_CHAR (may_not_optimize, REGNO (SET_DEST (set))))
        {
          rtx src_reg;
          rtx add_val;
@@ -3923,7 +3925,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
              /* Don't recognize a BASIC_INDUCT_VAR here.  */
              && dest_reg != src_reg
              /* This must be the only place where the register is set.  */
-             && (n_times_set[REGNO (dest_reg)] == 1
+             && (VARRAY_INT (n_times_set, REGNO (dest_reg)) == 1
                  /* or all sets must be consecutive and make a giv.  */
                  || (benefit = consec_sets_giv (benefit, p,
                                                 src_reg, dest_reg,
@@ -3939,7 +3941,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
                benefit += libcall_benefit (p);
 
              /* Skip the consecutive insns, if there are any.  */
-             for (count = n_times_set[REGNO (dest_reg)] - 1;
+             for (count = VARRAY_INT (n_times_set, REGNO (dest_reg)) - 1;
                   count > 0; count--)
                {
                  /* If first insn of libcall sequence, skip to end.
@@ -4057,16 +4059,6 @@ strength_reduce (scan_start, end, loop_top, insn_count,
      so that "decrement and branch until zero" insn can be used.  */
   check_dbra_loop (loop_end, insn_count, loop_start);
 
-#ifdef HAIFA
-  /* record loop-variables relevant for BCT optimization before unrolling
-     the loop.  Unrolling may update part of this information, and the
-     correct data will be used for generating the BCT.  */
-#ifdef HAVE_decrement_and_branch_on_count
-  if (HAVE_decrement_and_branch_on_count)
-    analyze_loop_iterations (loop_start, loop_end);
-#endif
-#endif  /* HAIFA */
-
   /* Create reg_map to hold substitutions for replaceable giv regs.  */
   reg_map = (rtx *) alloca (max_reg_before_loop * sizeof (rtx));
   bzero ((char *) reg_map, max_reg_before_loop * sizeof (rtx));
@@ -4566,13 +4558,12 @@ strength_reduce (scan_start, end, loop_top, insn_count,
   if (unroll_p)
     unroll_loop (loop_end, insn_count, loop_start, end_insert_before, 1);
 
-#ifdef HAIFA
-  /* instrument the loop with bct insn */
 #ifdef HAVE_decrement_and_branch_on_count
-  if (HAVE_decrement_and_branch_on_count)
+  /* Instrument the loop with BCT insn.  */
+  if (HAVE_decrement_and_branch_on_count && bct_p
+      && flag_branch_on_count_reg)
     insert_bct (loop_start, loop_end);
-#endif
-#endif  /* HAIFA */
+#endif  /* HAVE_decrement_and_branch_on_count */
 
   if (loop_dump_stream)
     fprintf (loop_dump_stream, "\n");
@@ -4881,7 +4872,7 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
       v->lifetime = (uid_luid[REGNO_LAST_UID (REGNO (dest_reg))]
                     - uid_luid[REGNO_FIRST_UID (REGNO (dest_reg))]);
 
-      v->times_used = n_times_used[REGNO (dest_reg)];
+      v->times_used = VARRAY_INT (n_times_used, REGNO (dest_reg));
 
       /* If the lifetime is zero, it means that this register is
         really a dead store.  So mark this as a giv that can be
@@ -6041,7 +6032,7 @@ consec_sets_giv (first_benefit, p, src_reg, dest_reg,
   reg_iv_type[REGNO (dest_reg)] = GENERAL_INDUCT;
   reg_iv_info[REGNO (dest_reg)] = v;
 
-  count = n_times_set[REGNO (dest_reg)] - 1;
+  count = VARRAY_INT (n_times_set, REGNO (dest_reg)) - 1;
 
   while (count > 0)
     {
@@ -6243,10 +6234,10 @@ express_from (g1, g2)
     return gen_rtx_PLUS (g2->mode, mult, add);
 }
 \f
-/* Return 1 if giv G2 can be combined with G1.  This means that G2 can use
-   (either directly or via an address expression) a register used to represent
-   G1.  Set g2->new_reg to a represtation of G1 (normally just
-   g1->dest_reg).  */
+/* Return an rtx, if any, that expresses giv G2 as a function of the register
+   represented by G1.  This indicates that G2 should be combined with G1 and
+   that G2 can use (either directly or via an address expression) a register
+   used to represent G1.  */
 
 static rtx
 combine_givs_p (g1, g2)
@@ -6257,7 +6248,7 @@ combine_givs_p (g1, g2)
   /* If these givs are identical, they can be combined.  We use the results
      of express_from because the addends are not in a canonical form, so
      rtx_equal_p is a weaker test.  */
-  if (tem == const0_rtx)
+  if (tem == g1->dest_reg)
     {
       return g1->dest_reg;
     }
@@ -6313,12 +6304,12 @@ combine_givs_used_once (g1, g2)
      struct induction *g1, *g2;
 {
   if (g1->giv_type == DEST_REG
-      && n_times_used[REGNO (g1->dest_reg)] == 1
+      && VARRAY_INT (n_times_used, REGNO (g1->dest_reg)) == 1
       && reg_mentioned_p (g1->dest_reg, PATTERN (g2->insn)))
     return -1;
 
   if (g2->giv_type == DEST_REG
-      && n_times_used[REGNO (g2->dest_reg)] == 1
+      && VARRAY_INT (n_times_used, REGNO (g2->dest_reg)) == 1
       && reg_mentioned_p (g2->dest_reg, PATTERN (g1->insn)))
     return 1;
 
@@ -6750,7 +6741,7 @@ check_dbra_loop (loop_end, insn_count, loop_start)
            }
        }
     }
-  else if (num_mem_sets <= 1)
+  else if (INTVAL (bl->biv->add_val) > 0)
     {
       /* Try to change inc to dec, so can apply above optimization.  */
       /* Can do this if:
@@ -6770,10 +6761,6 @@ check_dbra_loop (loop_end, insn_count, loop_start)
         which is reversible.  */
       int reversible_mem_store = 1;
 
-      for (p = loop_start; p != loop_end; p = NEXT_INSN (p))
-       if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
-         num_nonfixed_reads += count_nonfixed_reads (PATTERN (p));
-
       if (bl->giv_count == 0
          && ! loop_number_exit_count[uid_loop_num[INSN_UID (loop_start)]])
        {
@@ -6797,7 +6784,6 @@ check_dbra_loop (loop_end, insn_count, loop_start)
                  /* Don't bother about the end test.  */
                  ;
                else if (reg_mentioned_p (bivreg, PATTERN (p)))
-                 /* Any other use of the biv is no good.  */
                  {
                    no_use_except_counting = 0;
                    break;
@@ -6805,31 +6791,44 @@ check_dbra_loop (loop_end, insn_count, loop_start)
              }
        }
 
-      /* If the loop has a single store, and the destination address is
-        invariant, then we can't reverse the loop, because this address
-        might then have the wrong value at loop exit.
-        This would work if the source was invariant also, however, in that
-        case, the insn should have been moved out of the loop.  */
-
-      if (num_mem_sets == 1)
-       reversible_mem_store
-         = (! unknown_address_altered
-            && ! invariant_p (XEXP (loop_store_mems[0], 0)));
+      if (no_use_except_counting)
+       ; /* no need to worry about MEMs.  */
+      else if (num_mem_sets <= 1)
+       {
+         for (p = loop_start; p != loop_end; p = NEXT_INSN (p))
+           if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
+             num_nonfixed_reads += count_nonfixed_reads (PATTERN (p));
+
+         /* If the loop has a single store, and the destination address is
+            invariant, then we can't reverse the loop, because this address
+            might then have the wrong value at loop exit.
+            This would work if the source was invariant also, however, in that
+            case, the insn should have been moved out of the loop.  */
+
+         if (num_mem_sets == 1)
+           reversible_mem_store
+             = (! unknown_address_altered
+                && ! invariant_p (XEXP (loop_store_mems[0], 0)));
+       }
+      else
+       return 0;
 
       /* This code only acts for innermost loops.  Also it simplifies
         the memory address check by only reversing loops with
         zero or one memory access.
         Two memory accesses could involve parts of the same array,
-        and that can't be reversed.  */
-
-      if (num_nonfixed_reads <= 1
-         && !loop_has_call
-         && !loop_has_volatile
-         && reversible_mem_store
-         && (no_use_except_counting
-             || ((bl->giv_count + bl->biv_count + num_mem_sets
-                  + num_movables + compare_and_branch == insn_count)
-                 && (bl == loop_iv_list && bl->next == 0))))
+        and that can't be reversed.
+        If the biv is used only for counting, than we don't need to worry
+        about all these things.  */
+
+      if ((num_nonfixed_reads <= 1
+          && !loop_has_call
+          && !loop_has_volatile
+          && reversible_mem_store
+          && (bl->giv_count + bl->biv_count + num_mem_sets
+             + num_movables + compare_and_branch == insn_count)
+          && (bl == loop_iv_list && bl->next == 0))
+         || no_use_except_counting)
        {
          rtx tem;
 
@@ -6847,46 +6846,146 @@ check_dbra_loop (loop_end, insn_count, loop_start)
             confusing.  */
 
          if (comparison
-             && GET_CODE (XEXP (comparison, 1)) == CONST_INT
-             /* LE gets turned into LT */
-             && GET_CODE (comparison) == LT
-             && GET_CODE (bl->initial_value) == CONST_INT)
+             /* for constants, LE gets turned into LT */
+             && (GET_CODE (comparison) == LT
+                 || (GET_CODE (comparison) == LE
+                     && no_use_except_counting)))
            {
-             HOST_WIDE_INT add_val, comparison_val;
-             rtx initial_value;
+             HOST_WIDE_INT add_val, add_adjust, comparison_val;
+             rtx initial_value, comparison_value;
+             int nonneg = 0;
+             enum rtx_code cmp_code;
+             int comparison_const_width;
+             unsigned HOST_WIDE_INT comparison_sign_mask;
+             rtx vtop;
 
              add_val = INTVAL (bl->biv->add_val);
-             comparison_val = INTVAL (XEXP (comparison, 1));
-             final_value = XEXP (comparison, 1);
+             comparison_value = XEXP (comparison, 1);
+             comparison_const_width
+               = GET_MODE_BITSIZE (GET_MODE (XEXP (comparison, 1)));
+             if (comparison_const_width > HOST_BITS_PER_WIDE_INT)
+               comparison_const_width = HOST_BITS_PER_WIDE_INT;
+             comparison_sign_mask
+               = (unsigned HOST_WIDE_INT)1 << (comparison_const_width - 1);
+
+             /* If the comparison value is not a loop invariant, then we
+                can not reverse this loop.
+
+                ??? If the insns which initialize the comparison value as
+                a whole compute an invariant result, then we could move
+                them out of the loop and proceed with loop reversal.  */
+             if (!invariant_p (comparison_value))
+               return 0;
+
+             if (GET_CODE (comparison_value) == CONST_INT)
+               comparison_val = INTVAL (comparison_value);
              initial_value = bl->initial_value;
                
              /* Normalize the initial value if it is an integer and 
                 has no other use except as a counter.  This will allow
                 a few more loops to be reversed.  */
              if (no_use_except_counting
+                 && GET_CODE (comparison_value) == CONST_INT
                  && GET_CODE (initial_value) == CONST_INT)
                {
                  comparison_val = comparison_val - INTVAL (bl->initial_value);
-                 /* Check for overflow.  If comparison_val ends up as a
-                    negative value, then we can't reverse the loop.  */
-                 if (comparison_val >= 0)
-                   initial_value = const0_rtx;
+                 /* The code below requires comparison_val to be a multiple
+                    of add_val in order to do the loop reversal, so
+                    round up comparison_val to a multiple of add_val.
+                    Since comparison_value is constant, we know that the
+                    current comparison code is LT.  */
+                 comparison_val = comparison_val + add_val - 1;
+                 comparison_val
+                   -= (unsigned HOST_WIDE_INT) comparison_val % add_val;
+                 /* We postpone overflow checks for COMPARISON_VAL here;
+                    even if there is an overflow, we might still be able to
+                    reverse the loop, if converting the loop exit test to
+                    NE is possible.  */
+                 initial_value = const0_rtx;
                }
 
+             /* Check if there is a NOTE_INSN_LOOP_VTOP note.  If there is,
+                that means that this is a for or while style loop, with
+                a loop exit test at the start.  Thus, we can assume that
+                the loop condition was true when the loop was entered.
+                This allows us to change the loop exit condition to an
+                equality test.
+                We start at the end and search backwards for the previous
+                NOTE.  If there is no NOTE_INSN_LOOP_VTOP for this loop,
+                the search will stop at the NOTE_INSN_LOOP_CONT.  */
+             vtop = loop_end;
+             do
+               vtop = PREV_INSN (vtop);
+             while (GET_CODE (vtop) != NOTE
+                    || NOTE_LINE_NUMBER (vtop) > 0
+                    || NOTE_LINE_NUMBER (vtop) == NOTE_REPEATED_LINE_NUMBER
+                    || NOTE_LINE_NUMBER (vtop) == NOTE_INSN_DELETED);
+             if (NOTE_LINE_NUMBER (vtop) != NOTE_INSN_LOOP_VTOP)
+               vtop = NULL_RTX;
+               
+             /* First check if we can do a vanilla loop reversal.  */
+             if (initial_value == const0_rtx
+                 /* If we have a decrement_and_branch_on_count, prefer
+                    the NE test, since this will allow that instruction to
+                    be generated.  Note that we must use a vanilla loop
+                    reversal if the biv is used to calculate a giv or has
+                    a non-counting use.  */
+#if ! defined (HAVE_decrement_and_branch_until_zero) && defined (HAVE_decrement_and_branch_on_count)
+                 && (! (add_val == 1 && vtop
+                        && (bl->biv_count == 0
+                            || no_use_except_counting)))
+#endif
+                 && GET_CODE (comparison_value) == CONST_INT
+                    /* Now do postponed overflow checks on COMPARISON_VAL.  */
+                 && ! (((comparison_val - add_val) ^ INTVAL (comparison_value))
+                       & comparison_sign_mask))
+               {
+                 /* Register will always be nonnegative, with value
+                    0 on last iteration */
+                 add_adjust = add_val;
+                 nonneg = 1;
+                 cmp_code = GE;
+               }
+             else if (add_val == 1 && vtop
+                      && (bl->biv_count == 0
+                          || no_use_except_counting))
+               {
+                 add_adjust = 0;
+                 cmp_code = NE;
+               }
+             else
+               return 0;
+
+             if (GET_CODE (comparison) == LE)
+               add_adjust -= add_val;
+
              /* If the initial value is not zero, or if the comparison
                 value is not an exact multiple of the increment, then we
                 can not reverse this loop.  */
-             if (initial_value != const0_rtx
-                 || (comparison_val % add_val) != 0)
-               return 0;
+             if (initial_value == const0_rtx
+                 && GET_CODE (comparison_value) == CONST_INT)
+               {
+                 if (((unsigned HOST_WIDE_INT) comparison_val % add_val) != 0)
+                   return 0;
+               }
+             else
+               {
+                 if (! no_use_except_counting || add_val != 1)
+                   return 0;
+               }
+
+             final_value = comparison_value;
 
              /* Reset these in case we normalized the initial value
                 and comparison value above.  */
+             if (GET_CODE (comparison_value) == CONST_INT
+                 && GET_CODE (initial_value) == CONST_INT)
+               {
+                 comparison_value = GEN_INT (comparison_val);
+                 final_value
+                   = GEN_INT (comparison_val + INTVAL (bl->initial_value));
+               }
              bl->initial_value = initial_value;
-             XEXP (comparison, 1) = GEN_INT (comparison_val);
-
-             /* Register will always be nonnegative, with value
-                0 on last iteration if loop reversed */
 
              /* Save some info needed to produce the new insns.  */
              reg = bl->biv->dest_reg;
@@ -6895,13 +6994,59 @@ check_dbra_loop (loop_end, insn_count, loop_start)
                jump_label = XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 2);
              new_add_val = GEN_INT (- INTVAL (bl->biv->add_val));
 
-             start_value = GEN_INT (INTVAL (XEXP (comparison, 1))
-                                    - INTVAL (bl->biv->add_val));
-
-             /* Initialize biv to start_value before loop start.
+             /* Set start_value; if this is not a CONST_INT, we need
+                to generate a SUB.
+                Initialize biv to start_value before loop start.
                 The old initializing insn will be deleted as a
                 dead store by flow.c.  */
-             emit_insn_before (gen_move_insn (reg, start_value), loop_start);
+             if (initial_value == const0_rtx
+                 && GET_CODE (comparison_value) == CONST_INT)
+               {
+                 start_value = GEN_INT (comparison_val - add_adjust);
+                 emit_insn_before (gen_move_insn (reg, start_value),
+                                   loop_start);
+               }
+             else if (GET_CODE (initial_value) == CONST_INT)
+               {
+                 rtx offset = GEN_INT (-INTVAL (initial_value) - add_adjust);
+                 enum machine_mode mode = GET_MODE (reg);
+                 enum insn_code icode
+                   = add_optab->handlers[(int) mode].insn_code;
+                 if (! (*insn_operand_predicate[icode][0]) (reg, mode)
+                     || ! ((*insn_operand_predicate[icode][1])
+                           (comparison_value, mode))
+                     || ! (*insn_operand_predicate[icode][2]) (offset, mode))
+                   return 0;
+                 start_value
+                   = gen_rtx_PLUS (mode, comparison_value, offset);
+                 emit_insn_before ((GEN_FCN (icode)
+                                    (reg, comparison_value, offset)),
+                                   loop_start);
+                 if (GET_CODE (comparison) == LE)
+                   final_value = gen_rtx_PLUS (mode, comparison_value,
+                                               GEN_INT (add_val));
+               }
+             else if (! add_adjust)
+               {
+                 enum machine_mode mode = GET_MODE (reg);
+                 enum insn_code icode
+                   = sub_optab->handlers[(int) mode].insn_code;
+                 if (! (*insn_operand_predicate[icode][0]) (reg, mode)
+                     || ! ((*insn_operand_predicate[icode][1])
+                           (comparison_value, mode))
+                     || ! ((*insn_operand_predicate[icode][2])
+                           (initial_value, mode)))
+                   return 0;
+                 start_value
+                   = gen_rtx_MINUS (mode, comparison_value, initial_value);
+                 emit_insn_before ((GEN_FCN (icode)
+                                    (reg, comparison_value, initial_value)),
+                                   loop_start);
+               }
+             else
+               /* We could handle the other cases too, but it'll be
+                  better to have a testcase first.  */
+               return 0;
 
              /* Add insn to decrement register, and delete insn
                 that incremented the register.  */
@@ -6933,29 +7078,33 @@ check_dbra_loop (loop_end, insn_count, loop_start)
 
              /* Add new compare/branch insn at end of loop.  */
              start_sequence ();
-             emit_cmp_insn (reg, const0_rtx, GE, NULL_RTX,
+             emit_cmp_insn (reg, const0_rtx, cmp_code, NULL_RTX,
                             GET_MODE (reg), 0, 0);
-             emit_jump_insn (gen_bge (XEXP (jump_label, 0)));
+             emit_jump_insn ((*bcc_gen_fctn[(int) cmp_code])
+                             (XEXP (jump_label, 0)));
              tem = gen_sequence ();
              end_sequence ();
              emit_jump_insn_before (tem, loop_end);
 
-             for (tem = PREV_INSN (loop_end);
-                  tem && GET_CODE (tem) != JUMP_INSN; tem = PREV_INSN (tem))
-               ;
-             if (tem)
+             if (nonneg)
                {
-                 JUMP_LABEL (tem) = XEXP (jump_label, 0);
+                 for (tem = PREV_INSN (loop_end);
+                      tem && GET_CODE (tem) != JUMP_INSN;
+                      tem = PREV_INSN (tem))
+                   ;
+                 if (tem)
+                   {
+                     JUMP_LABEL (tem) = XEXP (jump_label, 0);
 
-                 /* Increment of LABEL_NUSES done above.  */
-                 /* Register is now always nonnegative,
-                    so add REG_NONNEG note to the branch.  */
-                 REG_NOTES (tem) = gen_rtx_EXPR_LIST (REG_NONNEG, NULL_RTX,
-                                                      REG_NOTES (tem));
+                     /* Increment of LABEL_NUSES done above.  */
+                     /* Register is now always nonnegative,
+                        so add REG_NONNEG note to the branch.  */
+                     REG_NOTES (tem) = gen_rtx_EXPR_LIST (REG_NONNEG, NULL_RTX,
+                                                          REG_NOTES (tem));
+                   }
+                 bl->nonneg = 1;
                }
 
-             bl->nonneg = 1;
-
              /* Mark that this biv has been reversed.  Each giv which depends
                 on this biv, and which is also live past the end of the loop
                 will have to be fixed up.  */
@@ -7616,7 +7765,14 @@ get_condition (jump, earliest)
             like Alpha that have an IEEE compliant EQ instruction, and
             a non-IEEE compliant BEQ instruction.  The use of CCmode is
             actually artificial, simply to prevent the combination, but
-            should not affect other platforms.  */
+            should not affect other platforms.
+
+            However, we must allow VOIDmode comparisons to match either
+            CCmode or non-CCmode comparison, because some ports have
+            modeless comparisons inside branch patterns.
+
+            ??? This mode check should perhaps look more like the mode check
+            in simplify_comparison in combine.  */
 
          if ((GET_CODE (SET_SRC (set)) == COMPARE
               || (((code == NE
@@ -7634,8 +7790,9 @@ get_condition (jump, earliest)
 #endif
                     ))
                   && GET_RTX_CLASS (GET_CODE (SET_SRC (set))) == '<'))
-             && ((GET_MODE_CLASS (mode) == MODE_CC)
-                 != (GET_MODE_CLASS (inner_mode) == MODE_CC)))
+             && (((GET_MODE_CLASS (mode) == MODE_CC)
+                  == (GET_MODE_CLASS (inner_mode) == MODE_CC))
+                 || mode == VOIDmode || inner_mode == VOIDmode))
            x = SET_SRC (set);
          else if (((code == EQ
                     || (code == GE
@@ -7652,8 +7809,10 @@ get_condition (jump, earliest)
 #endif
                     ))
                   && GET_RTX_CLASS (GET_CODE (SET_SRC (set))) == '<'
-                  && ((GET_MODE_CLASS (mode) == MODE_CC)
-                      != (GET_MODE_CLASS (inner_mode) == MODE_CC)))
+                  && (((GET_MODE_CLASS (mode) == MODE_CC)
+                       == (GET_MODE_CLASS (inner_mode) == MODE_CC))
+                      || mode == VOIDmode || inner_mode == VOIDmode))
+
            {
              /* We might have reversed a LT to get a GE here.  But this wasn't
                 actually the comparison of data, so we don't flag that we
@@ -7775,529 +7934,290 @@ get_condition_for_loop (x)
                         XEXP (comparison, 1), XEXP (comparison, 0));
 }
 
-#ifdef HAIFA
-/* Analyze a loop in order to instrument it with the use of count register.
-   loop_start and loop_end are the first and last insns of the loop.
-   This function works in cooperation with insert_bct ().
-   loop_can_insert_bct[loop_num] is set according to whether the optimization
-   is applicable to the loop.  When it is applicable, the following variables
-   are also set:
-    loop_start_value[loop_num]
-    loop_comparison_value[loop_num]
-    loop_increment[loop_num]
-    loop_comparison_code[loop_num] */
-
 #ifdef HAVE_decrement_and_branch_on_count
+/* Instrument loop for insertion of bct instruction.  We distinguish between
+   loops with compile-time bounds and those with run-time bounds. 
+   Information from loop_iterations() is used to compute compile-time bounds.
+   Run-time bounds should use loop preconditioning, but currently ignored.
+ */
+
 static void
-analyze_loop_iterations (loop_start, loop_end)
-  rtx loop_start, loop_end;
+insert_bct (loop_start, loop_end)
+     rtx loop_start, loop_end;
 {
-  rtx comparison, comparison_value;
-  rtx iteration_var, initial_value, increment;
-  enum rtx_code comparison_code;
-
-  rtx last_loop_insn;
-  rtx insn;
   int i;
+  unsigned HOST_WIDE_INT n_iterations;
+  rtx insn;
 
-  /* loop_variable mode */
-  enum machine_mode original_mode;
-
-  /* find the number of the loop */
-  int loop_num = uid_loop_num [INSN_UID (loop_start)];
-
-  /* we change our mind only when we are sure that loop will be instrumented */
-  loop_can_insert_bct[loop_num] = 0;
-
-  /* is the optimization suppressed.  */
-  if ( !flag_branch_on_count_reg )
-    return;
-
-  /* make sure that count-reg is not in use */
-  if (loop_used_count_register[loop_num]){
-    if (loop_dump_stream)
-      fprintf (loop_dump_stream,
-             "analyze_loop_iterations %d: BCT instrumentation failed: count register already in use\n",
-             loop_num);
-    return;
-  }
-
-  /* make sure that the function has no indirect jumps.  */
-  if (indirect_jump_in_function){
-    if (loop_dump_stream)
-      fprintf (loop_dump_stream,
-              "analyze_loop_iterations %d: BCT instrumentation failed: indirect jump in function\n",
-             loop_num);
-    return;
-  }
-
-  /* make sure that the last loop insn is a conditional jump */
-  last_loop_insn = PREV_INSN (loop_end);
-  if (GET_CODE (last_loop_insn) != JUMP_INSN || !condjump_p (last_loop_insn)) {
-    if (loop_dump_stream)
-      fprintf (loop_dump_stream,
-              "analyze_loop_iterations %d: BCT instrumentation failed: invalid jump at loop end\n",
-             loop_num);
-    return;
-  }
-
-  /* First find the iteration variable.  If the last insn is a conditional
-     branch, and the insn preceding it tests a register value, make that
-     register the iteration variable.  */
+  int increment_direction, compare_direction;
 
-  /* We used to use prev_nonnote_insn here, but that fails because it might
-     accidentally get the branch for a contained loop if the branch for this
-     loop was deleted.  We can only trust branches immediately before the
-     loop_end.  */
+  /* If the loop condition is <= or >=, the number of iteration
+      is 1 more than the range of the bounds of the loop.  */
+  int add_iteration = 0;
 
-  comparison = get_condition_for_loop (last_loop_insn);
-  /* ??? Get_condition may switch position of induction variable and
-     invariant register when it canonicalizes the comparison.  */
+  enum machine_mode loop_var_mode = word_mode;
 
-  if (comparison == 0) {
-    if (loop_dump_stream)
-      fprintf (loop_dump_stream,
-             "analyze_loop_iterations %d: BCT instrumentation failed: comparison not found\n",
-             loop_num);
-    return;
-  }
-
-  comparison_code = GET_CODE (comparison);
-  iteration_var = XEXP (comparison, 0);
-  comparison_value = XEXP (comparison, 1);
+  int loop_num = uid_loop_num [INSN_UID (loop_start)];
 
-  original_mode = GET_MODE (iteration_var);
-  if (GET_MODE_CLASS (original_mode) != MODE_INT
-      || GET_MODE_SIZE (original_mode) != UNITS_PER_WORD) {
-    if (loop_dump_stream)
-      fprintf (loop_dump_stream,
-             "analyze_loop_iterations %d: BCT Instrumentation failed: loop variable not integer\n",
-             loop_num);
+  /* It's impossible to instrument a competely unrolled loop.  */
+  if (loop_unroll_factor [loop_num] == -1)
     return;
-  }
 
-  /* get info about loop bounds and increment */
-  iteration_info (iteration_var, &initial_value, &increment,
-                 loop_start, loop_end);
-
-  /* make sure that all required loop data were found */
-  if (!(initial_value && increment && comparison_value
-       && invariant_p (comparison_value) && invariant_p (increment)
-       && ! indirect_jump_in_function))
+  /* Make sure that the count register is not in use.  */
+  if (loop_used_count_register [loop_num])
     {
-      if (loop_dump_stream) {
+      if (loop_dump_stream)
        fprintf (loop_dump_stream,
-                "analyze_loop_iterations %d: BCT instrumentation failed because of wrong loop: ", loop_num);
-       if (!(initial_value && increment && comparison_value)) {
-         fprintf (loop_dump_stream, "\tbounds not available: ");
-         if ( ! initial_value )
-           fprintf (loop_dump_stream, "initial ");
-         if ( ! increment )
-           fprintf (loop_dump_stream, "increment ");
-         if ( ! comparison_value )
-           fprintf (loop_dump_stream, "comparison ");
-         fprintf (loop_dump_stream, "\n");
-       }
-       if (!invariant_p (comparison_value) || !invariant_p (increment))
-         fprintf (loop_dump_stream, "\tloop bounds not invariant\n");
-      }
+                "insert_bct %d: BCT instrumentation failed: count register already in use\n",
+                loop_num);
       return;
     }
 
-  /* make sure that the increment is constant */
-  if (GET_CODE (increment) != CONST_INT) {
-    if (loop_dump_stream)
-      fprintf (loop_dump_stream,
-              "analyze_loop_iterations %d: instrumentation failed: not arithmetic loop\n",
-             loop_num);
-    return;
-  }
-
-  /* make sure that the loop contains neither function call, nor jump on table.
-     (the count register might be altered by the called function, and might
-     be used for a branch on table).  */
-  for (insn = loop_start; insn && insn != loop_end; insn = NEXT_INSN (insn)) {
-    if (GET_CODE (insn) == CALL_INSN){
+  /* Make sure that the function has no indirect jumps.  */
+  if (indirect_jump_in_function)
+    {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
-                "analyze_loop_iterations %d: BCT instrumentation failed: function call in the loop\n",
-               loop_num);
+                "insert_bct %d: BCT instrumentation failed: indirect jump in function\n",
+                loop_num);
       return;
     }
 
-    if (GET_CODE (insn) == JUMP_INSN
-       && (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
-          || GET_CODE (PATTERN (insn)) == ADDR_VEC)){
+  /* Make sure that the last loop insn is a conditional jump.  */
+  if (GET_CODE (PREV_INSN (loop_end)) != JUMP_INSN
+      || ! condjump_p (PREV_INSN (loop_end))
+      || simplejump_p (PREV_INSN (loop_end)))
+    {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
-                "analyze_loop_iterations %d: BCT instrumentation failed: computed branch in the loop\n",
-               loop_num);
+                "insert_bct %d: BCT instrumentation failed: invalid jump at loop end\n",
+                loop_num);
       return;
     }
-  }
-
-  /* At this point, we are sure that the loop can be instrumented with BCT.
-     Some of the loops, however, will not be instrumented - the final decision
-     is taken by insert_bct () */
-  if (loop_dump_stream)
-    fprintf (loop_dump_stream,
-            "analyze_loop_iterations: loop (luid =%d) can be BCT instrumented.\n",
-           loop_num);
-
-  /* mark all enclosing loops that they cannot use count register */
-  /* ???: In fact, since insert_bct may decide not to instrument this loop,
-     marking here may prevent instrumenting an enclosing loop that could
-    actually be instrumented.  But since this is rare, it is safer to mark
-    here in case the order of calling  (analyze/insert)_bct would be changed.  */
-  for (i=loop_num; i != -1; i = loop_outer_loop[i])
-    loop_used_count_register[i] = 1;
-
-  /* Set data structures which will be used by the instrumentation phase */
-  loop_start_value[loop_num] = initial_value;
-  loop_comparison_value[loop_num] = comparison_value;
-  loop_increment[loop_num] = increment;
-  loop_comparison_code[loop_num] = comparison_code;
-  loop_can_insert_bct[loop_num] = 1;
-}
 
-
-/* instrument loop for insertion of bct instruction.  We distinguish between
- loops with compile-time bounds, to those with run-time bounds.  The loop
- behaviour is analized according to the following characteristics/variables:
- ; Input variables:
- ;   comparison-value: the value to which the iteration counter is compared.
- ;   initial-value: iteration-counter initial value.
- ;   increment: iteration-counter increment.
- ; Computed variables:
- ;   increment-direction: the sign of the increment.
- ;   compare-direction: '1' for GT, GTE, '-1' for LT, LTE, '0' for NE.
- ;   range-direction: sign (comparison-value - initial-value)
- We give up on the following cases:
- ; loop variable overflow.
- ; run-time loop bounds with comparison code NE.
- */
-
-static void
-insert_bct (loop_start, loop_end)
-     rtx loop_start, loop_end;
-{
-  rtx initial_value, comparison_value, increment;
-  enum rtx_code comparison_code;
-
-  int increment_direction, compare_direction;
-  int unsigned_p = 0;
-
-  /* if the loop condition is <= or >=, the number of iteration
-      is 1 more than the range of the bounds of the loop */
-  int add_iteration = 0;
-
-  /* the only machine mode we work with - is the integer of the size that the
-     machine has */
-  enum machine_mode loop_var_mode = SImode;
-
-  int loop_num = uid_loop_num [INSN_UID (loop_start)];
-
-  /* get loop-variables. No need to check that these are valid - already
-     checked in analyze_loop_iterations ().  */
-  comparison_code = loop_comparison_code[loop_num];
-  initial_value = loop_start_value[loop_num];
-  comparison_value = loop_comparison_value[loop_num];
-  increment = loop_increment[loop_num];
-
-  /* check analyze_loop_iterations decision for this loop.  */
-  if (! loop_can_insert_bct[loop_num]){
-    if (loop_dump_stream)
-      fprintf (loop_dump_stream,
-             "insert_bct: [%d] - was decided not to instrument by analyze_loop_iterations ()\n",
-             loop_num);
-    return;
-  }
-
-  /* It's impossible to instrument a competely unrolled loop.  */
-  if (loop_unroll_factor [loop_num] == -1)
-    return;
-
-  /* make sure that the last loop insn is a conditional jump .
-     This check is repeated from analyze_loop_iterations (),
-     because unrolling might have changed that.  */
-  if (GET_CODE (PREV_INSN (loop_end)) != JUMP_INSN
-      || !condjump_p (PREV_INSN (loop_end))) {
-    if (loop_dump_stream)
-      fprintf (loop_dump_stream,
-             "insert_bct: not instrumenting BCT because of invalid branch\n");
-    return;
-  }
-
-  /* fix increment in case loop was unrolled.  */
-  if (loop_unroll_factor [loop_num] > 1)
-    increment = GEN_INT ( INTVAL (increment) * loop_unroll_factor [loop_num] );
-
-  /* determine properties and directions of the loop */
-  increment_direction = (INTVAL (increment) > 0) ? 1:-1;
-  switch ( comparison_code ) {
-  case LEU:
-    unsigned_p = 1;
-    /* fallthrough */
-  case LE:
-    compare_direction = 1;
-    add_iteration = 1;
-    break;
-  case GEU:
-    unsigned_p = 1;
-    /* fallthrough */
-  case GE:
-    compare_direction = -1;
-    add_iteration = 1;
-    break;
-  case EQ:
-    /* in this case we cannot know the number of iterations */
-    if (loop_dump_stream)
-      fprintf (loop_dump_stream,
-              "insert_bct: %d: loop cannot be instrumented: == in condition\n",
-             loop_num);
-    return;
-  case LTU:
-    unsigned_p = 1;
-    /* fallthrough */
-  case LT:
-    compare_direction = 1;
-    break;
-  case GTU:
-    unsigned_p = 1;
-    /* fallthrough */
-  case GT:
-    compare_direction = -1;
-    break;
-  case NE:
-    compare_direction = 0;
-    break;
-  default:
-    abort ();
-  }
-
-
-  /* make sure that the loop does not end by an overflow */
-  if (compare_direction != increment_direction) {
-    if (loop_dump_stream)
-      fprintf (loop_dump_stream,
-              "insert_bct: %d: loop cannot be instrumented: terminated by overflow\n",
-             loop_num);
-    return;
-  }
-
-  /* try to instrument the loop.  */
-
-  /* Handle the simpler case, where the bounds are known at compile time.  */
-  if (GET_CODE (initial_value) == CONST_INT && GET_CODE (comparison_value) == CONST_INT)
+  /* Make sure that the loop does not contain a function call
+     (the count register might be altered by the called function).  */
+  if (loop_has_call)
     {
-      int n_iterations;
-      int increment_value_abs = INTVAL (increment) * increment_direction;
-
-      /* check the relation between compare-val and initial-val */
-      int difference = INTVAL (comparison_value) - INTVAL (initial_value);
-      int range_direction = (difference > 0) ? 1 : -1;
-
-      /* make sure the loop executes enough iterations to gain from BCT */
-      if (difference > -3 && difference < 3) {
-       if (loop_dump_stream)
-         fprintf (loop_dump_stream,
-                 "insert_bct: loop %d not BCT instrumented: too small iteration count.\n",
-                 loop_num);
-       return;
-      }
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "insert_bct %d: BCT instrumentation failed: function call in loop\n",
+                loop_num);
+      return;
+    }
 
-      /* make sure that the loop executes at least once */
-      if ((range_direction ==  1 && compare_direction == -1)
-         || (range_direction == -1 && compare_direction ==  1))
+  /* Make sure that the loop does not jump via a table.
+     (the count register might be used to perform the branch on table).  */
+  for (insn = loop_start; insn && insn != loop_end; insn = NEXT_INSN (insn))
+    {
+      if (GET_CODE (insn) == JUMP_INSN
+         && (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
+             || GET_CODE (PATTERN (insn)) == ADDR_VEC))
        {
          if (loop_dump_stream)
            fprintf (loop_dump_stream,
-                   "insert_bct: loop %d: does not iterate even once. Not instrumenting.\n",
-                   loop_num);
+                    "insert_bct %d: BCT instrumentation failed: computed branch in the loop\n",
+                    loop_num);
          return;
        }
+    }
 
-      /* make sure that the loop does not end by an overflow (in compile time
-         bounds we must have an additional check for overflow, because here
-         we also support the compare code of 'NE'.  */
-      if (comparison_code == NE
-         && increment_direction != range_direction) {
-       if (loop_dump_stream)
-         fprintf (loop_dump_stream,
-                 "insert_bct (compile time bounds): %d: loop not instrumented: terminated by overflow\n",
-                 loop_num);
-       return;
-      }
+  /* Account for loop unrolling in instrumented iteration count.  */
+  if (loop_unroll_factor [loop_num] > 1)
+    n_iterations = loop_n_iterations / loop_unroll_factor [loop_num];
+  else
+    n_iterations = loop_n_iterations;
 
-      /* Determine the number of iterations by:
-        ;
-         ;                  compare-val - initial-val + (increment -1) + additional-iteration
-         ; num_iterations = -----------------------------------------------------------------
-         ;                                           increment
-        */
-      difference = (range_direction > 0) ? difference : -difference;
-#if 0
-      fprintf (stderr, "difference is: %d\n", difference); /* @*/
-      fprintf (stderr, "increment_value_abs is: %d\n", increment_value_abs); /* @*/
-      fprintf (stderr, "add_iteration is: %d\n", add_iteration); /* @*/
-      fprintf (stderr, "INTVAL (comparison_value) is: %d\n", INTVAL (comparison_value)); /* @*/
-      fprintf (stderr, "INTVAL (initial_value) is: %d\n", INTVAL (initial_value)); /* @*/
-#endif
+  if (n_iterations != 0 && n_iterations < 3)
+    {
+      /* Allow an enclosing outer loop to benefit if possible.  */
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "insert_bct %d: Too few iterations to benefit from BCT optimization\n",
+                loop_num);
+      return;
+    }
 
-      if (increment_value_abs == 0) {
-       fprintf (stderr, "insert_bct: error: increment == 0 !!!\n");
-       abort ();
-      }
-      n_iterations = (difference + increment_value_abs - 1 + add_iteration)
-       / increment_value_abs;
+  /* Try to instrument the loop.  */
 
-#if 0
-      fprintf (stderr, "number of iterations is: %d\n", n_iterations); /* @*/
-#endif
+  /* Handle the simpler case, where the bounds are known at compile time.  */
+  if (n_iterations > 0)
+    {
+      /* Mark all enclosing loops that they cannot use count register.  */
+      for (i=loop_num; i != -1; i = loop_outer_loop[i])
+       loop_used_count_register[i] = 1;
       instrument_loop_bct (loop_start, loop_end, GEN_INT (n_iterations));
+      return;
+    }
+
+  /* Handle the more complex case, that the bounds are NOT known
+     at compile time.  In this case we generate run_time calculation
+     of the number of iterations.  */
 
-      /* Done with this loop.  */
+  if (loop_iteration_var == 0)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "insert_bct %d: BCT Runtime Instrumentation failed: no loop iteration variable found\n",
+                loop_num);
       return;
     }
 
-  /* Handle the more complex case, that the bounds are NOT known at compile time.  */
-  /* In this case we generate run_time calculation of the number of iterations */
+  if (GET_MODE_CLASS (GET_MODE (loop_iteration_var)) != MODE_INT
+      || GET_MODE_SIZE (GET_MODE (loop_iteration_var)) != UNITS_PER_WORD)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "insert_bct %d: BCT Runtime Instrumentation failed: loop variable not integer\n",
+                loop_num);
+      return;
+    }
 
   /* With runtime bounds, if the compare is of the form '!=' we give up */
-  if (comparison_code == NE) {
-    if (loop_dump_stream)
-      fprintf (loop_dump_stream,
-             "insert_bct: fail for loop %d: runtime bounds with != comparison\n",
-             loop_num);
-    return;
-  }
+  if (loop_comparison_code == NE)
+    {
+      if (loop_dump_stream)
+       fprintf (loop_dump_stream,
+                "insert_bct %d: BCT Runtime Instrumentation failed: runtime bounds with != comparison\n",
+                loop_num);
+      return;
+    }
+/* Use common loop preconditioning code instead.  */
+#if 0
+  else
+    {
+      /* We rely on the existence of run-time guard to ensure that the
+        loop executes at least once.  */
+      rtx sequence;
+      rtx iterations_num_reg;
 
-  else {
-    /* We rely on the existence of run-time guard to ensure that the
-       loop executes at least once.  */
-    rtx sequence;
-    rtx iterations_num_reg;
+      unsigned HOST_WIDE_INT increment_value_abs
+       = INTVAL (increment) * increment_direction;
 
-    int increment_value_abs = INTVAL (increment) * increment_direction;
+      /* make sure that the increment is a power of two, otherwise (an
+        expensive) divide is needed.  */
+      if (exact_log2 (increment_value_abs) == -1)
+       {
+         if (loop_dump_stream)
+           fprintf (loop_dump_stream,
+                    "insert_bct: not instrumenting BCT because the increment is not power of 2\n");
+         return;
+       }
 
-    /* make sure that the increment is a power of two, otherwise (an
-       expensive) divide is needed.  */
-    if (exact_log2 (increment_value_abs) == -1)
+      /* compute the number of iterations */
+      start_sequence ();
       {
-       if (loop_dump_stream)
-         fprintf (loop_dump_stream,
-                 "insert_bct: not instrumenting BCT because the increment is not power of 2\n");
-       return;
-      }
+       rtx temp_reg;
 
-    /* compute the number of iterations */
-    start_sequence ();
-    {
-      rtx temp_reg;
-
-      /* Again, the number of iterations is calculated by:
-        ;
-         ;                  compare-val - initial-val + (increment -1) + additional-iteration
-         ; num_iterations = -----------------------------------------------------------------
-         ;                                           increment
+       /* Again, the number of iterations is calculated by:
+          ;
+          ;                  compare-val - initial-val + (increment -1) + additional-iteration
+          ; num_iterations = -----------------------------------------------------------------
+          ;                                           increment
         */
-      /* ??? Do we have to call copy_rtx here before passing rtx to
-        expand_binop?  */
-      if (compare_direction > 0) {
-       /* <, <= :the loop variable is increasing */
-       temp_reg = expand_binop (loop_var_mode, sub_optab, comparison_value,
-                                initial_value, NULL_RTX, 0, OPTAB_LIB_WIDEN);
-      }
-      else {
-       temp_reg = expand_binop (loop_var_mode, sub_optab, initial_value,
-                                comparison_value, NULL_RTX, 0, OPTAB_LIB_WIDEN);
-      }
+       /* ??? Do we have to call copy_rtx here before passing rtx to
+          expand_binop?  */
+       if (compare_direction > 0)
+         {
+           /* <, <= :the loop variable is increasing */
+           temp_reg = expand_binop (loop_var_mode, sub_optab,
+                                    comparison_value, initial_value,
+                                    NULL_RTX, 0, OPTAB_LIB_WIDEN);
+         }
+       else
+         {
+           temp_reg = expand_binop (loop_var_mode, sub_optab,
+                                    initial_value, comparison_value,
+                                    NULL_RTX, 0, OPTAB_LIB_WIDEN);
+         }
 
-      if (increment_value_abs - 1 + add_iteration != 0)
-       temp_reg = expand_binop (loop_var_mode, add_optab, temp_reg,
-                                GEN_INT (increment_value_abs - 1 + add_iteration),
-                                NULL_RTX, 0, OPTAB_LIB_WIDEN);
+       if (increment_value_abs - 1 + add_iteration != 0)
+         temp_reg = expand_binop (loop_var_mode, add_optab, temp_reg,
+                                  GEN_INT (increment_value_abs - 1
+                                           + add_iteration),
+                                  NULL_RTX, 0, OPTAB_LIB_WIDEN);
 
-      if (increment_value_abs != 1)
-       {
-         /* ??? This will generate an expensive divide instruction for
-            most targets.  The original authors apparently expected this
-            to be a shift, since they test for power-of-2 divisors above,
-            but just naively generating a divide instruction will not give 
-            a shift.  It happens to work for the PowerPC target because
-            the rs6000.md file has a divide pattern that emits shifts.
-            It will probably not work for any other target.  */
-         iterations_num_reg = expand_binop (loop_var_mode, sdiv_optab,
-                                            temp_reg,
-                                            GEN_INT (increment_value_abs),
-                                            NULL_RTX, 0, OPTAB_LIB_WIDEN);
-       }
-      else
-       iterations_num_reg = temp_reg;
+       if (increment_value_abs != 1)
+         {
+           /* ??? This will generate an expensive divide instruction for
+              most targets.  The original authors apparently expected this
+              to be a shift, since they test for power-of-2 divisors above,
+              but just naively generating a divide instruction will not give 
+              a shift.  It happens to work for the PowerPC target because
+              the rs6000.md file has a divide pattern that emits shifts.
+              It will probably not work for any other target.  */
+           iterations_num_reg = expand_binop (loop_var_mode, sdiv_optab,
+                                              temp_reg,
+                                              GEN_INT (increment_value_abs),
+                                              NULL_RTX, 0, OPTAB_LIB_WIDEN);
+         }
+       else
+         iterations_num_reg = temp_reg;
+      }
+      sequence = gen_sequence ();
+      end_sequence ();
+      emit_insn_before (sequence, loop_start);
+      instrument_loop_bct (loop_start, loop_end, iterations_num_reg);
     }
-    sequence = gen_sequence ();
-    end_sequence ();
-    emit_insn_before (sequence, loop_start);
-    instrument_loop_bct (loop_start, loop_end, iterations_num_reg);
-  }
+
+  return;
+#endif /* Complex case */
 }
 
-/* instrument loop by inserting a bct in it. This is done in the following way:
-   1. A new register is created and assigned the hard register number of the count
-    register.
-   2. In the head of the loop the new variable is initialized by the value passed in the
-    loop_num_iterations parameter.
+/* Instrument loop by inserting a bct in it as follows:
+   1. A new counter register is created.
+   2. In the head of the loop the new variable is initialized to the value
+   passed in the loop_num_iterations parameter.
    3. At the end of the loop, comparison of the register with 0 is generated.
-    The created comparison follows the pattern defined for the
-    decrement_and_branch_on_count insn, so this insn will be generated in assembly
-    generation phase.
-   4. The compare&branch on the old variable is deleted. So, if the loop-variable was
-    not used elsewhere, it will be eliminated by data-flow analisys.  */
+   The created comparison follows the pattern defined for the
+   decrement_and_branch_on_count insn, so this insn will be generated.
+   4. The branch on the old variable are deleted.  The compare must remain
+   because it might be used elsewhere.  If the loop-variable or condition
+   register are used elsewhere, they will be eliminated by flow.  */
 
 static void
 instrument_loop_bct (loop_start, loop_end, loop_num_iterations)
      rtx loop_start, loop_end;
      rtx loop_num_iterations;
 {
-  rtx temp_reg1, temp_reg2;
+  rtx counter_reg;
   rtx start_label;
-
   rtx sequence;
-  enum machine_mode loop_var_mode = SImode;
 
   if (HAVE_decrement_and_branch_on_count)
     {
       if (loop_dump_stream)
-       fprintf (loop_dump_stream, "Loop: Inserting BCT\n");
+       {
+         fputs ("instrument_bct: Inserting BCT (", loop_dump_stream);
+         if (GET_CODE (loop_num_iterations) == CONST_INT)
+           fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC,
+                    INTVAL (loop_num_iterations));
+         else
+           fputs ("runtime", loop_dump_stream);
+         fputs (" iterations)", loop_dump_stream);
+       }
 
-      /* eliminate the check on the old variable */
-      delete_insn (PREV_INSN (loop_end));
+      /* Discard original jump to continue loop.  Original compare result
+        may still be live, so it cannot be discarded explicitly.  */
       delete_insn (PREV_INSN (loop_end));
 
-      /* insert the label which will delimit the start of the loop */
+      /* Insert the label which will delimit the start of the loop.  */
       start_label = gen_label_rtx ();
       emit_label_after (start_label, loop_start);
 
-      /* insert initialization of the count register into the loop header */
+      /* Insert initialization of the count register into the loop header.  */
       start_sequence ();
-      temp_reg1 = gen_reg_rtx (loop_var_mode);
-      emit_insn (gen_move_insn (temp_reg1, loop_num_iterations));
-
-      /* this will be count register */
-      temp_reg2 = gen_rtx_REG (loop_var_mode, COUNT_REGISTER_REGNUM);
-      /* we have to move the value to the count register from an GPR
-        because rtx pointed to by loop_num_iterations could contain
-        expression which cannot be moved into count register */
-      emit_insn (gen_move_insn (temp_reg2, temp_reg1));
-
+      counter_reg = gen_reg_rtx (word_mode);
+      emit_insn (gen_move_insn (counter_reg, loop_num_iterations));
       sequence = gen_sequence ();
       end_sequence ();
-      emit_insn_after (sequence, loop_start);
+      emit_insn_before (sequence, loop_start);
 
-      /* insert new comparison on the count register instead of the
+      /* Insert new comparison on the count register instead of the
         old one, generating the needed BCT pattern (that will be
         later recognized by assembly generation phase).  */
-      emit_jump_insn_before (gen_decrement_and_branch_on_count (temp_reg2, start_label),
+      emit_jump_insn_before (gen_decrement_and_branch_on_count (counter_reg,
+                                                               start_label),
                             loop_end);
       LABEL_NUSES (start_label)++;
     }
@@ -8305,8 +8225,6 @@ instrument_loop_bct (loop_start, loop_end, loop_num_iterations)
 }
 #endif /* HAVE_decrement_and_branch_on_count */
 
-#endif /* HAIFA */
-
 /* Scan the function and determine whether it has indirect (computed) jumps.
 
    This is taken mostly from flow.c; similar code exists elsewhere
@@ -8389,6 +8307,8 @@ insert_loop_mem (mem, data)
   loop_mems[loop_mems_idx].optimize = (GET_MODE (m) != BLKmode);
   loop_mems[loop_mems_idx].reg = NULL_RTX;
   ++loop_mems_idx;
+
+  return 0;
 }
 
 /* Like load_mems, but also ensures that N_TIMES_SET,
@@ -8402,7 +8322,7 @@ load_mems_and_recount_loop_regs_set (scan_start, end, loop_top, start,
      rtx end;
      rtx loop_top;
      rtx start;
-     rtx *reg_single_usage;
+     varray_type reg_single_usage;
      int *insn_count;
 {
   int nregs = max_reg_num ();
@@ -8419,24 +8339,42 @@ load_mems_and_recount_loop_regs_set (scan_start, end, loop_top, start,
       old_nregs = nregs;
       nregs = max_reg_num ();
 
-      /* Note that we assume here that enough room was allocated in
-        the various arrays to accomodate the extra registers created
-        by load_mems.  */
-      bzero ((char *) n_times_set, nregs * sizeof (int));
-      bzero (may_not_optimize, nregs);
-      if (loop_has_call && reg_single_usage)
-       bzero ((char *) reg_single_usage, nregs * sizeof (rtx));
+      if (nregs > n_times_set->num_elements)
+       {
+         /* Grow all the arrays.  */
+         VARRAY_GROW (n_times_set, nregs);
+         VARRAY_GROW (n_times_used, nregs);
+         VARRAY_GROW (may_not_optimize, nregs);
+         if (reg_single_usage)
+           VARRAY_GROW (reg_single_usage, nregs);
+       }
+      /* Clear the arrays */
+      bzero ((char *) &n_times_set->data, nregs * sizeof (int));
+      bzero ((char *) &may_not_optimize->data, nregs * sizeof (char));
+      if (reg_single_usage)
+       bzero ((char *) &reg_single_usage->data, nregs * sizeof (rtx));
 
       count_loop_regs_set (loop_top ? loop_top : start, end,
                           may_not_optimize, reg_single_usage,
                           insn_count, nregs); 
 
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-       may_not_optimize[i] = 1, n_times_set[i] = 1;
+       {
+         VARRAY_CHAR (may_not_optimize, i) = 1;
+         VARRAY_INT (n_times_set, i) = 1;
+       }
       
+#ifdef AVOID_CCMODE_COPIES
+      /* Don't try to move insns which set CC registers if we should not
+        create CCmode register copies.  */
+      for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
+       if (GET_MODE_CLASS (GET_MODE (regno_reg_rtx[i])) == MODE_CC)
+         VARRAY_CHAR (may_not_optimize, i) = 1;
+#endif
+
       /* Set n_times_used for the new registers.  */
-      bcopy ((char *) (n_times_set + old_nregs),
-            (char *) (n_times_used + old_nregs),
+      bcopy ((char *) (&n_times_set->data.i[0] + old_nregs),
+            (char *) (&n_times_used->data.i[0] + old_nregs),
             (nregs - old_nregs) * sizeof (int));
     }
 }
@@ -8571,7 +8509,9 @@ load_mems (scan_start, end, loop_top, start)
               p != NULL_RTX;
               p = next_insn_in_loop (p, scan_start, end, loop_top))
            {
-             rtx_and_int ri = { p, i };
+             rtx_and_int ri;
+             ri.r = p;
+             ri.i = i;
              for_each_rtx (&p, replace_loop_mem, &ri);
            }
 
@@ -8601,7 +8541,7 @@ load_mems (scan_start, end, loop_top, start)
 
                  /* Store the memory immediately after END, which is
                   the NOTE_LOOP_END.  */
-                 set = gen_rtx_SET (GET_MODE (reg), mem, reg); 
+                 set = gen_rtx_SET (GET_MODE (reg), copy_rtx (mem), reg); 
                  emit_insn_after (set, label);
                }
 
@@ -8620,10 +8560,23 @@ load_mems (scan_start, end, loop_top, start)
     {
       /* Now, we need to replace all references to the previous exit
         label with the new one.  */
-      rtx_pair rr = { end_label, label };
+      rtx_pair rr; 
+      rr.r1 = end_label;
+      rr.r2 = label;
 
       for (p = start; p != end; p = NEXT_INSN (p))
-       for_each_rtx (&p, replace_label, &rr);
+       {
+         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;
+       }
     }
 }
 
@@ -8704,4 +8657,3 @@ replace_label (x, data)
   return 0;
 }
 
-