* loop.c (insert_bct): Ensure loop_iteration_var non-zero before use.
[gcc.git] / gcc / loop.c
index 24f1b6d747986193e36bdcda209d972e3453f6db..556877feff9dfb5351a3f29219a03f97e2afb8d4 100644 (file)
@@ -291,6 +291,8 @@ 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_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));
@@ -3313,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,
@@ -3359,76 +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.  */
-           VARRAY_CHAR (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 (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;
-               }
-           }
+           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.  */
-                   VARRAY_CHAR (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 (VARRAY_INT (n_times_set, regno) > 0 
-                             && last_set[regno] == 0)
-                           VARRAY_CHAR (may_not_move, regno) = 1;
-                         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;
-                       }
-                   }
-               }
+               count_one_set (insn, XVECEXP (PATTERN (insn), 0, i),
+                              may_not_move, last_set);
            }
        }
 
@@ -7779,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
@@ -7797,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
@@ -7815,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
@@ -8058,12 +8054,21 @@ insert_bct (loop_start, loop_end)
      at compile time.  In this case we generate run_time calculation
      of the number of iterations.  */
 
+  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;
+    }
+
   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 Instrumentation failed: loop variable not integer\n",
+                "insert_bct %d: BCT Runtime Instrumentation failed: loop variable not integer\n",
                 loop_num);
       return;
     }
@@ -8073,7 +8078,7 @@ insert_bct (loop_start, loop_end)
     {
       if (loop_dump_stream)
        fprintf (loop_dump_stream,
-                "insert_bct %d: runtime bounds with != comparison\n",
+                "insert_bct %d: BCT Runtime Instrumentation failed: runtime bounds with != comparison\n",
                 loop_num);
       return;
     }