OSDN Git Service

Combined compare & jump infrastructure
authorcrux <crux@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 18 Aug 1999 17:51:27 +0000 (17:51 +0000)
committercrux <crux@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 18 Aug 1999 17:51:27 +0000 (17:51 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@28752 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/expmed.c
gcc/expr.c
gcc/expr.h
gcc/flow.c
gcc/integrate.c
gcc/optabs.c
gcc/unroll.c

index 6996457..7cc2f1c 100644 (file)
@@ -1,3 +1,49 @@
+Wed Aug 18 18:20:40 1999  Bernd Schmidt  <bernds@cygnus.co.uk>
+
+       * expmed.c (emit_store_flag): If UNSIGNEDP, call unsigned_condition
+       on CODE.
+       (emit_store_flag_force): Use do_compare_rtx_and_jump.
+       (do_cmp_and_jump): Formatting fixes.
+       * expr.c (do_compare_and_jump): Renamed from compare; changed to call
+       do_compare_rtx_and_jump instead of compare_from_rtx.
+       (do_compare_rtx_and_jump): New function; mostly copied from
+       compare_from_rtx.
+       (do_jump_for_compare): Delete.
+       (expand_expr): Use do_compare_rtx_and_jump when handling MAX_EXPR and
+       MIN_EXPR.
+       (do_jump): Use do_compare_and_jump or do_compare_rtx_and_jump instead
+       of compare/do_jump_for_compare pairs.
+       (do_jump_by_parts_greater): Use do_jump_by_parts_greater_rtx.
+       (do_jump_by_parts_greater_rtx): Use do_compare_rtx_and_jump instead of
+       compare_from_rtx/do_jump_for_compare pairs.
+       (do_jump_by_parts_equality): Likewise.
+       (do_jump_by_parts_equality_rtx): Likewise.
+       * expr.h (do_compare_rtx_and_jump): Declare.
+       * optabs.c (prepare_cmp_insn): New function, contains most of the code
+       that used to be in emit_cmp_insn.
+       (cmp_available_p): New function.
+       (prepare_operand): New function.
+       (emit_cmp_and_jump_insn_1): New function, contains some code that used
+       to be in emit_cmp_insn.
+       (prepare_float_lib_cmp): Renamed from emit_float_lib_cmp; change some
+       parameters to be pointers; don't emit final compare but modify some of
+       the values pointed to by the args so the caller can perform the
+       correct comparison.
+       (expand_binop): Call emit_store_flag_force with signed forms of
+       comparison code.
+       (expand_abs): Use do_compare_rtx_and_jump instead of compare_from_rtx/
+       emit_jump_insn pair.
+       (emit_cmp_and_jump_insn): Use prepare_cmp_insn and
+       emit_cmp_and_jump_insn_1.  Call emit_queue.
+       (emit_cmp_insn): Just call emit_cmp_and_jump_insns with zero for LABEL
+       arg.
+       * flow.c (tidy_fallthru_edge): If HAVE_cc0, verify insn before a
+       jump sets cc0 before deleting it.
+       * integrate.c (expand_inline_function): Likewise.
+       * unroll.c (unroll_loop): Similar changes in several places.
+       (copy_loop_body): If HAVE_cc0, verify insn before a jump sets cc0
+       before deleting it.
+
 Wed Aug 18 06:37:44 1999  Bernd Schmidt  <bernds@cygnus.co.uk>
 
        * Makefile.in (insn-recog.o): Update dependencies.
index ffe16fe..b7e35af 100644 (file)
@@ -4093,6 +4093,9 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
   rtx last = get_last_insn ();
   rtx pattern, comparison;
 
+  if (unsignedp)
+    code = unsigned_condition (code);
+
   /* If one operand is constant, make it the second one.  Only do this
      if the other operand is not constant as well.  */
 
@@ -4492,15 +4495,10 @@ emit_store_flag_force (target, code, op0, op1, mode, unsignedp, normalizep)
     target = gen_reg_rtx (GET_MODE (target));
 
   emit_move_insn (target, const1_rtx);
-  tem = compare_from_rtx (op0, op1, code, unsignedp, mode, NULL_RTX, 0);
-  if (GET_CODE (tem) == CONST_INT)
-    return tem;
-
   label = gen_label_rtx ();
-  if (bcc_gen_fctn[(int) code] == 0)
-    abort ();
+  do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, NULL_RTX, 0,
+                          NULL_RTX, label);
 
-  emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label));
   emit_move_insn (target, const0_rtx);
   emit_label (label);
 
@@ -4519,13 +4517,13 @@ emit_store_flag_force (target, code, op0, op1, mode, unsignedp, normalizep)
 static void
 do_cmp_and_jump (arg1, arg2, op, mode, label)
      rtx arg1, arg2, label;
-    enum rtx_code op;
-    enum machine_mode mode;
+     enum rtx_code op;
+     enum machine_mode mode;
 {
   /* If this mode is an integer too wide to compare properly,
      compare word by word.  Rely on cse to optimize constant cases.  */
 
-  if (GET_MODE_CLASS (mode) == MODE_INT && !can_compare_p (mode))
+  if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode))
     {
       rtx label2 = gen_label_rtx ();
 
index d9382aa..5ad38cd 100644 (file)
@@ -152,8 +152,7 @@ static rtx expand_increment PROTO((tree, int, int));
 static void preexpand_calls    PROTO((tree));
 static void do_jump_by_parts_greater PROTO((tree, int, rtx, rtx));
 static void do_jump_by_parts_equality PROTO((tree, rtx, rtx));
-static void do_jump_for_compare        PROTO((rtx, rtx, rtx));
-static rtx compare             PROTO((tree, enum rtx_code, enum rtx_code));
+static void do_compare_and_jump        PROTO((tree, enum rtx_code, enum rtx_code, rtx, rtx));
 static rtx do_store_flag       PROTO((tree, rtx, enum machine_mode, int));
 
 /* Record for each mode whether we can move a register directly to or
@@ -7297,7 +7296,7 @@ expand_expr (exp, target, tmode, modifier)
 
       /* If this mode is an integer too wide to compare properly,
         compare word by word.  Rely on cse to optimize constant cases.  */
-      if (GET_MODE_CLASS (mode) == MODE_INT && !can_compare_p (mode))
+      if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode))
        {
          if (code == MAX_EXPR)
            do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type),
@@ -7305,29 +7304,15 @@ expand_expr (exp, target, tmode, modifier)
          else
            do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type),
                                          op1, target, NULL_RTX, op0);
-         emit_move_insn (target, op1);
        }
       else
        {
-         if (code == MAX_EXPR)
-           temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)))
-                   ? compare_from_rtx (target, op1, GEU, 1, mode, NULL_RTX, 0)
-                   : compare_from_rtx (target, op1, GE, 0, mode, NULL_RTX, 0));
-         else
-           temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)))
-                   ? compare_from_rtx (target, op1, LEU, 1, mode, NULL_RTX, 0)
-                   : compare_from_rtx (target, op1, LE, 0, mode, NULL_RTX, 0));
-         if (temp == const0_rtx)
-           emit_move_insn (target, op1);
-         else if (temp != const_true_rtx)
-           {
-             if (bcc_gen_fctn[(int) GET_CODE (temp)] != 0)
-               emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (temp)]) (op0));
-             else
-               abort ();
-             emit_move_insn (target, op1);
-           }
+         int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)));
+         do_compare_rtx_and_jump (target, op1, code == MAX_EXPR ? GE : LE,
+                                  unsignedp, mode, NULL_RTX, 0, NULL_RTX,
+                                  op0);
        }
+      emit_move_insn (target, op1);
       emit_label (op0);
       return target;
 
@@ -8626,7 +8611,6 @@ do_jump (exp, if_false_label, if_true_label)
      These cases set DROP_THROUGH_LABEL nonzero.  */
   rtx drop_through_label = 0;
   rtx temp;
-  rtx comparison = 0;
   int i;
   tree type;
   enum machine_mode mode;
@@ -8692,10 +8676,10 @@ do_jump (exp, if_false_label, if_true_label)
 
     case MINUS_EXPR:
       /* Non-zero iff operands of minus differ.  */
-      comparison = compare (build (NE_EXPR, TREE_TYPE (exp),
-                                  TREE_OPERAND (exp, 0),
-                                  TREE_OPERAND (exp, 1)),
-                           NE, NE);
+      do_compare_and_jump (build (NE_EXPR, TREE_TYPE (exp),
+                                 TREE_OPERAND (exp, 0),
+                                 TREE_OPERAND (exp, 1)),
+                          NE, NE, if_false_label, if_true_label);
       break;
 
     case BIT_AND_EXPR:
@@ -8854,7 +8838,7 @@ do_jump (exp, if_false_label, if_true_label)
                 && !can_compare_p (TYPE_MODE (inner_type)))
          do_jump_by_parts_equality (exp, if_false_label, if_true_label);
        else
-         comparison = compare (exp, EQ, EQ);
+         do_compare_and_jump (exp, EQ, EQ, if_false_label, if_true_label);
        break;
       }
 
@@ -8894,7 +8878,7 @@ do_jump (exp, if_false_label, if_true_label)
                 && !can_compare_p (TYPE_MODE (inner_type)))
          do_jump_by_parts_equality (exp, if_true_label, if_false_label);
        else
-         comparison = compare (exp, NE, NE);
+         do_compare_and_jump (exp, NE, NE, if_false_label, if_true_label);
        break;
       }
 
@@ -8904,7 +8888,7 @@ do_jump (exp, if_false_label, if_true_label)
          && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label);
       else
-       comparison = compare (exp, LT, LTU);
+       do_compare_and_jump (exp, LT, LTU, if_false_label, if_true_label);
       break;
 
     case LE_EXPR:
@@ -8913,7 +8897,7 @@ do_jump (exp, if_false_label, if_true_label)
          && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label);
       else
-       comparison = compare (exp, LE, LEU);
+       do_compare_and_jump (exp, LE, LEU, if_false_label, if_true_label);
       break;
 
     case GT_EXPR:
@@ -8922,7 +8906,7 @@ do_jump (exp, if_false_label, if_true_label)
          && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label);
       else
-       comparison = compare (exp, GT, GTU);
+       do_compare_and_jump (exp, GT, GTU, if_false_label, if_true_label);
       break;
 
     case GE_EXPR:
@@ -8931,7 +8915,7 @@ do_jump (exp, if_false_label, if_true_label)
          && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label);
       else
-       comparison = compare (exp, GE, GEU);
+       do_compare_and_jump (exp, GE, GEU, if_false_label, if_true_label);
       break;
 
     default:
@@ -8947,42 +8931,28 @@ do_jump (exp, if_false_label, if_true_label)
        temp = copy_to_reg (temp);
 #endif
       do_pending_stack_adjust ();
-      if (GET_CODE (temp) == CONST_INT)
-       comparison = (temp == const0_rtx ? const0_rtx : const_true_rtx);
-      else if (GET_CODE (temp) == LABEL_REF)
-       comparison = const_true_rtx;
+      /* Do any postincrements in the expression that was tested.  */
+      emit_queue ();
+
+      if (GET_CODE (temp) == CONST_INT || GET_CODE (temp) == LABEL_REF)
+       {
+         rtx target = temp == const0_rtx ? if_false_label : if_true_label;
+         if (target)
+           emit_jump (target);
+       }
       else if (GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
-              && !can_compare_p (GET_MODE (temp)))
+              && ! can_compare_p (GET_MODE (temp)))
        /* Note swapping the labels gives us not-equal.  */
        do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label);
       else if (GET_MODE (temp) != VOIDmode)
-       comparison = compare_from_rtx (temp, CONST0_RTX (GET_MODE (temp)),
-                                      NE, TREE_UNSIGNED (TREE_TYPE (exp)),
-                                      GET_MODE (temp), NULL_RTX, 0);
+       do_compare_rtx_and_jump (temp, CONST0_RTX (GET_MODE (temp)),
+                                NE, TREE_UNSIGNED (TREE_TYPE (exp)),
+                                GET_MODE (temp), NULL_RTX, 0,
+                                if_false_label, if_true_label);
       else
        abort ();
     }
 
-  /* Do any postincrements in the expression that was tested.  */
-  emit_queue ();
-
-  /* If COMPARISON is nonzero here, it is an rtx that can be substituted
-     straight into a conditional jump instruction as the jump condition.
-     Otherwise, all the work has been done already.  */
-
-  if (comparison == const_true_rtx)
-    {
-      if (if_true_label)
-       emit_jump (if_true_label);
-    }
-  else if (comparison == const0_rtx)
-    {
-      if (if_false_label)
-       emit_jump (if_false_label);
-    }
-  else if (comparison)
-    do_jump_for_compare (comparison, if_false_label, if_true_label);
-
   if (drop_through_label)
     {
       /* If do_jump produces code that might be jumped around,
@@ -9007,57 +8977,9 @@ do_jump_by_parts_greater (exp, swap, if_false_label, if_true_label)
   rtx op0 = expand_expr (TREE_OPERAND (exp, swap), NULL_RTX, VOIDmode, 0);
   rtx op1 = expand_expr (TREE_OPERAND (exp, !swap), NULL_RTX, VOIDmode, 0);
   enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-  int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
-  rtx drop_through_label = 0;
   int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)));
-  int i;
-
-  if (! if_true_label || ! if_false_label)
-    drop_through_label = gen_label_rtx ();
-  if (! if_true_label)
-    if_true_label = drop_through_label;
-  if (! if_false_label)
-    if_false_label = drop_through_label;
 
-  /* Compare a word at a time, high order first.  */
-  for (i = 0; i < nwords; i++)
-    {
-      rtx comp;
-      rtx op0_word, op1_word;
-
-      if (WORDS_BIG_ENDIAN)
-       {
-         op0_word = operand_subword_force (op0, i, mode);
-         op1_word = operand_subword_force (op1, i, mode);
-       }
-      else
-       {
-         op0_word = operand_subword_force (op0, nwords - 1 - i, mode);
-         op1_word = operand_subword_force (op1, nwords - 1 - i, mode);
-       }
-
-      /* All but high-order word must be compared as unsigned.  */
-      comp = compare_from_rtx (op0_word, op1_word,
-                              (unsignedp || i > 0) ? GTU : GT,
-                              unsignedp, word_mode, NULL_RTX, 0);
-      if (comp == const_true_rtx)
-       emit_jump (if_true_label);
-      else if (comp != const0_rtx)
-       do_jump_for_compare (comp, NULL_RTX, if_true_label);
-
-      /* Consider lower words only if these are equal.  */
-      comp = compare_from_rtx (op0_word, op1_word, NE, unsignedp, word_mode,
-                              NULL_RTX, 0);
-      if (comp == const_true_rtx)
-       emit_jump (if_false_label);
-      else if (comp != const0_rtx)
-       do_jump_for_compare (comp, NULL_RTX, if_false_label);
-    }
-
-  if (if_false_label)
-    emit_jump (if_false_label);
-  if (drop_through_label)
-    emit_label (drop_through_label);
+  do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true_label);
 }
 
 /* Compare OP0 with OP1, word at a time, in mode MODE.
@@ -9100,21 +9022,13 @@ do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true
        }
 
       /* All but high-order word must be compared as unsigned.  */
-      comp = compare_from_rtx (op0_word, op1_word,
-                              (unsignedp || i > 0) ? GTU : GT,
-                              unsignedp, word_mode, NULL_RTX, 0);
-      if (comp == const_true_rtx)
-       emit_jump (if_true_label);
-      else if (comp != const0_rtx)
-       do_jump_for_compare (comp, NULL_RTX, if_true_label);
+      do_compare_rtx_and_jump (op0_word, op1_word, GT,
+                              (unsignedp || i > 0), word_mode, NULL_RTX, 0,
+                              NULL_RTX, if_true_label);
 
       /* Consider lower words only if these are equal.  */
-      comp = compare_from_rtx (op0_word, op1_word, NE, unsignedp, word_mode,
-                              NULL_RTX, 0);
-      if (comp == const_true_rtx)
-       emit_jump (if_false_label);
-      else if (comp != const0_rtx)
-       do_jump_for_compare (comp, NULL_RTX, if_false_label);
+      do_compare_rtx_and_jump (op0_word, op1_word, NE, unsignedp, word_mode,
+                              NULL_RTX, 0, NULL_RTX, if_false_label);
     }
 
   if (if_false_label)
@@ -9142,16 +9056,11 @@ do_jump_by_parts_equality (exp, if_false_label, if_true_label)
     drop_through_label = if_false_label = gen_label_rtx ();
 
   for (i = 0; i < nwords; i++)
-    {
-      rtx comp = compare_from_rtx (operand_subword_force (op0, i, mode),
-                                  operand_subword_force (op1, i, mode),
-                                  EQ, TREE_UNSIGNED (TREE_TYPE (exp)),
-                                  word_mode, NULL_RTX, 0);
-      if (comp == const_true_rtx)
-       emit_jump (if_false_label);
-      else if (comp != const0_rtx)
-       do_jump_for_compare (comp, if_false_label, NULL_RTX);
-    }
+    do_compare_rtx_and_jump (operand_subword_force (op0, i, mode),
+                            operand_subword_force (op1, i, mode),
+                            EQ, TREE_UNSIGNED (TREE_TYPE (exp)),
+                            word_mode, NULL_RTX, 0, if_false_label,
+                            NULL_RTX);
 
   if (if_true_label)
     emit_jump (if_true_label);
@@ -9187,15 +9096,8 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
 
   if (part != 0)
     {
-      rtx comp = compare_from_rtx (part, const0_rtx, EQ, 1, word_mode,
-                                  NULL_RTX, 0);
-
-      if (comp == const_true_rtx)
-       emit_jump (if_false_label);
-      else if (comp == const0_rtx)
-       emit_jump (if_true_label);
-      else
-       do_jump_for_compare (comp, if_false_label, if_true_label);
+      do_compare_rtx_and_jump (part, const0_rtx, EQ, 1, word_mode,
+                              NULL_RTX, 0, if_false_label, if_true_label);
 
       return;
     }
@@ -9205,15 +9107,9 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
     drop_through_label = if_false_label = gen_label_rtx ();
 
   for (i = 0; i < nwords; i++)
-    {
-      rtx comp = compare_from_rtx (operand_subword_force (op0, i,
-                                                         GET_MODE (op0)),
-                                  const0_rtx, EQ, 1, word_mode, NULL_RTX, 0);
-      if (comp == const_true_rtx)
-       emit_jump (if_false_label);
-      else if (comp != const0_rtx)
-       do_jump_for_compare (comp, if_false_label, NULL_RTX);
-    }
+    do_compare_rtx_and_jump (operand_subword_force (op0, i, GET_MODE (op0)),
+                            const0_rtx, EQ, 1, word_mode, NULL_RTX, 0,
+                            if_false_label, NULL_RTX);
 
   if (if_true_label)
     emit_jump (if_true_label);
@@ -9221,168 +9117,84 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
   if (drop_through_label)
     emit_label (drop_through_label);
 }
-
-/* Given a comparison expression in rtl form, output conditional branches to
-   IF_TRUE_LABEL, IF_FALSE_LABEL, or both.  */
-
-static void
-do_jump_for_compare (comparison, if_false_label, if_true_label)
-     rtx comparison, if_false_label, if_true_label;
-{
-  if (if_true_label)
-    {
-      if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0)
-       emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)])
-                         (if_true_label));
-      else
-       abort ();
-
-      if (if_false_label)
-       emit_jump (if_false_label);
-    }
-  else if (if_false_label)
-    {
-      rtx first = get_last_insn (), insn, branch;
-      int br_count;
-
-      /* Output the branch with the opposite condition.  Then try to invert
-        what is generated.  If more than one insn is a branch, or if the
-        branch is not the last insn written, abort. If we can't invert
-        the branch, emit make a true label, redirect this jump to that,
-        emit a jump to the false label and define the true label.  */
-      /* ??? Note that we wouldn't have to do any of this nonsense if
-        we passed both labels into a combined compare-and-branch. 
-        Ah well, jump threading does a good job of repairing the damage.  */
-
-      if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0)
-       emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)])
-                         (if_false_label));
-      else
-       abort ();
-
-      /* Here we get the first insn that was just emitted.  It used to be the
-        case that, on some machines, emitting the branch would discard
-        the previous compare insn and emit a replacement.  This isn't
-        done anymore, but abort if we see that FIRST is deleted.  */
-
-      if (first == 0)
-       first = get_insns ();
-      else if (INSN_DELETED_P (first))
-       abort ();
-      else
-       first = NEXT_INSN (first);
-
-      /* Look for multiple branches in this sequence, as might be generated
-        for a multi-word integer comparison.  */
-
-      br_count = 0;
-      branch = NULL_RTX;
-      for (insn = first; insn ; insn = NEXT_INSN (insn))
-       if (GET_CODE (insn) == JUMP_INSN)
-         {
-           branch = insn;
-           br_count += 1;
-         }
-
-      /* If we've got one branch at the end of the sequence,
-        we can try to reverse it.  */
-
-      if (br_count == 1 && NEXT_INSN (branch) == NULL_RTX)
-       {
-         rtx insn_label;
-         insn_label = XEXP (condjump_label (branch), 0);
-         JUMP_LABEL (branch) = insn_label;
-
-         if (insn_label != if_false_label)
-           abort ();
-
-         if (invert_jump (branch, if_false_label))
-           return;
-       }
-
-      /* Multiple branches, or reversion failed.  Convert to branches
-        around an unconditional jump.  */
-
-      if_true_label = gen_label_rtx ();
-      for (insn = first; insn; insn = NEXT_INSN (insn))
-       if (GET_CODE (insn) == JUMP_INSN)
-         {
-           rtx insn_label;
-           insn_label = XEXP (condjump_label (insn), 0);
-           JUMP_LABEL (insn) = insn_label;
-
-           if (insn_label == if_false_label)
-             redirect_jump (insn, if_true_label);
-         }
-       emit_jump (if_false_label);
-       emit_label (if_true_label);
-    }
-}
 \f
-/* Generate code for a comparison expression EXP
+/* Generate code for a comparison of OP0 and OP1 with rtx code CODE.
    (including code to compute the values to be compared)
    and set (CC0) according to the result.
-   SIGNED_CODE should be the rtx operation for this comparison for
-   signed data; UNSIGNED_CODE, likewise for use if data is unsigned.
+   The decision as to signed or unsigned comparison must be made by the caller.
 
    We force a stack adjustment unless there are currently
-   things pushed on the stack that aren't yet used.  */
+   things pushed on the stack that aren't yet used.
 
-static rtx
-compare (exp, signed_code, unsigned_code)
-     register tree exp;
-     enum rtx_code signed_code, unsigned_code;
+   If MODE is BLKmode, SIZE is an RTX giving the size of the objects being
+   compared.
+
+   If ALIGN is non-zero, it is the alignment of this type; if zero, the
+   size of MODE should be used.  */
+
+rtx
+compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
+     register rtx op0, op1;
+     enum rtx_code code;
+     int unsignedp;
+     enum machine_mode mode;
+     rtx size;
+     int align;
 {
-  register rtx op0, op1;
-  register tree type;
-  register enum machine_mode mode;
-  int unsignedp;
-  enum rtx_code code;
+  rtx tem;
 
-  /* Don't crash if the comparison was erroneous.  */
-  op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
-  if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK)
-    return op0;
-  
-  op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
-  type = TREE_TYPE (TREE_OPERAND (exp, 0));
-  mode = TYPE_MODE (type);
-  unsignedp = TREE_UNSIGNED (type);
-  code = unsignedp ? unsigned_code : signed_code;
+  /* If one operand is constant, make it the second one.  Only do this
+     if the other operand is not constant as well.  */
 
-#ifdef HAVE_canonicalize_funcptr_for_compare
-  /* If function pointers need to be "canonicalized" before they can
-     be reliably compared, then canonicalize them.  */
-  if (HAVE_canonicalize_funcptr_for_compare
-      && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
-      && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))))
-         == FUNCTION_TYPE))
+  if ((CONSTANT_P (op0) && ! CONSTANT_P (op1))
+      || (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT))
     {
-      rtx new_op0 = gen_reg_rtx (mode);
-
-      emit_insn (gen_canonicalize_funcptr_for_compare (new_op0, op0));
-      op0 = new_op0;
+      tem = op0;
+      op0 = op1;
+      op1 = tem;
+      code = swap_condition (code);
     }
 
-  if (HAVE_canonicalize_funcptr_for_compare
-      && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE
-      && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))))
-         == FUNCTION_TYPE))
+  if (flag_force_mem)
     {
-      rtx new_op1 = gen_reg_rtx (mode);
+      op0 = force_not_mem (op0);
+      op1 = force_not_mem (op1);
+    }
 
-      emit_insn (gen_canonicalize_funcptr_for_compare (new_op1, op1));
-      op1 = new_op1;
+  do_pending_stack_adjust ();
+
+  if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT
+      && (tem = simplify_relational_operation (code, mode, op0, op1)) != 0)
+    return tem;
+
+#if 0
+  /* There's no need to do this now that combine.c can eliminate lots of
+     sign extensions.  This can be less efficient in certain cases on other
+     machines.  */
+
+  /* If this is a signed equality comparison, we can do it as an
+     unsigned comparison since zero-extension is cheaper than sign
+     extension and comparisons with zero are done as unsigned.  This is
+     the case even on machines that can do fast sign extension, since
+     zero-extension is easier to combine with other operations than
+     sign-extension is.  If we are comparing against a constant, we must
+     convert it to what it would look like unsigned.  */
+  if ((code == EQ || code == NE) && ! unsignedp
+      && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
+    {
+      if (GET_CODE (op1) == CONST_INT
+         && (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1))
+       op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0)));
+      unsignedp = 1;
     }
 #endif
+       
+  emit_cmp_insn (op0, op1, code, size, mode, unsignedp, align);
 
-  return compare_from_rtx (op0, op1, code, unsignedp, mode,
-                          ((mode == BLKmode)
-                           ? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX),
-                          TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
+  return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
 }
 
-/* Like compare but expects the values to compare as two rtx's.
+/* Like do_compare_and_jump but expects the values to compare as two rtx's.
    The decision as to signed or unsigned comparison must be made by the caller.
 
    If MODE is BLKmode, SIZE is an RTX giving the size of the objects being
@@ -9391,16 +9203,28 @@ compare (exp, signed_code, unsigned_code)
    If ALIGN is non-zero, it is the alignment of this type; if zero, the
    size of MODE should be used.  */
 
-rtx
-compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
+void
+do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, size, align,
+                        if_false_label, if_true_label)
      register rtx op0, op1;
      enum rtx_code code;
      int unsignedp;
      enum machine_mode mode;
      rtx size;
      int align;
+     rtx if_false_label, if_true_label;
 {
   rtx tem;
+  int dummy_true_label = 0;
+
+  /* Reverse the comparison if that is safe and we want to jump if it is
+     false.  */
+  if (! if_true_label && ! FLOAT_MODE_P (mode))
+    {
+      if_true_label = if_false_label;
+      if_false_label = 0;
+      code = reverse_condition (code);
+    }
 
   /* If one operand is constant, make it the second one.  Only do this
      if the other operand is not constant as well.  */
@@ -9424,7 +9248,19 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
 
   if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT
       && (tem = simplify_relational_operation (code, mode, op0, op1)) != 0)
-    return tem;
+    {
+      if (tem == const_true_rtx)
+       {
+         if (if_true_label)
+           emit_jump (if_true_label);
+       }
+      else
+       {
+         if (if_false_label)
+           emit_jump (if_false_label);
+       }
+      return;
+    }
 
 #if 0
   /* There's no need to do this now that combine.c can eliminate lots of
@@ -9447,10 +9283,90 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
       unsignedp = 1;
     }
 #endif
-       
-  emit_cmp_insn (op0, op1, code, size, mode, unsignedp, align);
 
-  return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
+  if (! if_true_label)
+    {
+      dummy_true_label = 1;
+      if_true_label = gen_label_rtx ();
+    }
+
+  emit_cmp_and_jump_insns (op0, op1, code, size, mode, unsignedp, align,
+                          if_true_label);
+
+  if (if_false_label)
+    emit_jump (if_false_label);
+  if (dummy_true_label)
+    emit_label (if_true_label);
+}
+
+/* Generate code for a comparison expression EXP (including code to compute
+   the values to be compared) and a conditional jump to IF_FALSE_LABEL and/or
+   IF_TRUE_LABEL.  One of the labels can be NULL_RTX, in which case the
+   generated code will drop through.
+   SIGNED_CODE should be the rtx operation for this comparison for
+   signed data; UNSIGNED_CODE, likewise for use if data is unsigned.
+
+   We force a stack adjustment unless there are currently
+   things pushed on the stack that aren't yet used.  */
+
+static void
+do_compare_and_jump (exp, signed_code, unsigned_code, if_false_label,
+                    if_true_label)
+     register tree exp;
+     enum rtx_code signed_code, unsigned_code;
+     rtx if_false_label, if_true_label;
+{
+  register rtx op0, op1;
+  register tree type;
+  register enum machine_mode mode;
+  int unsignedp;
+  enum rtx_code code;
+
+  /* Don't crash if the comparison was erroneous.  */
+  op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+  if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK)
+    return;
+
+  op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
+  type = TREE_TYPE (TREE_OPERAND (exp, 0));
+  mode = TYPE_MODE (type);
+  unsignedp = TREE_UNSIGNED (type);
+  code = unsignedp ? unsigned_code : signed_code;
+
+#ifdef HAVE_canonicalize_funcptr_for_compare
+  /* If function pointers need to be "canonicalized" before they can
+     be reliably compared, then canonicalize them.  */
+  if (HAVE_canonicalize_funcptr_for_compare
+      && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
+      && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))))
+         == FUNCTION_TYPE))
+    {
+      rtx new_op0 = gen_reg_rtx (mode);
+
+      emit_insn (gen_canonicalize_funcptr_for_compare (new_op0, op0));
+      op0 = new_op0;
+    }
+
+  if (HAVE_canonicalize_funcptr_for_compare
+      && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE
+      && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))))
+         == FUNCTION_TYPE))
+    {
+      rtx new_op1 = gen_reg_rtx (mode);
+
+      emit_insn (gen_canonicalize_funcptr_for_compare (new_op1, op1));
+      op1 = new_op1;
+    }
+#endif
+
+  /* Do any postincrements in the expression that was tested.  */
+  emit_queue ();
+
+  do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode,
+                          ((mode == BLKmode)
+                           ? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX),
+                          TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT,
+                          if_false_label, if_true_label);
 }
 \f
 /* Generate code to calculate EXP using a store-flag instruction
index 8319e25..b3fbaea 100644 (file)
@@ -801,6 +801,9 @@ extern void do_jump PROTO((tree, rtx, rtx));
 /* Generate rtl to compare two rtx's, will call emit_cmp_insn.  */
 extern rtx compare_from_rtx PROTO((rtx, rtx, enum rtx_code, int,
                                   enum machine_mode, rtx, int));
+extern void do_compare_rtx_and_jump PROTO((rtx, rtx, enum rtx_code, int,
+                                          enum machine_mode, rtx, int,
+                                          rtx, rtx));
 
 /* Generate a tablejump instruction (used for switch statements).  */
 extern void do_tablejump PROTO((rtx, enum machine_mode, rtx, rtx, rtx));
index c38d0b3..c7ffe78 100644 (file)
@@ -1998,7 +1998,7 @@ tidy_fallthru_edge (e, b, c)
 #ifdef HAVE_cc0
       /* If this was a conditional jump, we need to also delete
         the insn that set cc0.  */
-      if (! simplejump_p (q) && condjump_p (q))
+      if (! simplejump_p (q) && condjump_p (q) && sets_cc0_p (PREV_INSN (q)))
        q = PREV_INSN (q);
 #endif
 
index 9049ac0..af7f9d2 100644 (file)
@@ -1958,8 +1958,9 @@ expand_inline_function (fndecl, parms, target, ignore, type,
          if (condjump_p (insn) && ! simplejump_p (insn) && map->last_pc_value)
            {
 #ifdef HAVE_cc0
-             /* The previous insn set cc0 for us.  So delete it.  */
-             delete_insn (PREV_INSN (copy));
+             /* If the previous insn set cc0 for us, delete it.  */
+             if (sets_cc0_p (PREV_INSN (copy)))
+               delete_insn (PREV_INSN (copy));
 #endif
 
              /* If this is now a no-op, delete it.  */
index 3765133..2de77e5 100644 (file)
@@ -267,6 +267,15 @@ static void init_floating_libfuncs PROTO((optab, const char *, int));
 #ifdef HAVE_conditional_trap
 static void init_traps PROTO((void));
 #endif
+static int cmp_available_p PROTO((enum machine_mode, enum rtx_code, int));
+static void emit_cmp_and_jump_insn_1 PROTO((rtx, rtx, enum machine_mode,
+                                           enum rtx_code, int, rtx));
+static void prepare_cmp_insn PROTO((rtx *, rtx *, enum rtx_code, rtx,
+                                   enum machine_mode *, int *, int));
+static rtx prepare_operand PROTO((int, rtx, int, enum machine_mode,
+                                 enum machine_mode, int));
+static void prepare_float_lib_cmp PROTO((rtx *, rtx *, enum rtx_code,
+                                        enum machine_mode *, int *));
 \f
 /* Add a REG_EQUAL note to the last insn in SEQ.  TARGET is being set to
    the result of operation CODE applied to OP0 (and OP1 if it is a binary
@@ -1326,7 +1335,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
              carry_out = gen_reg_rtx (word_mode);
              carry_out = emit_store_flag_force (carry_out,
                                                 (binoptab == add_optab
-                                                 ? LTU : GTU),
+                                                 ? LT : GT),
                                                 x, op0_piece,
                                                 word_mode, 1, normalizep);
            }
@@ -1349,7 +1358,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
                  /* Get out carry from adding/subtracting carry in.  */
                  carry_tmp = emit_store_flag_force (carry_tmp,
                                                     binoptab == add_optab
-                                                    ? LTU : GTU,
+                                                    ? LT : GT,
                                                     x, carry_in,
                                                     word_mode, 1, normalizep);
 
@@ -2463,19 +2472,8 @@ expand_abs (mode, op0, target, safe)
     do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx, 
                                  NULL_RTX, op1);
   else
-    {
-      temp = compare_from_rtx (target, CONST0_RTX (mode), GE, 0, mode,
-                              NULL_RTX, 0);
-      if (temp == const1_rtx)
-       return target;
-      else if (temp != const0_rtx)
-       {
-         if (bcc_gen_fctn[(int) GET_CODE (temp)] != 0)
-           emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (temp)]) (op1));
-         else
-           abort ();
-       }
-    }
+    do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode,
+                            NULL_RTX, 0, NULL_RTX, op1);
 
   op0 = expand_unop (mode, neg_optab, target, target, 0);
   if (op0 != target)
@@ -2983,31 +2981,57 @@ emit_0_to_1_insn (x)
   emit_move_insn (x, const1_rtx);
 }
 
-/* Generate code to compare X with Y
-   so that the condition codes are set.
+/* Nonzero if we can perform a comparison of mode MODE for a conditional jump
+   straightforwardly.  */
 
-   MODE is the mode of the inputs (in case they are const_int).
-   UNSIGNEDP nonzero says that X and Y are unsigned;
+static int
+cmp_available_p (mode, code, can_use_tst_p)
+     enum machine_mode mode;
+     enum rtx_code code;
+     int can_use_tst_p;
+{
+  do
+    {
+      if (cmp_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing
+         || (can_use_tst_p
+             && tst_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing))
+       return 1;
+      mode = GET_MODE_WIDER_MODE (mode);
+    } while (mode != VOIDmode);
+
+  return 0;
+}
+
+/* This function is called when we are going to emit a compare instruction that
+   compares the values found in *PX and *PY, using the rtl operator COMPARISON.
+
+   *PMODE is the mode of the inputs (in case they are const_int).
+   *PUNSIGNEDP nonzero says that the operands are unsigned;
    this matters if they need to be widened.
 
-   If they have mode BLKmode, then SIZE specifies the size of both X and Y,
-   and ALIGN specifies the known shared alignment of X and Y.
+   If they have mode BLKmode, then SIZE specifies the size of both operands,
+   and ALIGN specifies the known shared alignment of the operands.
 
-   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).
-   It is ignored for fixed-point and block comparisons;
-   it is used only for floating-point comparisons.  */
+   This function performs all the setup necessary so that the caller only has
+   to emit a single comparison insn.  This setup can involve doing a BLKmode
+   comparison or emitting a library call to perform the comparison if no insn
+   is available to handle it.
+   The values which are passed in through pointers can be modified; the caller
+   should perform the comparison on the modified values.  */
 
 void
-emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
-     rtx x, y;
+prepare_cmp_insn (px, py, comparison, size, pmode, punsignedp, align)
+     rtx *px, *py;
      enum rtx_code comparison;
      rtx size;
-     enum machine_mode mode;
-     int unsignedp;
+     enum machine_mode *pmode;
+     int *punsignedp;
      int align;
 {
+  enum machine_mode mode = *pmode;
+  rtx x = *px, y = *py;
+  int unsignedp = *punsignedp;
   enum mode_class class;
-  enum machine_mode wider_mode;
 
   class = GET_MODE_CLASS (mode);
 
@@ -3046,6 +3070,9 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
 
   if (mode == BLKmode)
     {
+      rtx result;
+      enum machine_mode result_mode;
+
       emit_queue ();
       x = protect_from_queue (x, 0);
       y = protect_from_queue (y, 0);
@@ -3057,12 +3084,9 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
          && GET_CODE (size) == CONST_INT
          && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode)))
        {
-         enum machine_mode result_mode
-           = insn_operand_mode[(int) CODE_FOR_cmpstrqi][0];
-         rtx result = gen_reg_rtx (result_mode);
+         result_mode = insn_operand_mode[(int) CODE_FOR_cmpstrqi][0];
+         result = gen_reg_rtx (result_mode);
          emit_insn (gen_cmpstrqi (result, x, y, size, GEN_INT (align)));
-         emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX,
-                        result_mode, 0, 0);
        }
       else
 #endif
@@ -3071,33 +3095,25 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
          && GET_CODE (size) == CONST_INT
          && INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode)))
        {
-         enum machine_mode result_mode
-           = insn_operand_mode[(int) CODE_FOR_cmpstrhi][0];
-         rtx result = gen_reg_rtx (result_mode);
+         result_mode = insn_operand_mode[(int) CODE_FOR_cmpstrhi][0];
+         result = gen_reg_rtx (result_mode);
          emit_insn (gen_cmpstrhi (result, x, y, size, GEN_INT (align)));
-         emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX,
-                        result_mode, 0, 0);
        }
       else
 #endif
 #ifdef HAVE_cmpstrsi
       if (HAVE_cmpstrsi)
        {
-         enum machine_mode result_mode
-           = insn_operand_mode[(int) CODE_FOR_cmpstrsi][0];
-         rtx result = gen_reg_rtx (result_mode);
+         result_mode = insn_operand_mode[(int) CODE_FOR_cmpstrsi][0];
+         result = gen_reg_rtx (result_mode);
          size = protect_from_queue (size, 0);
          emit_insn (gen_cmpstrsi (result, x, y,
                                   convert_to_mode (SImode, size, 1),
                                   GEN_INT (align)));
-         emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX,
-                        result_mode, 0, 0);
        }
       else
 #endif
        {
-         rtx result;
-
 #ifdef TARGET_MEM_FUNCTIONS
          emit_library_call (memcmp_libfunc, 0,
                             TYPE_MODE (integer_type_node), 3,
@@ -3119,83 +3135,24 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
             register so reload doesn't clobber the value if it needs
             the return register for a spill reg.  */
          result = gen_reg_rtx (TYPE_MODE (integer_type_node));
+         result_mode = TYPE_MODE (integer_type_node);
          emit_move_insn (result,
-                         hard_libcall_value (TYPE_MODE (integer_type_node)));
-         emit_cmp_insn (result,
-                        const0_rtx, comparison, NULL_RTX,
-                        TYPE_MODE (integer_type_node), 0, 0);
+                         hard_libcall_value (result_mode));
        }
+      *px = result;
+      *py = const0_rtx;
+      *pmode = result_mode;
       return;
     }
 
-  /* Handle some compares against zero.  */
-
-  if (y == CONST0_RTX (mode)
-      && tst_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
-    {
-      int icode = (int) tst_optab->handlers[(int) mode].insn_code;
-
-      emit_queue ();
-      x = protect_from_queue (x, 0);
-      y = protect_from_queue (y, 0);
-
-      /* Now, if insn does accept these operands, put them into pseudos.  */
-      if (! (*insn_operand_predicate[icode][0])
-         (x, insn_operand_mode[icode][0]))
-       x = copy_to_mode_reg (insn_operand_mode[icode][0], x);
-
-      emit_insn (GEN_FCN (icode) (x));
-      return;
-    }
-
-  /* Handle compares for which there is a directly suitable insn.  */
-
-  if (cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
-    {
-      int icode = (int) cmp_optab->handlers[(int) mode].insn_code;
-
-      emit_queue ();
-      x = protect_from_queue (x, 0);
-      y = protect_from_queue (y, 0);
-
-      /* Now, if insn doesn't accept these operands, put them into pseudos.  */
-      if (! (*insn_operand_predicate[icode][0])
-         (x, insn_operand_mode[icode][0]))
-       x = copy_to_mode_reg (insn_operand_mode[icode][0], x);
-
-      if (! (*insn_operand_predicate[icode][1])
-         (y, insn_operand_mode[icode][1]))
-       y = copy_to_mode_reg (insn_operand_mode[icode][1], y);
-
-      emit_insn (GEN_FCN (icode) (x, y));
-      return;
-    }
-
-  /* Try widening if we can find a direct insn that way.  */
-
-  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
-    {
-      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
-          wider_mode = GET_MODE_WIDER_MODE (wider_mode))
-       {
-         if (cmp_optab->handlers[(int) wider_mode].insn_code
-             != CODE_FOR_nothing)
-           {
-             x = protect_from_queue (x, 0);
-             y = protect_from_queue (y, 0);
-             x = convert_modes (wider_mode, mode, x, unsignedp);
-             y = convert_modes (wider_mode, mode, y, unsignedp);
-             emit_cmp_insn (x, y, comparison, NULL_RTX,
-                            wider_mode, unsignedp, align);
-             return;
-           }
-       }
-    }
+  *px = x;
+  *py = y;
+  if (cmp_available_p (mode, comparison, y == CONST0_RTX (mode)))
+    return;
 
   /* Handle a lib call just for the mode we are using.  */
 
-  if (cmp_optab->handlers[(int) mode].libfunc
-      && class != MODE_FLOAT)
+  if (cmp_optab->handlers[(int) mode].libfunc && class != MODE_FLOAT)
     {
       rtx libfunc = cmp_optab->handlers[(int) mode].libfunc;
       rtx result;
@@ -3217,18 +3174,99 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
       /* Integer comparison returns a result that must be compared against 1,
         so that even if we do an unsigned compare afterward,
         there is still a value that can represent the result "less than".  */
-      emit_cmp_insn (result, const1_rtx,
-                    comparison, NULL_RTX, word_mode, unsignedp, 0);
+      *px = result;
+      *py = const1_rtx;
+      *pmode = word_mode;
       return;
     }
 
   if (class == MODE_FLOAT)
-    emit_float_lib_cmp (x, y, comparison);
+    prepare_float_lib_cmp (px, py, comparison, pmode, punsignedp);
 
   else
     abort ();
 }
 
+/* Before emitting an insn with code ICODE, make sure that X, which is going
+   to be used for operand OPNUM of the insn, is converted from mode MODE to
+   WIDER_MODE (UNSIGNEDP determines whether it is a unsigned conversion), and
+   that it is accepted by the operand predicate.  Return the new value.  */
+static rtx
+prepare_operand (icode, x, opnum, mode, wider_mode, unsignedp)
+     int icode;
+     rtx x;
+     int opnum;
+     enum machine_mode mode, wider_mode;
+     int unsignedp;
+{
+  x = protect_from_queue (x, 0);
+
+  if (mode != wider_mode)
+    x = convert_modes (wider_mode, mode, x, unsignedp);
+
+  if (! (*insn_operand_predicate[icode][opnum])
+      (x, insn_operand_mode[icode][opnum]))
+    x = copy_to_mode_reg (insn_operand_mode[icode][opnum], x);
+  return x;
+}
+
+/* Subroutine of emit_cmp_and_jump_insns; this function is called when we know
+   we can do the comparison.
+   The arguments are the same as for emit_cmp_and_jump_insns; but LABEL may
+   be NULL_RTX which indicates that only a comparison is to be generated.  */
+
+static void
+emit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label)
+     rtx x, y;
+     enum machine_mode mode;
+     enum rtx_code comparison;
+     int unsignedp;
+     rtx label;
+{
+  rtx test = gen_rtx_fmt_ee (comparison, mode, x, y);
+  enum mode_class class = GET_MODE_CLASS (mode);
+  enum machine_mode wider_mode = mode;
+
+  /* Try combined insns first.  */
+  do
+    {
+      enum insn_code icode;
+      PUT_MODE (test, wider_mode);
+
+      /* Handle some compares against zero.  */
+      icode = (int) tst_optab->handlers[(int) wider_mode].insn_code;
+      if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing)
+       {
+         x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
+         emit_insn (GEN_FCN (icode) (x));
+         if (label)
+           emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label));
+         return;
+       }
+
+      /* Handle compares for which there is a directly suitable insn.  */
+
+      icode = (int) cmp_optab->handlers[(int) wider_mode].insn_code;
+      if (icode != CODE_FOR_nothing)
+       {
+         x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
+         y = prepare_operand (icode, y, 1, mode, wider_mode, unsignedp);
+         emit_insn (GEN_FCN (icode) (x, y));
+         if (label)
+           emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label));
+         return;
+       }
+
+      if (class != MODE_INT && class != MODE_FLOAT
+         && class != MODE_COMPLEX_FLOAT)
+       break;
+
+      wider_mode = GET_MODE_WIDER_MODE (wider_mode);
+    } while (wider_mode != VOIDmode);
+
+  abort ();
+}
+
 /* Generate code to compare X with Y so that the condition codes are
    set and to jump to LABEL if the condition is true.  If X is a
    constant and Y is not a constant, then the comparison is swapped to
@@ -3281,11 +3319,24 @@ emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, label)
     op0 = force_reg (mode, op0);
 #endif
 
-  emit_cmp_insn (op0, op1, comparison, size, mode, unsignedp, align);
-
+  emit_queue ();
   if (unsignedp)
     comparison = unsigned_condition (comparison);
-  emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label));
+  prepare_cmp_insn (&op0, &op1, comparison, size, &mode, &unsignedp, align);
+  emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label);
+}
+
+/* Like emit_cmp_and_jump_insns, but generate only the comparison.  */
+void
+emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
+     rtx x, y;
+     enum rtx_code comparison;
+     rtx size;
+     enum machine_mode mode;
+     int unsignedp;
+     int align;
+{
+  emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, 0);
 }
 
 
@@ -3310,10 +3361,13 @@ can_compare_p (mode)
    COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).  */
 
 void
-emit_float_lib_cmp (x, y, comparison)
-     rtx x, y;
+prepare_float_lib_cmp (px, py, comparison, pmode, punsignedp)
+     rtx *px, *py;
      enum rtx_code comparison;
+     enum machine_mode *pmode;
+     int *punsignedp;
 {
+  rtx x = *px, y = *py;
   enum machine_mode mode = GET_MODE (x);
   rtx libfunc = 0;
   rtx result;
@@ -3481,9 +3535,9 @@ emit_float_lib_cmp (x, y, comparison)
            {
              x = protect_from_queue (x, 0);
              y = protect_from_queue (y, 0);
-             x = convert_to_mode (wider_mode, x, 0);
-             y = convert_to_mode (wider_mode, y, 0);
-             emit_float_lib_cmp (x, y, comparison);
+             *px = convert_to_mode (wider_mode, x, 0);
+             *py = convert_to_mode (wider_mode, y, 0);
+             prepare_float_lib_cmp (px, py, comparison, pmode, punsignedp);
              return;
            }
        }
@@ -3501,9 +3555,10 @@ emit_float_lib_cmp (x, y, comparison)
      the return register for a spill reg.  */
   result = gen_reg_rtx (word_mode);
   emit_move_insn (result, hard_libcall_value (word_mode));
-
-  emit_cmp_insn (result, const0_rtx, comparison,
-                NULL_RTX, word_mode, 0, 0);
+  *px = result;
+  *py = const0_rtx;
+  *pmode = word_mode;
+  *punsignedp = 0;
 }
 \f
 /* Generate code to indirectly jump to a location given in the rtx LOC.  */
index c65d101..8bfd6b7 100644 (file)
@@ -339,15 +339,13 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
        }
       else if (GET_CODE (last_loop_insn) == JUMP_INSN)
        {
+         rtx prev = PREV_INSN (last_loop_insn);
+         delete_insn (last_loop_insn);
 #ifdef HAVE_cc0
-         /* The immediately preceding insn is a compare which must be
+         /* The immediately preceding insn may be a compare which must be
             deleted.  */
-         delete_insn (last_loop_insn);
-         delete_insn (PREV_INSN (last_loop_insn));
-#else
-         /* The immediately preceding insn may not be the compare, so don't
-            delete it.  */
-         delete_insn (last_loop_insn);
+         if (sets_cc0_p (prev))
+           delete_insn (prev);
 #endif
        }
       return;
@@ -479,14 +477,12 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
        copy_end = PREV_INSN (PREV_INSN (last_loop_insn));
       else if (GET_CODE (last_loop_insn) == JUMP_INSN)
        {
+         copy_end = PREV_INSN (last_loop_insn);
 #ifdef HAVE_cc0
-         /* The instruction immediately before the JUMP_INSN is a compare
+         /* The instruction immediately before the JUMP_INSN may be a compare
             instruction which we do not want to copy.  */
-         copy_end = PREV_INSN (PREV_INSN (last_loop_insn));
-#else
-         /* The instruction immediately before the JUMP_INSN may not be the
-            compare, so we must copy it.  */
-         copy_end = PREV_INSN (last_loop_insn);
+         if (sets_cc0_p (PREV_INSN (copy_end)))
+           copy_end = PREV_INSN (copy_end);
 #endif
        }
       else
@@ -520,17 +516,14 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
        }
       else if (GET_CODE (last_loop_insn) == JUMP_INSN)
        {
+         insert_before = last_loop_insn;
 #ifdef HAVE_cc0
-         /* The instruction immediately before the JUMP_INSN is a compare
+         /* The instruction immediately before the JUMP_INSN may be a compare
             instruction which we do not want to copy or delete.  */
-         insert_before = PREV_INSN (last_loop_insn);
-         copy_end = PREV_INSN (insert_before);
-#else
-         /* The instruction immediately before the JUMP_INSN may not be the
-            compare, so we must copy it.  */
-         insert_before = last_loop_insn;
-         copy_end = PREV_INSN (last_loop_insn);
+         if (sets_cc0_p (PREV_INSN (insert_before)))
+           insert_before = PREV_INSN (insert_before);
 #endif
+         copy_end = PREV_INSN (insert_before);
        }
       else
        {
@@ -793,9 +786,9 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
        copy_end_luid--;
 
       /* If we have a target that uses cc0, then we also must not duplicate
-        the insn that sets cc0 before the jump insn.  */
+        the insn that sets cc0 before the jump insn, if one is present.  */
 #ifdef HAVE_cc0
-      if (GET_CODE (copy_end) == JUMP_INSN)
+      if (GET_CODE (copy_end) == JUMP_INSN && sets_cc0_p (PREV_INSN (copy_end)))
        copy_end_luid--;
 #endif
 
@@ -1036,14 +1029,12 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
            copy_end = PREV_INSN (PREV_INSN (last_loop_insn));
          else if (GET_CODE (last_loop_insn) == JUMP_INSN)
            {
+             copy_end = PREV_INSN (last_loop_insn);
 #ifdef HAVE_cc0
-             /* The immediately preceding insn is a compare which we do not
+             /* The immediately preceding insn may be a compare which we do not
                 want to copy.  */
-             copy_end = PREV_INSN (PREV_INSN (last_loop_insn));
-#else
-             /* The immediately preceding insn may not be a compare, so we
-                must copy it.  */
-             copy_end = PREV_INSN (last_loop_insn);
+             if (sets_cc0_p (PREV_INSN (copy_end)))
+               copy_end = PREV_INSN (copy_end);
 #endif
            }
          else
@@ -1098,17 +1089,14 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
            }
          else
            {
-#ifdef HAVE_cc0
-             /* The immediately preceding insn is a compare which we do not
-                want to copy.  */
-             insert_before = PREV_INSN (last_loop_insn);
-             copy_end = PREV_INSN (insert_before);
-#else
-             /* The immediately preceding insn may not be a compare, so we
-                must copy it.  */
              insert_before = last_loop_insn;
-             copy_end = PREV_INSN (last_loop_insn);
+#ifdef HAVE_cc0
+             /* The instruction immediately before the JUMP_INSN may be a compare
+                instruction which we do not want to copy or delete.  */
+             if (sets_cc0_p (PREV_INSN (insert_before)))
+               insert_before = PREV_INSN (insert_before);
 #endif
+             copy_end = PREV_INSN (insert_before);
            }
 
          /* Set unroll type to MODULO now.  */
@@ -2089,8 +2077,9 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
          if (condjump_p (insn) && !simplejump_p (insn) && map->last_pc_value)
            {
 #ifdef HAVE_cc0
-             /* The previous insn set cc0 for us.  So delete it.  */
-             delete_insn (PREV_INSN (copy));
+             /* If the previous insn set cc0 for us, delete it.  */
+             if (sets_cc0_p (PREV_INSN (copy)))
+               delete_insn (PREV_INSN (copy));
 #endif
 
              /* If this is now a no-op, delete it.  */