loop.c (basic_induction_var): A non-integer variable which is being set by a paradoxi...
[platform/upstream/gcc.git] / gcc / loop.c
index a3b2bb0..2b2a837 100644 (file)
@@ -37,6 +37,7 @@ Boston, MA 02111-1307, USA.  */
 #include "config.h"
 #include "system.h"
 #include "rtl.h"
+#include "tm_p.h"
 #include "obstack.h"
 #include "function.h"
 #include "expr.h"
@@ -268,6 +269,9 @@ static struct movable *the_movables;
 
 FILE *loop_dump_stream;
 
+/* For communicating return values from note_set_pseudo_multiple_uses.  */
+static int note_set_pseudo_multiple_uses_retval;
+
 /* Forward declarations.  */
 
 static void verify_dominator PROTO((int));
@@ -282,6 +286,7 @@ 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 void note_set_pseudo_multiple_uses PROTO((rtx, rtx));
 static int loop_reg_used_before_p PROTO((rtx, rtx, rtx, rtx, rtx));
 static void scan_loop PROTO((rtx, rtx, rtx, int, int));
 #if 0
@@ -301,11 +306,11 @@ static void strength_reduce PROTO((rtx, rtx, rtx, int, rtx, rtx,
                                   struct loop_info *, 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 find_mem_givs PROTO((rtx, rtx, int, int, rtx, rtx));
 static void record_biv PROTO((struct induction *, rtx, rtx, rtx, rtx, rtx *, int, int));
 static void check_final_value PROTO((struct induction *, rtx, rtx, 
                                     unsigned HOST_WIDE_INT));
-static void record_giv PROTO((struct induction *, rtx, rtx, rtx, rtx, rtx, int, enum g_types, int, rtx *, rtx, rtx));
+static void record_giv PROTO((struct induction *, rtx, rtx, rtx, rtx, rtx, int, enum g_types, int, int, rtx *, rtx, rtx));
 static void update_giv_derive PROTO((rtx));
 static int basic_induction_var PROTO((rtx, enum machine_mode, rtx, rtx, rtx *, rtx *, rtx **));
 static rtx simplify_giv_expr PROTO((rtx, int *));
@@ -2356,12 +2361,15 @@ constant_high_bytes (p, loop_start)
   /* Try to change (SET (REG ...) (ZERO_EXTEND (..:B ...)))
      to (SET (STRICT_LOW_PART (SUBREG:B (REG...))) ...).  */
 
-  new = gen_rtx_SET (VOIDmode,
-                    gen_rtx_STRICT_LOW_PART (VOIDmode,
-                                             gen_rtx_SUBREG (GET_MODE (XEXP (SET_SRC (PATTERN (p)), 0)),
-                                  SET_DEST (PATTERN (p)),
-                                  0)),
-                XEXP (SET_SRC (PATTERN (p)), 0));
+  new
+    = gen_rtx_SET
+      (VOIDmode,
+       gen_rtx_STRICT_LOW_PART
+       (VOIDmode,
+       gen_rtx_SUBREG (GET_MODE (XEXP (SET_SRC (PATTERN (p)), 0)),
+                       SET_DEST (PATTERN (p)), 0)),
+       XEXP (SET_SRC (PATTERN (p)), 0));
+
   insn_code_number = recog (new, p);
 
   if (insn_code_number)
@@ -2369,8 +2377,8 @@ constant_high_bytes (p, loop_start)
       register int i;
 
       /* Clear destination register before the loop.  */
-      emit_insn_before (gen_rtx_SET (VOIDmode, SET_DEST (PATTERN (p)),
-                                    const0_rtx),
+      emit_insn_before (gen_rtx_SET (VOIDmode,
+                                    SET_DEST (PATTERN (p)), const0_rtx),
                        loop_start);
 
       /* Inside the loop, just load the low part.  */
@@ -2776,6 +2784,7 @@ find_and_verify_loops (f)
          {
            rtx p;
            rtx our_next = next_real_insn (insn);
+           rtx last_insn_to_move = NEXT_INSN (insn);
            int dest_loop;
            int outer_loop = -1;
 
@@ -2827,21 +2836,39 @@ find_and_verify_loops (f)
                && INSN_UID (JUMP_LABEL (p)) != 0
                && condjump_p (p)
                && ! simplejump_p (p)
-               && next_real_insn (JUMP_LABEL (p)) == our_next)
+               && next_real_insn (JUMP_LABEL (p)) == our_next
+               /* If it's not safe to move the sequence, then we
+                  mustn't try.  */
+               && insns_safe_to_move_p (p, NEXT_INSN (insn), 
+                                        &last_insn_to_move))
              {
                rtx target
                  = JUMP_LABEL (insn) ? JUMP_LABEL (insn) : get_last_insn ();
                int target_loop_num = uid_loop_num[INSN_UID (target)];
-               rtx loc;
+               rtx loc, loc2;
 
                for (loc = target; loc; loc = PREV_INSN (loc))
                  if (GET_CODE (loc) == BARRIER
+                     /* Don't move things inside a tablejump.  */
+                     && ((loc2 = next_nonnote_insn (loc)) == 0
+                         || GET_CODE (loc2) != CODE_LABEL
+                         || (loc2 = next_nonnote_insn (loc2)) == 0
+                         || GET_CODE (loc2) != JUMP_INSN
+                         || (GET_CODE (PATTERN (loc2)) != ADDR_VEC
+                             && GET_CODE (PATTERN (loc2)) != ADDR_DIFF_VEC))
                      && uid_loop_num[INSN_UID (loc)] == target_loop_num)
                    break;
 
                if (loc == 0)
                  for (loc = target; loc; loc = NEXT_INSN (loc))
                    if (GET_CODE (loc) == BARRIER
+                       /* Don't move things inside a tablejump.  */
+                       && ((loc2 = next_nonnote_insn (loc)) == 0
+                           || GET_CODE (loc2) != CODE_LABEL
+                           || (loc2 = next_nonnote_insn (loc2)) == 0
+                           || GET_CODE (loc2) != JUMP_INSN
+                           || (GET_CODE (PATTERN (loc2)) != ADDR_VEC
+                               && GET_CODE (PATTERN (loc2)) != ADDR_DIFF_VEC))
                        && uid_loop_num[INSN_UID (loc)] == target_loop_num)
                      break;
 
@@ -2882,11 +2909,13 @@ find_and_verify_loops (f)
 
                       /* Include the BARRIER after INSN and copy the
                          block after LOC.  */
-                      new_label = squeeze_notes (new_label, NEXT_INSN (insn));
-                      reorder_insns (new_label, NEXT_INSN (insn), loc);
+                      new_label = squeeze_notes (new_label, 
+                                                 last_insn_to_move);
+                      reorder_insns (new_label, last_insn_to_move, loc);
 
                       /* All those insns are now in TARGET_LOOP_NUM.  */
-                      for (q = new_label; q != NEXT_INSN (NEXT_INSN (insn));
+                      for (q = new_label; 
+                           q != NEXT_INSN (last_insn_to_move);
                            q = NEXT_INSN (q))
                         uid_loop_num[INSN_UID (q)] = target_loop_num;
 
@@ -3147,6 +3176,36 @@ note_addr_stored (x, y)
 
   loop_store_mems = gen_rtx_EXPR_LIST (VOIDmode, x, loop_store_mems);
 }
+
+/* X is a value modified by an INSN that references a biv inside a loop
+   exit test (ie, X is somehow related to the value of the biv).  If X
+   is a pseudo that is used more than once, then the biv is (effectively)
+   used more than once.  */
+
+static void
+note_set_pseudo_multiple_uses (x, y)
+     rtx x;
+     rtx y ATTRIBUTE_UNUSED;
+{
+  if (x == 0)
+    return;
+
+  while (GET_CODE (x) == STRICT_LOW_PART
+        || GET_CODE (x) == SIGN_EXTRACT
+        || GET_CODE (x) == ZERO_EXTRACT
+        || GET_CODE (x) == SUBREG)
+    x = XEXP (x, 0);
+
+  if (GET_CODE (x) != REG || REGNO (x) < FIRST_PSEUDO_REGISTER)
+    return;
+
+  /* If we do not have usage information, or if we know the register
+     is used more than once, note that fact for check_dbra_loop.  */
+  if (REGNO (x) >= max_reg_before_loop
+      || ! VARRAY_RTX (reg_single_usage, REGNO (x))
+      || VARRAY_RTX (reg_single_usage, REGNO (x)) == const0_rtx)
+    note_set_pseudo_multiple_uses_retval = 1;
+}
 \f
 /* Return nonzero if the rtx X is invariant over the current loop.
 
@@ -3703,7 +3762,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
   rtx end_insert_before;
   int loop_depth = 0;
   int n_extra_increment;
-  int unrolled_insn_copies;
+  int unrolled_insn_copies = 0;
 
   /* If scan_start points to the loop exit test, we have to be wary of
      subversive use of gotos inside expression statements.  */
@@ -3923,7 +3982,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
        unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
                     loop_info, 0);
 
-      return;
+      goto egress;
     }
 
   /* Find initial value for each biv by searching backwards from loop_start,
@@ -4050,14 +4109,14 @@ strength_reduce (scan_start, end, loop_top, insn_count,
              /* The register from BL2 must be set before the register from
                 BL is set, or we must be able to move the latter set after
                 the former set.  Currently there can't be any labels
-                in-between when biv_toal_increment returns nonzero both times
+                in-between when biv_total_increment returns nonzero both times
                 but we test it here in case some day some real cfg analysis
                 gets used to set always_computable.  */
-             && ((loop_insn_first_p (bl2->biv->insn, bl->biv->insn)
-                  && no_labels_between_p (bl2->biv->insn, bl->biv->insn))
-                 || (! reg_used_between_p (bl->biv->src_reg, bl->biv->insn,
-                                           bl2->biv->insn)
-                     && no_jumps_between_p (bl->biv->insn, bl2->biv->insn)))
+             && (loop_insn_first_p (bl2->biv->insn, bl->biv->insn)
+                 ? no_labels_between_p (bl2->biv->insn, bl->biv->insn)
+                 : (! reg_used_between_p (bl->biv->src_reg, bl->biv->insn,
+                                          bl2->biv->insn)
+                    && no_jumps_between_p (bl->biv->insn, bl2->biv->insn)))
              && validate_change (bl->biv->insn,
                                  &SET_SRC (single_set (bl->biv->insn)),
                                  copy_rtx (src), 0))
@@ -4377,6 +4436,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
 
   not_every_iteration = 0;
   loop_depth = 0;
+  maybe_multiple = 0;
   p = scan_start;
   while (1)
     {
@@ -4445,8 +4505,8 @@ strength_reduce (scan_start, end, loop_top, insn_count,
                p = last_consec_insn;
 
              record_giv (v, p, src_reg, dest_reg, mult_val, add_val, benefit,
-                         DEST_REG, not_every_iteration, NULL_PTR, loop_start,
-                         loop_end);
+                         DEST_REG, not_every_iteration, maybe_multiple,
+                         NULL_PTR, loop_start, loop_end);
 
            }
        }
@@ -4456,8 +4516,8 @@ strength_reduce (scan_start, end, loop_top, insn_count,
       /* This resulted in worse code on a VAX 8600.  I wonder if it
         still does.  */
       if (GET_CODE (p) == INSN)
-       find_mem_givs (PATTERN (p), p, not_every_iteration, loop_start,
-                      loop_end);
+       find_mem_givs (PATTERN (p), p, not_every_iteration, maybe_multiple,
+                      loop_start, loop_end);
 #endif
 
       /* Update the status of whether giv can derive other givs.  This can
@@ -4466,6 +4526,49 @@ strength_reduce (scan_start, end, loop_top, insn_count,
        || GET_CODE (p) == CODE_LABEL)
        update_giv_derive (p);
 
+      /* Past CODE_LABEL, we get to insns that may be executed multiple
+        times.  The only way we can be sure that they can't is if every
+        every jump insn between here and the end of the loop either
+        returns, exits the loop, is a forward jump, or is a jump
+        to the loop start.  */
+
+      if (GET_CODE (p) == CODE_LABEL)
+       {
+         rtx insn = p;
+
+         maybe_multiple = 0;
+
+         while (1)
+           {
+             insn = NEXT_INSN (insn);
+             if (insn == scan_start)
+               break;
+             if (insn == end)
+               {
+                 if (loop_top != 0)
+                   insn = loop_top;
+                 else
+                   break;
+                 if (insn == scan_start)
+                   break;
+               }
+
+             if (GET_CODE (insn) == JUMP_INSN
+                 && GET_CODE (PATTERN (insn)) != RETURN
+                 && (! condjump_p (insn)
+                     || (JUMP_LABEL (insn) != 0
+                         && JUMP_LABEL (insn) != scan_start
+                         && (INSN_UID (JUMP_LABEL (insn)) >= max_uid_for_loop
+                             || INSN_UID (insn) >= max_uid_for_loop
+                             || (INSN_LUID (JUMP_LABEL (insn))
+                                 < INSN_LUID (insn))))))
+               {
+                 maybe_multiple = 1;
+                 break;
+               }
+           }
+       }
+
       /* Past a jump, we get to insns for which we can't count
         on whether they will be executed during each iteration.  */
       /* This code appears twice in strength_reduce.  There is also similar
@@ -5178,6 +5281,8 @@ strength_reduce (scan_start, end, loop_top, insn_count,
 
   if (loop_dump_stream)
     fprintf (loop_dump_stream, "\n");
+
+egress:
   VARRAY_FREE (reg_iv_type);
   VARRAY_FREE (reg_iv_info);
 }
@@ -5224,13 +5329,15 @@ valid_initial_value_p (x, insn, call_seen, loop_start)
 /* Scan X for memory refs and check each memory address
    as a possible giv.  INSN is the insn whose pattern X comes from.
    NOT_EVERY_ITERATION is 1 if the insn might not be executed during
-   every loop iteration.  */
+   every loop iteration.  MAYBE_MULTIPLE is 1 if the insn might be executed
+   more thanonce in each loop iteration.  */
 
 static void
-find_mem_givs (x, insn, not_every_iteration, loop_start, loop_end)
+find_mem_givs (x, insn, not_every_iteration, maybe_multiple, loop_start,
+              loop_end)
      rtx x;
      rtx insn;
-     int not_every_iteration;
+     int not_every_iteration, maybe_multiple;
      rtx loop_start, loop_end;
 {
   register int i, j;
@@ -5278,7 +5385,7 @@ find_mem_givs (x, insn, not_every_iteration, loop_start, loop_end)
 
            record_giv (v, insn, src_reg, addr_placeholder, mult_val,
                        add_val, benefit, DEST_ADDR, not_every_iteration,
-                       &XEXP (x, 0), loop_start, loop_end);
+                       maybe_multiple, &XEXP (x, 0), loop_start, loop_end);
 
            v->mem_mode = GET_MODE (x);
          }
@@ -5294,12 +5401,12 @@ find_mem_givs (x, insn, not_every_iteration, loop_start, loop_end)
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     if (fmt[i] == 'e')
-      find_mem_givs (XEXP (x, i), insn, not_every_iteration, loop_start,
-                    loop_end);
+      find_mem_givs (XEXP (x, i), insn, not_every_iteration, maybe_multiple,
+                    loop_start, loop_end);
     else if (fmt[i] == 'E')
       for (j = 0; j < XVECLEN (x, i); j++)
        find_mem_givs (XVECEXP (x, i, j), insn, not_every_iteration,
-                      loop_start, loop_end);
+                      maybe_multiple, loop_start, loop_end);
 }
 \f
 /* Fill in the data about one biv update.
@@ -5421,7 +5528,8 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location,
 
 static void
 record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
-           type, not_every_iteration, location, loop_start, loop_end)
+           type, not_every_iteration, maybe_multiple, location, loop_start,
+           loop_end)
      struct induction *v;
      rtx insn;
      rtx src_reg;
@@ -5429,7 +5537,7 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
      rtx mult_val, add_val;
      int benefit;
      enum g_types type;
-     int not_every_iteration;
+     int not_every_iteration, maybe_multiple;
      rtx *location;
      rtx loop_start, loop_end;
 {
@@ -5447,7 +5555,7 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
   v->location = location;
   v->cant_derive = 0;
   v->combined_with = 0;
-  v->maybe_multiple = 0;
+  v->maybe_multiple = maybe_multiple;
   v->maybe_dead = 0;
   v->derive_adjustment = 0;
   v->same = 0;
@@ -5882,9 +5990,10 @@ update_giv_derive (p)
                                             &dummy);
 
                  if (tem && giv->derive_adjustment)
-                   tem = simplify_giv_expr (gen_rtx_PLUS (giv->mode, tem,
-                                                          giv->derive_adjustment),
-                                            &dummy);
+                   tem = simplify_giv_expr
+                     (gen_rtx_PLUS (giv->mode, tem, giv->derive_adjustment),
+                      &dummy);
+
                  if (tem)
                    giv->derive_adjustment = tem;
                  else
@@ -5949,6 +6058,7 @@ basic_induction_var (x, mode, dest_reg, p, inc_val, mult_val, location)
   rtx insn, set = 0;
 
   code = GET_CODE (x);
+  *location = NULL;
   switch (code)
     {
     case PLUS:
@@ -6008,6 +6118,8 @@ basic_induction_var (x, mode, dest_reg, p, inc_val, mult_val, location)
               || (GET_CODE (SET_DEST (set)) == SUBREG
                   && (GET_MODE_SIZE (GET_MODE (SET_DEST (set)))
                       <= UNITS_PER_WORD)
+                  && (GET_MODE_CLASS (GET_MODE (SET_DEST (set)))
+                      == MODE_INT)
                   && SUBREG_REG (SET_DEST (set)) == x))
              && basic_induction_var (SET_SRC (set),
                                      (GET_MODE (SET_SRC (set)) == VOIDmode
@@ -6206,8 +6318,10 @@ general_induction_var (x, src_reg, add_val, mult_val, is_addr, pbenefit)
 
    *BENEFIT will be incremented by the benefit of any sub-giv encountered.  */
 
-static rtx sge_plus PROTO ((enum machine_mode, rtx, rtx));
-static rtx sge_plus_constant PROTO ((rtx, rtx));
+static rtx sge_plus PARAMS ((enum machine_mode, rtx, rtx));
+static rtx sge_plus_constant PARAMS ((rtx, rtx));
+static int cmp_combine_givs_stats PARAMS ((const PTR, const PTR));
+static int cmp_recombine_givs_stats PARAMS ((const PTR, const PTR));
 
 static rtx
 simplify_giv_expr (x, benefit)
@@ -6274,10 +6388,13 @@ simplify_giv_expr (x, benefit)
 
          case PLUS:
            /* (a + invar_1) + invar_2.  Associate.  */
-           return simplify_giv_expr (
-               gen_rtx_PLUS (mode, XEXP (arg0, 0),
-                             gen_rtx_PLUS (mode, XEXP (arg0, 1), arg1)),
-               benefit);
+           return
+             simplify_giv_expr (gen_rtx_PLUS (mode,
+                                              XEXP (arg0, 0),
+                                              gen_rtx_PLUS (mode,
+                                                            XEXP (arg0, 1),
+                                                            arg1)),
+                                benefit);
 
          default:
            abort ();
@@ -6297,11 +6414,12 @@ simplify_giv_expr (x, benefit)
        tem = arg0, arg0 = arg1, arg1 = tem;
 
       if (GET_CODE (arg1) == PLUS)
-         return simplify_giv_expr (gen_rtx_PLUS (mode,
-                                                 gen_rtx_PLUS (mode, arg0,
-                                                               XEXP (arg1, 0)),
-                                                 XEXP (arg1, 1)),
-                                   benefit);
+         return
+           simplify_giv_expr (gen_rtx_PLUS (mode,
+                                            gen_rtx_PLUS (mode, arg0,
+                                                          XEXP (arg1, 0)),
+                                            XEXP (arg1, 1)),
+                              benefit);
 
       /* Now must have MULT + MULT.  Distribute if same biv, else not giv.  */
       if (GET_CODE (arg0) != MULT || GET_CODE (arg1) != MULT)
@@ -6321,7 +6439,8 @@ simplify_giv_expr (x, benefit)
       /* Handle "a - b" as "a + b * (-1)".  */
       return simplify_giv_expr (gen_rtx_PLUS (mode,
                                              XEXP (x, 0),
-                                             gen_rtx_MULT (mode, XEXP (x, 1),
+                                             gen_rtx_MULT (mode,
+                                                           XEXP (x, 1),
                                                            constm1_rtx)),
                                benefit);
 
@@ -6380,7 +6499,8 @@ simplify_giv_expr (x, benefit)
 
        case MULT:
          /* (a * invar_1) * invar_2.  Associate.  */
-         return simplify_giv_expr (gen_rtx_MULT (mode, XEXP (arg0, 0),
+         return simplify_giv_expr (gen_rtx_MULT (mode,
+                                                 XEXP (arg0, 0),
                                                  gen_rtx_MULT (mode,
                                                                XEXP (arg0, 1),
                                                                arg1)),
@@ -6406,11 +6526,12 @@ simplify_giv_expr (x, benefit)
       if (GET_CODE (XEXP (x, 1)) != CONST_INT)
        return 0;
 
-      return simplify_giv_expr (gen_rtx_MULT (mode,
-                                             XEXP (x, 0),
-                                             GEN_INT ((HOST_WIDE_INT) 1
-                                                      << INTVAL (XEXP (x, 1)))),
-                               benefit);
+      return
+       simplify_giv_expr (gen_rtx_MULT (mode,
+                                        XEXP (x, 0),
+                                        GEN_INT ((HOST_WIDE_INT) 1
+                                                 << INTVAL (XEXP (x, 1)))),
+                          benefit);
 
     case NEG:
       /* "-a" is "a * (-1)" */
@@ -6448,9 +6569,10 @@ simplify_giv_expr (x, benefit)
            if (v->cant_derive)
              return 0;
 
-           tem = gen_rtx_PLUS (mode, gen_rtx_MULT (mode, v->src_reg,
-                                                   v->mult_val),
-                          v->add_val);
+           tem = gen_rtx_PLUS (mode, gen_rtx_MULT (mode,
+                                                   v->src_reg, v->mult_val),
+                               v->add_val);
+
            if (v->derive_adjustment)
              tem = gen_rtx_MINUS (mode, tem, v->derive_adjustment);
            return simplify_giv_expr (tem, benefit);
@@ -6945,9 +7067,14 @@ struct combine_givs_stats
 };
 
 static int
-cmp_combine_givs_stats (x, y)
-     struct combine_givs_stats *x, *y;
+cmp_combine_givs_stats (xp, yp)
+     const PTR xp;
+     const PTR yp;
 {
+  const struct combine_givs_stats * const x =
+    (const struct combine_givs_stats *) xp;
+  const struct combine_givs_stats * const y =
+    (const struct combine_givs_stats *) yp;
   int d;
   d = y->total_benefit - x->total_benefit;
   /* Stabilize the sort.  */
@@ -7132,9 +7259,14 @@ struct recombine_givs_stats
    when scanning the array starting at the end, thus the arguments are
    used in reverse.  */
 static int
-cmp_recombine_givs_stats (x, y)
-     struct recombine_givs_stats *x, *y;
+cmp_recombine_givs_stats (xp, yp)
+     const PTR xp;
+     const PTR yp;
 {
+  const struct recombine_givs_stats * const x =
+    (const struct recombine_givs_stats *) xp;
+  const struct recombine_givs_stats * const y =
+    (const struct recombine_givs_stats *) yp;
   int d;
   d = y->start_luid - x->start_luid;
   /* Stabilize the sort.  */
@@ -7797,7 +7929,8 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
            }
        }
     }
-  else if (INTVAL (bl->biv->add_val) > 0)
+  else if (GET_CODE (bl->biv->add_val) == CONST_INT
+          && INTVAL (bl->biv->add_val) > 0)
     {
       /* Try to change inc to dec, so can apply above optimization.  */
       /* Can do this if:
@@ -7835,10 +7968,22 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
                    && REGNO (SET_DEST (set)) == bl->regno)
                  /* An insn that sets the biv is okay.  */
                  ;
-               else if (p == prev_nonnote_insn (prev_nonnote_insn (loop_end))
-                        || p == prev_nonnote_insn (loop_end))
-                 /* Don't bother about the end test.  */
-                 ;
+               else if ((p == prev_nonnote_insn (prev_nonnote_insn (loop_end))
+                         || p == prev_nonnote_insn (loop_end))
+                        && reg_mentioned_p (bivreg, PATTERN (p)))
+                 {
+                   /* If either of these insns uses the biv and sets a pseudo
+                      that has more than one usage, then the biv has uses
+                      other than counting since it's used to derive a value
+                      that is used more than one time.  */
+                   note_set_pseudo_multiple_uses_retval = 0;
+                   note_stores (PATTERN (p), note_set_pseudo_multiple_uses);
+                   if (note_set_pseudo_multiple_uses_retval)
+                     {
+                       no_use_except_counting = 0;
+                       break;
+                     }
+                 }
                else if (reg_mentioned_p (bivreg, PATTERN (p)))
                  {
                    no_use_except_counting = 0;
@@ -7923,7 +8068,7 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
                  || (GET_CODE (comparison) == LE
                      && no_use_except_counting)))
            {
-             HOST_WIDE_INT add_val, add_adjust, comparison_val;
+             HOST_WIDE_INT add_val, add_adjust, comparison_val = 0;
              rtx initial_value, comparison_value;
              int nonneg = 0;
              enum rtx_code cmp_code;
@@ -8069,10 +8214,12 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
                  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])
+
+                 if (! (*insn_data[icode].operand[0].predicate) (reg, mode)
+                     || ! ((*insn_data[icode].operand[1].predicate)
                            (comparison_value, mode))
-                     || ! (*insn_operand_predicate[icode][2]) (offset, mode))
+                     || ! ((*insn_data[icode].operand[2].predicate)
+                           (offset, mode)))
                    return 0;
                  start_value
                    = gen_rtx_PLUS (mode, comparison_value, offset);
@@ -8088,10 +8235,10 @@ check_dbra_loop (loop_end, insn_count, loop_start, loop_info)
                  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])
+                 if (! (*insn_data[icode].operand[0].predicate) (reg, mode)
+                     || ! ((*insn_data[icode].operand[1].predicate)
                            (comparison_value, mode))
-                     || ! ((*insn_operand_predicate[icode][2])
+                     || ! ((*insn_data[icode].operand[2].predicate)
                            (initial_value, mode)))
                    return 0;
                  start_value