OSDN Git Service

PR debug/43670
[pf3gnuchains/gcc-fork.git] / gcc / dojump.c
index f19cbcc..0ebf932 100644 (file)
@@ -1,12 +1,13 @@
 /* Convert tree expression to rtl instructions, for GNU compiler.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
 /* Convert tree expression to rtl instructions, for GNU compiler.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
 
 #include "config.h"
 #include "system.h"
@@ -34,12 +34,22 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "optabs.h"
 #include "langhooks.h"
 #include "ggc.h"
 #include "optabs.h"
 #include "langhooks.h"
 #include "ggc.h"
+#include "basic-block.h"
+#include "output.h"
 
 static bool prefer_and_bit_test (enum machine_mode, int);
 
 static bool prefer_and_bit_test (enum machine_mode, int);
-static void do_jump_by_parts_greater (tree, int, rtx, rtx);
-static void do_jump_by_parts_equality (tree, rtx, rtx);
-static void do_compare_and_jump        (tree, enum rtx_code, enum rtx_code, rtx,
-                                rtx);
+static void do_jump_by_parts_greater (tree, tree, int, rtx, rtx, int);
+static void do_jump_by_parts_equality (tree, tree, rtx, rtx, int);
+static void do_compare_and_jump        (tree, tree, enum rtx_code, enum rtx_code, rtx,
+                                rtx, int);
+
+/* Invert probability if there is any.  -1 stands for unknown.  */
+
+static inline int
+inv (int prob)
+{
+  return prob == -1 ? -1 : REG_BR_PROB_BASE - prob;
+}
 
 /* At the start of a function, record that we have no previously-pushed
    arguments waiting to be popped.  */
 
 /* At the start of a function, record that we have no previously-pushed
    arguments waiting to be popped.  */
@@ -50,6 +60,16 @@ init_pending_stack_adjust (void)
   pending_stack_adjust = 0;
 }
 
   pending_stack_adjust = 0;
 }
 
+/* Discard any pending stack adjustment.  This avoid relying on the
+   RTL optimizers to remove useless adjustments when we know the
+   stack pointer value is dead.  */
+void
+discard_pending_stack_adjust (void)
+{
+  stack_pointer_delta -= pending_stack_adjust;
+  pending_stack_adjust = 0;
+}
+
 /* When exiting from function, if safe, clear out any pending stack adjust
    so the adjustment won't get done.
 
 /* When exiting from function, if safe, clear out any pending stack adjust
    so the adjustment won't get done.
 
@@ -60,14 +80,9 @@ void
 clear_pending_stack_adjust (void)
 {
   if (optimize > 0
 clear_pending_stack_adjust (void)
 {
   if (optimize > 0
-      && (! flag_omit_frame_pointer || current_function_calls_alloca)
-      && EXIT_IGNORE_STACK
-      && ! (DECL_INLINE (current_function_decl) && ! flag_no_inline)
-      && ! flag_inline_functions)
-    {
-      stack_pointer_delta -= pending_stack_adjust,
-      pending_stack_adjust = 0;
-    }
+      && (! flag_omit_frame_pointer || cfun->calls_alloca)
+      && EXIT_IGNORE_STACK)
+    discard_pending_stack_adjust ();
 }
 
 /* Pop any previously-pushed arguments that have not been popped yet.  */
 }
 
 /* Pop any previously-pushed arguments that have not been popped yet.  */
@@ -90,17 +105,29 @@ do_pending_stack_adjust (void)
    functions here.  */
 
 void
    functions here.  */
 
 void
-jumpifnot (tree exp, rtx label)
+jumpifnot (tree exp, rtx label, int prob)
 {
 {
-  do_jump (exp, label, NULL_RTX);
+  do_jump (exp, label, NULL_RTX, inv (prob));
+}
+
+void
+jumpifnot_1 (enum tree_code code, tree op0, tree op1, rtx label, int prob)
+{
+  do_jump_1 (code, op0, op1, label, NULL_RTX, inv (prob));
 }
 
 /* Generate code to evaluate EXP and jump to LABEL if the value is nonzero.  */
 
 void
 }
 
 /* Generate code to evaluate EXP and jump to LABEL if the value is nonzero.  */
 
 void
-jumpif (tree exp, rtx label)
+jumpif (tree exp, rtx label, int prob)
 {
 {
-  do_jump (exp, NULL_RTX, label);
+  do_jump (exp, NULL_RTX, label, prob);
+}
+
+void
+jumpif_1 (enum tree_code code, tree op0, tree op1, rtx label, int prob)
+{
+  do_jump_1 (code, op0, op1, NULL_RTX, label, prob);
 }
 
 /* Used internally by prefer_and_bit_test.  */
 }
 
 /* Used internally by prefer_and_bit_test.  */
@@ -135,11 +162,191 @@ prefer_and_bit_test (enum machine_mode mode, int bitnum)
     }
 
   /* Fill in the integers.  */
     }
 
   /* Fill in the integers.  */
-  XEXP (and_test, 1) = GEN_INT ((unsigned HOST_WIDE_INT) 1 << bitnum);
+  XEXP (and_test, 1)
+    = immed_double_int_const (double_int_setbit (double_int_zero, bitnum),
+                                                mode);
   XEXP (XEXP (shift_test, 0), 1) = GEN_INT (bitnum);
 
   XEXP (XEXP (shift_test, 0), 1) = GEN_INT (bitnum);
 
-  return (rtx_cost (and_test, IF_THEN_ELSE)
-         <= rtx_cost (shift_test, IF_THEN_ELSE));
+  return (rtx_cost (and_test, IF_THEN_ELSE, optimize_insn_for_speed_p ())
+         <= rtx_cost (shift_test, IF_THEN_ELSE, optimize_insn_for_speed_p ()));
+}
+
+/* Subroutine of do_jump, dealing with exploded comparisons of the type
+   OP0 CODE OP1 .  IF_FALSE_LABEL and IF_TRUE_LABEL like in do_jump.
+   PROB is probability of jump to if_true_label, or -1 if unknown.  */
+
+void
+do_jump_1 (enum tree_code code, tree op0, tree op1,
+          rtx if_false_label, rtx if_true_label, int prob)
+{
+  enum machine_mode mode;
+  rtx drop_through_label = 0;
+
+  switch (code)
+    {
+    case EQ_EXPR:
+      {
+        tree inner_type = TREE_TYPE (op0);
+
+        gcc_assert (GET_MODE_CLASS (TYPE_MODE (inner_type))
+                   != MODE_COMPLEX_FLOAT);
+       gcc_assert (GET_MODE_CLASS (TYPE_MODE (inner_type))
+                   != MODE_COMPLEX_INT);
+
+        if (integer_zerop (op1))
+         do_jump (op0, if_true_label, if_false_label, inv (prob));
+        else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
+                 && !can_compare_p (EQ, TYPE_MODE (inner_type), ccp_jump))
+         do_jump_by_parts_equality (op0, op1, if_false_label, if_true_label,
+                                    prob);
+        else
+         do_compare_and_jump (op0, op1, EQ, EQ, if_false_label, if_true_label,
+                              prob);
+        break;
+      }
+
+    case NE_EXPR:
+      {
+        tree inner_type = TREE_TYPE (op0);
+
+        gcc_assert (GET_MODE_CLASS (TYPE_MODE (inner_type))
+                   != MODE_COMPLEX_FLOAT);
+       gcc_assert (GET_MODE_CLASS (TYPE_MODE (inner_type))
+                   != MODE_COMPLEX_INT);
+
+        if (integer_zerop (op1))
+         do_jump (op0, if_false_label, if_true_label, prob);
+        else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
+           && !can_compare_p (NE, TYPE_MODE (inner_type), ccp_jump))
+         do_jump_by_parts_equality (op0, op1, if_true_label, if_false_label,
+                                    inv (prob));
+        else
+         do_compare_and_jump (op0, op1, NE, NE, if_false_label, if_true_label,
+                              prob);
+        break;
+      }
+
+    case LT_EXPR:
+      mode = TYPE_MODE (TREE_TYPE (op0));
+      if (GET_MODE_CLASS (mode) == MODE_INT
+          && ! can_compare_p (LT, mode, ccp_jump))
+       do_jump_by_parts_greater (op0, op1, 1, if_false_label, if_true_label,
+                                 prob);
+      else
+       do_compare_and_jump (op0, op1, LT, LTU, if_false_label, if_true_label,
+                            prob);
+      break;
+
+    case LE_EXPR:
+      mode = TYPE_MODE (TREE_TYPE (op0));
+      if (GET_MODE_CLASS (mode) == MODE_INT
+          && ! can_compare_p (LE, mode, ccp_jump))
+       do_jump_by_parts_greater (op0, op1, 0, if_true_label, if_false_label,
+                                 inv (prob));
+      else
+       do_compare_and_jump (op0, op1, LE, LEU, if_false_label, if_true_label,
+                            prob);
+      break;
+
+    case GT_EXPR:
+      mode = TYPE_MODE (TREE_TYPE (op0));
+      if (GET_MODE_CLASS (mode) == MODE_INT
+          && ! can_compare_p (GT, mode, ccp_jump))
+       do_jump_by_parts_greater (op0, op1, 0, if_false_label, if_true_label,
+                                 prob);
+      else
+       do_compare_and_jump (op0, op1, GT, GTU, if_false_label, if_true_label,
+                            prob);
+      break;
+
+    case GE_EXPR:
+      mode = TYPE_MODE (TREE_TYPE (op0));
+      if (GET_MODE_CLASS (mode) == MODE_INT
+          && ! can_compare_p (GE, mode, ccp_jump))
+       do_jump_by_parts_greater (op0, op1, 1, if_true_label, if_false_label,
+                                 inv (prob));
+      else
+       do_compare_and_jump (op0, op1, GE, GEU, if_false_label, if_true_label,
+                            prob);
+      break;
+
+    case ORDERED_EXPR:
+      do_compare_and_jump (op0, op1, ORDERED, ORDERED,
+                          if_false_label, if_true_label, prob);
+      break;
+
+    case UNORDERED_EXPR:
+      do_compare_and_jump (op0, op1, UNORDERED, UNORDERED,
+                          if_false_label, if_true_label, prob);
+      break;
+
+    case UNLT_EXPR:
+      do_compare_and_jump (op0, op1, UNLT, UNLT, if_false_label, if_true_label,
+                          prob);
+      break;
+
+    case UNLE_EXPR:
+      do_compare_and_jump (op0, op1, UNLE, UNLE, if_false_label, if_true_label,
+                          prob);
+      break;
+
+    case UNGT_EXPR:
+      do_compare_and_jump (op0, op1, UNGT, UNGT, if_false_label, if_true_label,
+                          prob);
+      break;
+
+    case UNGE_EXPR:
+      do_compare_and_jump (op0, op1, UNGE, UNGE, if_false_label, if_true_label,
+                          prob);
+      break;
+
+    case UNEQ_EXPR:
+      do_compare_and_jump (op0, op1, UNEQ, UNEQ, if_false_label, if_true_label,
+                          prob);
+      break;
+
+    case LTGT_EXPR:
+      do_compare_and_jump (op0, op1, LTGT, LTGT, if_false_label, if_true_label,
+                          prob);
+      break;
+
+    case TRUTH_ANDIF_EXPR:
+      if (if_false_label == NULL_RTX)
+        {
+         drop_through_label = gen_label_rtx ();
+         do_jump (op0, drop_through_label, NULL_RTX, prob);
+         do_jump (op1, NULL_RTX, if_true_label, prob);
+       }
+      else
+       {
+         do_jump (op0, if_false_label, NULL_RTX, prob);
+         do_jump (op1, if_false_label, if_true_label, prob);
+       }
+      break;
+
+    case TRUTH_ORIF_EXPR:
+      if (if_true_label == NULL_RTX)
+       {
+          drop_through_label = gen_label_rtx ();
+         do_jump (op0, NULL_RTX, drop_through_label, prob);
+         do_jump (op1, if_false_label, NULL_RTX, prob);
+       }
+      else
+       {
+         do_jump (op0, NULL_RTX, if_true_label, prob);
+         do_jump (op1, if_false_label, if_true_label, prob);
+       }
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  if (drop_through_label)
+    {
+      do_pending_stack_adjust ();
+      emit_label (drop_through_label);
+    }
 }
 
 /* Generate code to evaluate EXP and jump to IF_FALSE_LABEL if
 }
 
 /* Generate code to evaluate EXP and jump to IF_FALSE_LABEL if
@@ -151,23 +358,17 @@ prefer_and_bit_test (enum machine_mode mode, int bitnum)
    actually perform a jump.  An example where there is no jump
    is when EXP is `(foo (), 0)' and IF_FALSE_LABEL is null.
 
    actually perform a jump.  An example where there is no jump
    is when EXP is `(foo (), 0)' and IF_FALSE_LABEL is null.
 
-   This function is responsible for optimizing cases such as
-   &&, || and comparison operators in EXP.  */
+   PROB is probability of jump to if_true_label, or -1 if unknown.  */
 
 void
 
 void
-do_jump (tree exp, rtx if_false_label, rtx if_true_label)
+do_jump (tree exp, rtx if_false_label, rtx if_true_label, int prob)
 {
   enum tree_code code = TREE_CODE (exp);
 {
   enum tree_code code = TREE_CODE (exp);
-  /* Some cases need to create a label to jump to
-     in order to properly fall through.
-     These cases set DROP_THROUGH_LABEL nonzero.  */
-  rtx drop_through_label = 0;
   rtx temp;
   int i;
   tree type;
   enum machine_mode mode;
   rtx temp;
   int i;
   tree type;
   enum machine_mode mode;
-
-  emit_queue ();
+  rtx drop_through_label = 0;
 
   switch (code)
     {
 
   switch (code)
     {
@@ -189,12 +390,6 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
       break;
 #endif
 
       break;
 #endif
 
-    case UNSAVE_EXPR:
-      do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
-      TREE_OPERAND (exp, 0)
-       = lang_hooks.unsave_expr_now (TREE_OPERAND (exp, 0));
-      break;
-
     case NOP_EXPR:
       if (TREE_CODE (TREE_OPERAND (exp, 0)) == COMPONENT_REF
           || TREE_CODE (TREE_OPERAND (exp, 0)) == BIT_FIELD_REF
     case NOP_EXPR:
       if (TREE_CODE (TREE_OPERAND (exp, 0)) == COMPONENT_REF
           || TREE_CODE (TREE_OPERAND (exp, 0)) == BIT_FIELD_REF
@@ -208,113 +403,42 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
            < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0)))))
         goto normal;
     case NON_LVALUE_EXPR:
            < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0)))))
         goto normal;
     case NON_LVALUE_EXPR:
-    case REFERENCE_EXPR:
     case ABS_EXPR:
     case NEGATE_EXPR:
     case LROTATE_EXPR:
     case RROTATE_EXPR:
       /* These cannot change zero->nonzero or vice versa.  */
     case ABS_EXPR:
     case NEGATE_EXPR:
     case LROTATE_EXPR:
     case RROTATE_EXPR:
       /* These cannot change zero->nonzero or vice versa.  */
-      do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
+      do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label, prob);
       break;
 
       break;
 
-#if 0
-      /* This is never less insns than evaluating the PLUS_EXPR followed by
-         a test and can be longer if the test is eliminated.  */
-    case PLUS_EXPR:
-      /* Reduce to minus.  */
-      exp = build (MINUS_EXPR, TREE_TYPE (exp),
-                   TREE_OPERAND (exp, 0),
-                   fold (build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (exp, 1)),
-                                 TREE_OPERAND (exp, 1))));
-      /* Process as MINUS.  */
-#endif
-
-    case MINUS_EXPR:
-      /* Nonzero iff operands of minus differ.  */
-      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:
-      /* fold_single_bit_test() converts (X & (1 << C)) into (X >> C) & 1.
-        See if the former is preferred for jump tests and restore it
-        if so.  */
-      if (TREE_CODE (TREE_OPERAND (exp, 0)) == RSHIFT_EXPR
-         && integer_onep (TREE_OPERAND (exp, 1)))
-       {
-         tree arg = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
-         tree shift = TREE_OPERAND (TREE_OPERAND (exp, 0), 1);
-         tree one = TREE_OPERAND (exp, 1);
-         tree argtype = TREE_TYPE (arg);
-         if (TREE_CODE (shift) == INTEGER_CST
-             && compare_tree_int (shift, 0) > 0
-             && compare_tree_int (shift, HOST_BITS_PER_WIDE_INT) < 0
-             && prefer_and_bit_test (TYPE_MODE (argtype),
-                                     TREE_INT_CST_LOW (shift)))
-           {
-             do_jump (build (BIT_AND_EXPR, argtype, arg,
-                             fold (build (LSHIFT_EXPR, argtype, one, shift))),
-                      if_false_label, if_true_label);
-             break;
-           }
-       }
-
-      /* If we are AND'ing with a small constant, do this comparison in the
-         smallest type that fits.  If the machine doesn't have comparisons
-         that small, it will be converted back to the wider comparison.
-         This helps if we are testing the sign bit of a narrower object.
-         combine can't do this for us because it can't know whether a
-         ZERO_EXTRACT or a compare in a smaller mode exists, but we do.  */
-
-      if (! SLOW_BYTE_ACCESS
-          && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
-          && TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_WIDE_INT
-          && (i = tree_floor_log2 (TREE_OPERAND (exp, 1))) >= 0
-          && (mode = mode_for_size (i + 1, MODE_INT, 0)) != BLKmode
-          && (type = lang_hooks.types.type_for_mode (mode, 1)) != 0
-          && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
-          && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code
-              != CODE_FOR_nothing))
-        {
-          do_jump (convert (type, exp), if_false_label, if_true_label);
-          break;
-        }
-      goto normal;
-
     case TRUTH_NOT_EXPR:
     case TRUTH_NOT_EXPR:
-      do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
+      do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label,
+              inv (prob));
       break;
 
       break;
 
-    case TRUTH_ANDIF_EXPR:
-      if (if_false_label == 0)
-        if_false_label = drop_through_label = gen_label_rtx ();
-      do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
-      start_cleanup_deferral ();
-      do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
-      end_cleanup_deferral ();
-      break;
+    case COND_EXPR:
+      {
+       rtx label1 = gen_label_rtx ();
+       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;
+         }
 
 
-    case TRUTH_ORIF_EXPR:
-      if (if_true_label == 0)
-        if_true_label = drop_through_label = gen_label_rtx ();
-      do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
-      start_cleanup_deferral ();
-      do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
-      end_cleanup_deferral ();
-      break;
+        do_pending_stack_adjust ();
+       do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX, -1);
+       do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label, prob);
+        emit_label (label1);
+       do_jump (TREE_OPERAND (exp, 2), if_false_label, if_true_label, prob);
+       break;
+      }
 
     case COMPOUND_EXPR:
 
     case COMPOUND_EXPR:
-      push_temp_slots ();
-      expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
-      preserve_temp_slots (NULL_RTX);
-      free_temp_slots ();
-      pop_temp_slots ();
-      emit_queue ();
-      do_pending_stack_adjust ();
-      do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
-      break;
+      /* Lowered by gimplify.c.  */
+      gcc_unreachable ();
 
     case COMPONENT_REF:
     case BIT_FIELD_REF:
 
     case COMPONENT_REF:
     case BIT_FIELD_REF:
@@ -331,359 +455,185 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
         /* Get description of this reference.  We don't actually care
            about the underlying object here.  */
         get_inner_reference (exp, &bitsize, &bitpos, &offset, &mode,
         /* Get description of this reference.  We don't actually care
            about the underlying object here.  */
         get_inner_reference (exp, &bitsize, &bitpos, &offset, &mode,
-                             &unsignedp, &volatilep);
+                             &unsignedp, &volatilep, false);
 
         type = lang_hooks.types.type_for_size (bitsize, unsignedp);
         if (! SLOW_BYTE_ACCESS
             && type != 0 && bitsize >= 0
             && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
 
         type = lang_hooks.types.type_for_size (bitsize, unsignedp);
         if (! SLOW_BYTE_ACCESS
             && type != 0 && bitsize >= 0
             && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
-            && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code
-          != CODE_FOR_nothing))
+            && have_insn_for (COMPARE, TYPE_MODE (type)))
           {
           {
-            do_jump (convert (type, exp), if_false_label, if_true_label);
+           do_jump (fold_convert (type, exp), if_false_label, if_true_label,
+                    prob);
             break;
           }
         goto normal;
       }
 
             break;
           }
         goto normal;
       }
 
-    case COND_EXPR:
-      /* Do (a ? 1 : 0) and (a ? 0 : 1) as special cases.  */
-      if (integer_onep (TREE_OPERAND (exp, 1))
-          && integer_zerop (TREE_OPERAND (exp, 2)))
-        do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
-
-      else if (integer_zerop (TREE_OPERAND (exp, 1))
-               && integer_onep (TREE_OPERAND (exp, 2)))
-        do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
-
-      else
-      {
-        rtx label1 = gen_label_rtx ();
-        drop_through_label = gen_label_rtx ();
-
-        do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX);
-
-        start_cleanup_deferral ();
-        /* Now the THEN-expression.  */
-        do_jump (TREE_OPERAND (exp, 1),
-                 if_false_label ? if_false_label : drop_through_label,
-                 if_true_label ? if_true_label : drop_through_label);
-        /* In case the do_jump just above never jumps.  */
-        do_pending_stack_adjust ();
-        emit_label (label1);
-
-        /* Now the ELSE-expression.  */
-        do_jump (TREE_OPERAND (exp, 2),
-           if_false_label ? if_false_label : drop_through_label,
-           if_true_label ? if_true_label : drop_through_label);
-        end_cleanup_deferral ();
-      }
-      break;
+    case MINUS_EXPR:
+      /* Nonzero iff operands of minus differ.  */
+      code = NE_EXPR;
 
 
+      /* FALLTHRU */
     case EQ_EXPR:
     case EQ_EXPR:
-      {
-        tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
-
-        if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT
-            || GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT)
-          {
-            tree exp0 = save_expr (TREE_OPERAND (exp, 0));
-            tree exp1 = save_expr (TREE_OPERAND (exp, 1));
-            do_jump
-              (fold
-               (build (TRUTH_ANDIF_EXPR, TREE_TYPE (exp),
-                 fold (build (EQ_EXPR, TREE_TYPE (exp),
-                  fold (build1 (REALPART_EXPR,
-                    TREE_TYPE (inner_type),
-                    exp0)),
-                  fold (build1 (REALPART_EXPR,
-                    TREE_TYPE (inner_type),
-                    exp1)))),
-                 fold (build (EQ_EXPR, TREE_TYPE (exp),
-                  fold (build1 (IMAGPART_EXPR,
-                    TREE_TYPE (inner_type),
-                    exp0)),
-                  fold (build1 (IMAGPART_EXPR,
-                    TREE_TYPE (inner_type),
-                    exp1)))))),
-               if_false_label, if_true_label);
-          }
-
-        else if (integer_zerop (TREE_OPERAND (exp, 1)))
-          do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
-
-        else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
-                 && !can_compare_p (EQ, TYPE_MODE (inner_type), ccp_jump))
-          do_jump_by_parts_equality (exp, if_false_label, if_true_label);
-        else
-          do_compare_and_jump (exp, EQ, EQ, if_false_label, if_true_label);
-        break;
-      }
-
     case NE_EXPR:
     case NE_EXPR:
-      {
-        tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
-
-        if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT
-            || GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT)
-          {
-            tree exp0 = save_expr (TREE_OPERAND (exp, 0));
-            tree exp1 = save_expr (TREE_OPERAND (exp, 1));
-            do_jump
-              (fold
-               (build (TRUTH_ORIF_EXPR, TREE_TYPE (exp),
-                 fold (build (NE_EXPR, TREE_TYPE (exp),
-                  fold (build1 (REALPART_EXPR,
-                    TREE_TYPE (inner_type),
-                    exp0)),
-                  fold (build1 (REALPART_EXPR,
-                    TREE_TYPE (inner_type),
-                    exp1)))),
-                 fold (build (NE_EXPR, TREE_TYPE (exp),
-                    fold (build1 (IMAGPART_EXPR,
-                      TREE_TYPE (inner_type),
-                      exp0)),
-                    fold (build1 (IMAGPART_EXPR,
-                      TREE_TYPE (inner_type),
-                      exp1)))))),
-               if_false_label, if_true_label);
-          }
-
-        else if (integer_zerop (TREE_OPERAND (exp, 1)))
-          do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
-
-        else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
-           && !can_compare_p (NE, TYPE_MODE (inner_type), ccp_jump))
-          do_jump_by_parts_equality (exp, if_true_label, if_false_label);
-        else
-          do_compare_and_jump (exp, NE, NE, if_false_label, if_true_label);
-        break;
-      }
-
     case LT_EXPR:
     case LT_EXPR:
-      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-      if (GET_MODE_CLASS (mode) == MODE_INT
-          && ! can_compare_p (LT, mode, ccp_jump))
-        do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label);
-      else
-        do_compare_and_jump (exp, LT, LTU, if_false_label, if_true_label);
-      break;
-
     case LE_EXPR:
     case LE_EXPR:
-      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-      if (GET_MODE_CLASS (mode) == MODE_INT
-          && ! can_compare_p (LE, mode, ccp_jump))
-        do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label);
-      else
-        do_compare_and_jump (exp, LE, LEU, if_false_label, if_true_label);
-      break;
-
     case GT_EXPR:
     case GT_EXPR:
-      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-      if (GET_MODE_CLASS (mode) == MODE_INT
-          && ! can_compare_p (GT, mode, ccp_jump))
-        do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label);
-      else
-        do_compare_and_jump (exp, GT, GTU, if_false_label, if_true_label);
-      break;
-
     case GE_EXPR:
     case GE_EXPR:
-      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-      if (GET_MODE_CLASS (mode) == MODE_INT
-          && ! can_compare_p (GE, mode, ccp_jump))
-        do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label);
-      else
-        do_compare_and_jump (exp, GE, GEU, if_false_label, if_true_label);
+    case ORDERED_EXPR:
+    case UNORDERED_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+    case LTGT_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    other_code:
+      do_jump_1 (code, TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                if_false_label, if_true_label, prob);
       break;
 
       break;
 
-    case UNORDERED_EXPR:
-    case ORDERED_EXPR:
-      {
-        enum rtx_code cmp, rcmp;
-        int do_rev;
+    case BIT_AND_EXPR:
+      /* fold_single_bit_test() converts (X & (1 << C)) into (X >> C) & 1.
+        See if the former is preferred for jump tests and restore it
+        if so.  */
+      if (integer_onep (TREE_OPERAND (exp, 1)))
+       {
+         tree exp0 = TREE_OPERAND (exp, 0);
+         rtx set_label, clr_label;
+         int setclr_prob = prob;
+
+         /* Strip narrowing integral type conversions.  */
+         while (CONVERT_EXPR_P (exp0)
+                && TREE_OPERAND (exp0, 0) != error_mark_node
+                && TYPE_PRECISION (TREE_TYPE (exp0))
+                   <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp0, 0))))
+           exp0 = TREE_OPERAND (exp0, 0);
+
+         /* "exp0 ^ 1" inverts the sense of the single bit test.  */
+         if (TREE_CODE (exp0) == BIT_XOR_EXPR
+             && integer_onep (TREE_OPERAND (exp0, 1)))
+           {
+             exp0 = TREE_OPERAND (exp0, 0);
+             clr_label = if_true_label;
+             set_label = if_false_label;
+             setclr_prob = inv (prob);
+           }
+         else
+           {
+             clr_label = if_false_label;
+             set_label = if_true_label;
+           }
 
 
-        if (code == UNORDERED_EXPR)
-          cmp = UNORDERED, rcmp = ORDERED;
-        else
-          cmp = ORDERED, rcmp = UNORDERED;
-        mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-
-        do_rev = 0;
-        if (! can_compare_p (cmp, mode, ccp_jump)
-            && (can_compare_p (rcmp, mode, ccp_jump)
-          /* If the target doesn't provide either UNORDERED or ORDERED
-             comparisons, canonicalize on UNORDERED for the library.  */
-          || rcmp == UNORDERED))
-          do_rev = 1;
-
-        if (! do_rev)
-          do_compare_and_jump (exp, cmp, cmp, if_false_label, if_true_label);
-        else
-          do_compare_and_jump (exp, rcmp, rcmp, if_true_label, if_false_label);
-      }
-      break;
+         if (TREE_CODE (exp0) == RSHIFT_EXPR)
+           {
+             tree arg = TREE_OPERAND (exp0, 0);
+             tree shift = TREE_OPERAND (exp0, 1);
+             tree argtype = TREE_TYPE (arg);
+             if (TREE_CODE (shift) == INTEGER_CST
+                 && compare_tree_int (shift, 0) >= 0
+                 && compare_tree_int (shift, HOST_BITS_PER_WIDE_INT) < 0
+                 && prefer_and_bit_test (TYPE_MODE (argtype),
+                                         TREE_INT_CST_LOW (shift)))
+               {
+                 unsigned HOST_WIDE_INT mask
+                   = (unsigned HOST_WIDE_INT) 1 << TREE_INT_CST_LOW (shift);
+                 do_jump (build2 (BIT_AND_EXPR, argtype, arg,
+                                  build_int_cstu (argtype, mask)),
+                          clr_label, set_label, setclr_prob);
+                 break;
+               }
+           }
+       }
 
 
-    {
-      enum rtx_code rcode1;
-      enum tree_code tcode2;
-
-      case UNLT_EXPR:
-        rcode1 = UNLT;
-        tcode2 = LT_EXPR;
-        goto unordered_bcc;
-      case UNLE_EXPR:
-        rcode1 = UNLE;
-        tcode2 = LE_EXPR;
-        goto unordered_bcc;
-      case UNGT_EXPR:
-        rcode1 = UNGT;
-        tcode2 = GT_EXPR;
-        goto unordered_bcc;
-      case UNGE_EXPR:
-        rcode1 = UNGE;
-        tcode2 = GE_EXPR;
-        goto unordered_bcc;
-      case UNEQ_EXPR:
-        rcode1 = UNEQ;
-        tcode2 = EQ_EXPR;
-        goto unordered_bcc;
-
-      unordered_bcc:
-        mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-        if (can_compare_p (rcode1, mode, ccp_jump))
-          do_compare_and_jump (exp, rcode1, rcode1, if_false_label,
-                               if_true_label);
-        else
-          {
-            tree op0 = save_expr (TREE_OPERAND (exp, 0));
-            tree op1 = save_expr (TREE_OPERAND (exp, 1));
-            tree cmp0, cmp1;
-
-            /* If the target doesn't support combined unordered
-               compares, decompose into UNORDERED + comparison.  */
-            cmp0 = fold (build (UNORDERED_EXPR, TREE_TYPE (exp), op0, op1));
-            cmp1 = fold (build (tcode2, TREE_TYPE (exp), op0, op1));
-            exp = build (TRUTH_ORIF_EXPR, TREE_TYPE (exp), cmp0, cmp1);
-            do_jump (exp, if_false_label, if_true_label);
-          }
-      }
-      break;
+      /* If we are AND'ing with a small constant, do this comparison in the
+         smallest type that fits.  If the machine doesn't have comparisons
+         that small, it will be converted back to the wider comparison.
+         This helps if we are testing the sign bit of a narrower object.
+         combine can't do this for us because it can't know whether a
+         ZERO_EXTRACT or a compare in a smaller mode exists, but we do.  */
 
 
-      /* Special case:
-          __builtin_expect (<test>, 0) and
-          __builtin_expect (<test>, 1)
+      if (! SLOW_BYTE_ACCESS
+          && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
+          && TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_WIDE_INT
+          && (i = tree_floor_log2 (TREE_OPERAND (exp, 1))) >= 0
+          && (mode = mode_for_size (i + 1, MODE_INT, 0)) != BLKmode
+          && (type = lang_hooks.types.type_for_mode (mode, 1)) != 0
+          && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
+          && have_insn_for (COMPARE, TYPE_MODE (type)))
+        {
+         do_jump (fold_convert (type, exp), if_false_label, if_true_label,
+                  prob);
+          break;
+        }
 
 
-         We need to do this here, so that <test> is not converted to a SCC
-         operation on machines that use condition code registers and COMPARE
-         like the PowerPC, and then the jump is done based on whether the SCC
-         operation produced a 1 or 0.  */
-    case CALL_EXPR:
-      /* Check for a built-in function.  */
-      {
-       tree fndecl = get_callee_fndecl (exp);
-       tree arglist = TREE_OPERAND (exp, 1);
-
-       if (fndecl
-           && DECL_BUILT_IN (fndecl)
-           && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
-           && arglist != NULL_TREE
-           && TREE_CHAIN (arglist) != NULL_TREE)
-         {
-           rtx seq = expand_builtin_expect_jump (exp, if_false_label,
-                                                 if_true_label);
-
-           if (seq != NULL_RTX)
-             {
-               emit_insn (seq);
-               return;
-             }
-         }
-      }
-      /* Fall through and generate the normal code.  */
+      if (TYPE_PRECISION (TREE_TYPE (exp)) > 1
+         || TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
+       goto normal;
+
+      /* Boolean comparisons can be compiled as TRUTH_AND_EXPR.  */
+
+    case TRUTH_AND_EXPR:
+      /* High branch cost, expand as the bitwise AND of the conditions.
+        Do the same if the RHS has side effects, because we're effectively
+        turning a TRUTH_AND_EXPR into a TRUTH_ANDIF_EXPR.  */
+      if (BRANCH_COST (optimize_insn_for_speed_p (),
+                      false) >= 4
+         || TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 1)))
+       goto normal;
+      code = TRUTH_ANDIF_EXPR;
+      goto other_code;
+
+    case BIT_IOR_EXPR:
+    case TRUTH_OR_EXPR:
+      /* High branch cost, expand as the bitwise OR of the conditions.
+        Do the same if the RHS has side effects, because we're effectively
+        turning a TRUTH_OR_EXPR into a TRUTH_ORIF_EXPR.  */
+      if (BRANCH_COST (optimize_insn_for_speed_p (), false) >= 4
+         || TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 1)))
+       goto normal;
+      code = TRUTH_ORIF_EXPR;
+      goto other_code;
 
 
+      /* Fall through and generate the normal code.  */
     default:
     normal:
     default:
     normal:
-      temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
-#if 0
-      /* This is not needed any more and causes poor code since it causes
-         comparisons and tests from non-SI objects to have different code
-         sequences.  */
-      /* Copy to register to avoid generating bad insns by cse
-         from (set (mem ...) (arithop))  (set (cc0) (mem ...)).  */
-      if (!cse_not_expected && GET_CODE (temp) == MEM)
-        temp = copy_to_reg (temp);
-#endif
+      temp = expand_normal (exp);
       do_pending_stack_adjust ();
       do_pending_stack_adjust ();
-      /* Do any postincrements in the expression that was tested.  */
-      emit_queue ();
-
-      if (GET_CODE (temp) == CONST_INT
-          || (GET_CODE (temp) == CONST_DOUBLE && GET_MODE (temp) == VOIDmode)
-          || 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 (NE, GET_MODE (temp), ccp_jump))
-        /* 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)
+      /* The RTL optimizers prefer comparisons against pseudos.  */
+      if (GET_CODE (temp) == SUBREG)
        {
        {
-         /* The RTL optimizers prefer comparisons against pseudos.  */
-         if (GET_CODE (temp) == SUBREG)
-           {
-             /* Compare promoted variables in their promoted mode.  */
-             if (SUBREG_PROMOTED_VAR_P (temp)
-                 && GET_CODE (XEXP (temp, 0)) == REG)
-               temp = XEXP (temp, 0);
-             else
-               temp = copy_to_reg (temp);
-           }
-         do_compare_rtx_and_jump (temp, CONST0_RTX (GET_MODE (temp)),
-                                  NE, TREE_UNSIGNED (TREE_TYPE (exp)),
-                                  GET_MODE (temp), NULL_RTX,
-                                  if_false_label, if_true_label);
+         /* Compare promoted variables in their promoted mode.  */
+         if (SUBREG_PROMOTED_VAR_P (temp)
+             && REG_P (XEXP (temp, 0)))
+           temp = XEXP (temp, 0);
+         else
+           temp = copy_to_reg (temp);
        }
        }
-      else
-        abort ();
+      do_compare_rtx_and_jump (temp, CONST0_RTX (GET_MODE (temp)),
+                              NE, TYPE_UNSIGNED (TREE_TYPE (exp)),
+                              GET_MODE (temp), NULL_RTX,
+                              if_false_label, if_true_label, prob);
     }
 
   if (drop_through_label)
     {
     }
 
   if (drop_through_label)
     {
-      /* If do_jump produces code that might be jumped around,
-         do any stack adjusts from that code, before the place
-         where control merges in.  */
       do_pending_stack_adjust ();
       emit_label (drop_through_label);
     }
 }
 \f
       do_pending_stack_adjust ();
       emit_label (drop_through_label);
     }
 }
 \f
-/* Given a comparison expression EXP for values too wide to be compared
-   with one insn, test the comparison and jump to the appropriate label.
-   The code of EXP is ignored; we always test GT if SWAP is 0,
-   and LT if SWAP is 1.  */
-
-static void
-do_jump_by_parts_greater (tree exp, int swap, rtx if_false_label,
-                         rtx 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 unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)));
-
-  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.
    UNSIGNEDP says to do unsigned comparison.
    Jump to IF_TRUE_LABEL if OP0 is greater, IF_FALSE_LABEL otherwise.  */
 
 /* Compare OP0 with OP1, word at a time, in mode MODE.
    UNSIGNEDP says to do unsigned comparison.
    Jump to IF_TRUE_LABEL if OP0 is greater, IF_FALSE_LABEL otherwise.  */
 
-void
+static void
 do_jump_by_parts_greater_rtx (enum machine_mode mode, int unsignedp, rtx op0,
 do_jump_by_parts_greater_rtx (enum machine_mode mode, int unsignedp, rtx op0,
-                             rtx op1, rtx if_false_label, rtx if_true_label)
+                             rtx op1, rtx if_false_label, rtx if_true_label,
+                             int prob)
 {
   int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
   rtx drop_through_label = 0;
 {
   int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
   rtx drop_through_label = 0;
@@ -715,11 +665,12 @@ do_jump_by_parts_greater_rtx (enum machine_mode mode, int unsignedp, rtx op0,
       /* All but high-order word must be compared as unsigned.  */
       do_compare_rtx_and_jump (op0_word, op1_word, GT,
                                (unsignedp || i > 0), word_mode, NULL_RTX,
       /* All but high-order word must be compared as unsigned.  */
       do_compare_rtx_and_jump (op0_word, op1_word, GT,
                                (unsignedp || i > 0), word_mode, NULL_RTX,
-                               NULL_RTX, if_true_label);
+                              NULL_RTX, if_true_label, prob);
 
       /* Consider lower words only if these are equal.  */
       do_compare_rtx_and_jump (op0_word, op1_word, NE, unsignedp, word_mode,
 
       /* Consider lower words only if these are equal.  */
       do_compare_rtx_and_jump (op0_word, op1_word, NE, unsignedp, word_mode,
-                               NULL_RTX, NULL_RTX, if_false_label);
+                              NULL_RTX, NULL_RTX, if_false_label,
+                              inv (prob));
     }
 
   if (if_false_label)
     }
 
   if (if_false_label)
@@ -728,42 +679,34 @@ do_jump_by_parts_greater_rtx (enum machine_mode mode, int unsignedp, rtx op0,
     emit_label (drop_through_label);
 }
 
     emit_label (drop_through_label);
 }
 
-/* Given an EQ_EXPR expression EXP for values too wide to be compared
-   with one insn, test the comparison and jump to the appropriate label.  */
+/* Given a comparison expression EXP for values too wide to be compared
+   with one insn, test the comparison and jump to the appropriate label.
+   The code of EXP is ignored; we always test GT if SWAP is 0,
+   and LT if SWAP is 1.  */
 
 static void
 
 static void
-do_jump_by_parts_equality (tree exp, rtx if_false_label, rtx if_true_label)
+do_jump_by_parts_greater (tree treeop0, tree treeop1, int swap,
+                         rtx if_false_label, rtx if_true_label, int prob)
 {
 {
-  rtx op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
-  rtx op1 = expand_expr (TREE_OPERAND (exp, 1), 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);
-  int i;
-  rtx drop_through_label = 0;
-
-  if (! if_false_label)
-    drop_through_label = if_false_label = gen_label_rtx ();
+  rtx op0 = expand_normal (swap ? treeop1 : treeop0);
+  rtx op1 = expand_normal (swap ? treeop0 : treeop1);
+  enum machine_mode mode = TYPE_MODE (TREE_TYPE (treeop0));
+  int unsignedp = TYPE_UNSIGNED (TREE_TYPE (treeop0));
 
 
-  for (i = 0; i < nwords; i++)
-    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, if_false_label, NULL_RTX);
-
-  if (if_true_label)
-    emit_jump (if_true_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, prob);
 }
 \f
 }
 \f
-/* Jump according to whether OP0 is 0.
-   We assume that OP0 has an integer mode that is too wide
-   for the available compare insns.  */
+/* Jump according to whether OP0 is 0.  We assume that OP0 has an integer
+   mode, MODE, that is too wide for the available compare insns.  Either
+   Either (but not both) of IF_TRUE_LABEL and IF_FALSE_LABEL may be NULL_RTX
+   to indicate drop through.  */
 
 
-void
-do_jump_by_parts_equality_rtx (rtx op0, rtx if_false_label, rtx if_true_label)
+static void
+do_jump_by_parts_zero_rtx (enum machine_mode mode, rtx op0,
+                          rtx if_false_label, rtx if_true_label, int prob)
 {
 {
-  int nwords = GET_MODE_SIZE (GET_MODE (op0)) / UNITS_PER_WORD;
+  int nwords = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
   rtx part;
   int i;
   rtx drop_through_label = 0;
   rtx part;
   int i;
   rtx drop_through_label = 0;
@@ -774,17 +717,16 @@ do_jump_by_parts_equality_rtx (rtx op0, rtx if_false_label, rtx if_true_label)
      be slower, but that's highly unlikely.  */
 
   part = gen_reg_rtx (word_mode);
      be slower, but that's highly unlikely.  */
 
   part = gen_reg_rtx (word_mode);
-  emit_move_insn (part, operand_subword_force (op0, 0, GET_MODE (op0)));
+  emit_move_insn (part, operand_subword_force (op0, 0, mode));
   for (i = 1; i < nwords && part != 0; i++)
     part = expand_binop (word_mode, ior_optab, part,
   for (i = 1; i < nwords && part != 0; i++)
     part = expand_binop (word_mode, ior_optab, part,
-                         operand_subword_force (op0, i, GET_MODE (op0)),
+                         operand_subword_force (op0, i, mode),
                          part, 1, OPTAB_WIDEN);
 
   if (part != 0)
     {
       do_compare_rtx_and_jump (part, const0_rtx, EQ, 1, word_mode,
                          part, 1, OPTAB_WIDEN);
 
   if (part != 0)
     {
       do_compare_rtx_and_jump (part, const0_rtx, EQ, 1, word_mode,
-                               NULL_RTX, if_false_label, if_true_label);
-
+                              NULL_RTX, if_false_label, if_true_label, prob);
       return;
     }
 
       return;
     }
 
@@ -793,9 +735,9 @@ do_jump_by_parts_equality_rtx (rtx op0, rtx if_false_label, rtx if_true_label)
     drop_through_label = if_false_label = gen_label_rtx ();
 
   for (i = 0; i < nwords; i++)
     drop_through_label = if_false_label = gen_label_rtx ();
 
   for (i = 0; i < nwords; i++)
-    do_compare_rtx_and_jump (operand_subword_force (op0, i, GET_MODE (op0)),
+    do_compare_rtx_and_jump (operand_subword_force (op0, i, mode),
                              const0_rtx, EQ, 1, word_mode, NULL_RTX,
                              const0_rtx, EQ, 1, word_mode, NULL_RTX,
-                             if_false_label, NULL_RTX);
+                            if_false_label, NULL_RTX, prob);
 
   if (if_true_label)
     emit_jump (if_true_label);
 
   if (if_true_label)
     emit_jump (if_true_label);
@@ -803,79 +745,139 @@ do_jump_by_parts_equality_rtx (rtx op0, rtx if_false_label, rtx if_true_label)
   if (drop_through_label)
     emit_label (drop_through_label);
 }
   if (drop_through_label)
     emit_label (drop_through_label);
 }
-\f
-/* 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.
-   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.
+/* Test for the equality of two RTX expressions OP0 and OP1 in mode MODE,
+   where MODE is an integer mode too wide to be compared with one insn.
+   Either (but not both) of IF_TRUE_LABEL and IF_FALSE_LABEL may be NULL_RTX
+   to indicate drop through.  */
 
 
-   If MODE is BLKmode, SIZE is an RTX giving the size of the objects being
-   compared.  */
-
-rtx
-compare_from_rtx (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
-                 enum machine_mode mode, rtx size)
+static void
+do_jump_by_parts_equality_rtx (enum machine_mode mode, rtx op0, rtx op1,
+                              rtx if_false_label, rtx if_true_label, int prob)
 {
 {
-  enum rtx_code ucode;
-  rtx tem;
-
-  /* If one operand is constant, make it the second one.  Only do this
-     if the other operand is not constant as well.  */
+  int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
+  rtx drop_through_label = 0;
+  int i;
 
 
-  if (swap_commutative_operands_p (op0, op1))
+  if (op1 == const0_rtx)
     {
     {
-      tem = op0;
-      op0 = op1;
-      op1 = tem;
-      code = swap_condition (code);
+      do_jump_by_parts_zero_rtx (mode, op0, if_false_label, if_true_label,
+                                prob);
+      return;
     }
     }
-
-  if (flag_force_mem)
+  else if (op0 == const0_rtx)
     {
     {
-      op0 = force_not_mem (op0);
-      op1 = force_not_mem (op1);
+      do_jump_by_parts_zero_rtx (mode, op1, if_false_label, if_true_label,
+                                prob);
+      return;
     }
 
     }
 
-  do_pending_stack_adjust ();
+  if (! if_false_label)
+    drop_through_label = if_false_label = gen_label_rtx ();
 
 
-  ucode = unsignedp ? unsigned_condition (code) : code;
-  tem = simplify_const_relational_operation (ucode, mode, op0, op1);
-  if (tem != 0)
-    return tem;
+  for (i = 0; i < nwords; i++)
+    do_compare_rtx_and_jump (operand_subword_force (op0, i, mode),
+                             operand_subword_force (op1, i, mode),
+                             EQ, 0, word_mode, NULL_RTX,
+                            if_false_label, NULL_RTX, prob);
 
 
-#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
+  if (if_true_label)
+    emit_jump (if_true_label);
+  if (drop_through_label)
+    emit_label (drop_through_label);
+}
 
 
-  emit_cmp_insn (op0, op1, code, size, mode, unsignedp);
+/* Given an EQ_EXPR expression EXP for values too wide to be compared
+   with one insn, test the comparison and jump to the appropriate label.  */
 
 
-#if HAVE_cc0
-  return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
-#else
-  return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
-#endif
+static void
+do_jump_by_parts_equality (tree treeop0, tree treeop1, rtx if_false_label,
+                          rtx if_true_label, int prob)
+{
+  rtx op0 = expand_normal (treeop0);
+  rtx op1 = expand_normal (treeop1);
+  enum machine_mode mode = TYPE_MODE (TREE_TYPE (treeop0));
+  do_jump_by_parts_equality_rtx (mode, op0, op1, if_false_label,
+                                if_true_label, prob);
 }
 }
+\f
+/* Split a comparison into two others, the second of which has the other
+   "orderedness".  The first is always ORDERED or UNORDERED if MODE
+   does not honor NaNs (which means that it can be skipped in that case;
+   see do_compare_rtx_and_jump).
+
+   The two conditions are written in *CODE1 and *CODE2.  Return true if
+   the conditions must be ANDed, false if they must be ORed.  */
+
+bool
+split_comparison (enum rtx_code code, enum machine_mode mode,
+                 enum rtx_code *code1, enum rtx_code *code2)
+{
+  switch (code)
+    {
+    case LT:
+      *code1 = ORDERED;
+      *code2 = UNLT;
+      return true;
+    case LE:
+      *code1 = ORDERED;
+      *code2 = UNLE;
+      return true;
+    case GT:
+      *code1 = ORDERED;
+      *code2 = UNGT;
+      return true;
+    case GE:
+      *code1 = ORDERED;
+      *code2 = UNGE;
+      return true;
+    case EQ:
+      *code1 = ORDERED;
+      *code2 = UNEQ;
+      return true;
+    case NE:
+      *code1 = UNORDERED;
+      *code2 = LTGT;
+      return false;
+    case UNLT:
+      *code1 = UNORDERED;
+      *code2 = LT;
+      return false;
+    case UNLE:
+      *code1 = UNORDERED;
+      *code2 = LE;
+      return false;
+    case UNGT:
+      *code1 = UNORDERED;
+      *code2 = GT;
+      return false;
+    case UNGE:
+      *code1 = UNORDERED;
+      *code2 = GE;
+      return false;
+    case UNEQ:
+      *code1 = UNORDERED;
+      *code2 = EQ;
+      return false;
+    case LTGT:
+      /* Do not turn a trapping comparison into a non-trapping one.  */
+      if (HONOR_SNANS (mode))
+       {
+          *code1 = LT;
+          *code2 = GT;
+          return false;
+       }
+      else
+       {
+         *code1 = ORDERED;
+         *code2 = NE;
+         return true;
+       }
+    default:
+      gcc_unreachable ();
+    }
+}
+
 
 /* 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.
 
 /* 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.
@@ -886,19 +888,38 @@ compare_from_rtx (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
 void
 do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
                         enum machine_mode mode, rtx size, rtx if_false_label,
 void
 do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
                         enum machine_mode mode, rtx size, rtx if_false_label,
-                        rtx if_true_label)
+                        rtx if_true_label, int prob)
 {
 {
-  enum rtx_code ucode;
   rtx tem;
   rtx tem;
-  int dummy_true_label = 0;
+  rtx dummy_label = NULL_RTX;
+  rtx last;
 
   /* Reverse the comparison if that is safe and we want to jump if it is
 
   /* Reverse the comparison if that is safe and we want to jump if it is
-     false.  */
-  if (! if_true_label && ! FLOAT_MODE_P (mode))
+     false.  Also convert to the reverse comparison if the target can
+     implement it.  */
+  if ((! if_true_label
+       || ! can_compare_p (code, mode, ccp_jump))
+      && (! FLOAT_MODE_P (mode)
+         || code == ORDERED || code == UNORDERED
+         || (! HONOR_NANS (mode) && (code == LTGT || code == UNEQ))
+         || (! HONOR_SNANS (mode) && (code == EQ || code == NE))))
     {
     {
-      if_true_label = if_false_label;
-      if_false_label = 0;
-      code = reverse_condition (code);
+      enum rtx_code rcode;
+      if (FLOAT_MODE_P (mode))
+        rcode = reverse_condition_maybe_unordered (code);
+      else
+        rcode = reverse_condition (code);
+
+      /* Canonicalize to UNORDERED for the libcall.  */
+      if (can_compare_p (rcode, mode, ccp_jump)
+         || (code == ORDERED && ! can_compare_p (ORDERED, mode, ccp_jump)))
+       {
+          tem = if_true_label;
+          if_true_label = if_false_label;
+          if_false_label = tem;
+         code = rcode;
+         prob = inv (prob);
+       }
     }
 
   /* If one operand is constant, make it the second one.  Only do this
     }
 
   /* If one operand is constant, make it the second one.  Only do this
@@ -912,66 +933,181 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
       code = swap_condition (code);
     }
 
       code = swap_condition (code);
     }
 
-  if (flag_force_mem)
-    {
-      op0 = force_not_mem (op0);
-      op1 = force_not_mem (op1);
-    }
-
   do_pending_stack_adjust ();
 
   do_pending_stack_adjust ();
 
-  ucode = unsignedp ? unsigned_condition (code) : code;
-  tem = simplify_const_relational_operation (ucode, mode, op0, op1);
-  if (tem != 0)
+  code = unsignedp ? unsigned_condition (code) : code;
+  if (0 != (tem = simplify_relational_operation (code, mode, VOIDmode,
+                                                op0, op1)))
     {
     {
-      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 (CONSTANT_P (tem))
+       {
+         rtx label = (tem == const0_rtx || tem == CONST0_RTX (mode))
+                     ? if_false_label : if_true_label;
+         if (label)
+           emit_jump (label);
+         return;
+       }
 
 
-#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;
+      code = GET_CODE (tem);
+      mode = GET_MODE (tem);
+      op0 = XEXP (tem, 0);
+      op1 = XEXP (tem, 1);
+      unsignedp = (code == GTU || code == LTU || code == GEU || code == LEU);
     }
     }
-#endif
 
   if (! if_true_label)
 
   if (! if_true_label)
+    dummy_label = if_true_label = gen_label_rtx ();
+
+  if (GET_MODE_CLASS (mode) == MODE_INT
+      && ! can_compare_p (code, mode, ccp_jump))
     {
     {
-      dummy_true_label = 1;
-      if_true_label = gen_label_rtx ();
+      switch (code)
+       {
+       case LTU:
+         do_jump_by_parts_greater_rtx (mode, 1, op1, op0,
+                                       if_false_label, if_true_label, prob);
+         break;
+
+       case LEU:
+         do_jump_by_parts_greater_rtx (mode, 1, op0, op1,
+                                       if_true_label, if_false_label,
+                                       inv (prob));
+         break;
+
+       case GTU:
+         do_jump_by_parts_greater_rtx (mode, 1, op0, op1,
+                                       if_false_label, if_true_label, prob);
+         break;
+
+       case GEU:
+         do_jump_by_parts_greater_rtx (mode, 1, op1, op0,
+                                       if_true_label, if_false_label,
+                                       inv (prob));
+         break;
+
+       case LT:
+         do_jump_by_parts_greater_rtx (mode, 0, op1, op0,
+                                       if_false_label, if_true_label, prob);
+         break;
+
+       case LE:
+         do_jump_by_parts_greater_rtx (mode, 0, op0, op1,
+                                       if_true_label, if_false_label,
+                                       inv (prob));
+         break;
+
+       case GT:
+         do_jump_by_parts_greater_rtx (mode, 0, op0, op1,
+                                       if_false_label, if_true_label, prob);
+         break;
+
+       case GE:
+         do_jump_by_parts_greater_rtx (mode, 0, op1, op0,
+                                       if_true_label, if_false_label,
+                                       inv (prob));
+         break;
+
+       case EQ:
+         do_jump_by_parts_equality_rtx (mode, op0, op1, if_false_label,
+                                        if_true_label, prob);
+         break;
+
+       case NE:
+         do_jump_by_parts_equality_rtx (mode, op0, op1, if_true_label,
+                                        if_false_label, inv (prob));
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
     }
     }
+  else
+    {
+      if (GET_MODE_CLASS (mode) == MODE_FLOAT
+         && ! can_compare_p (code, mode, ccp_jump)
+         && can_compare_p (swap_condition (code), mode, ccp_jump))
+       {
+         rtx tmp;
+         code = swap_condition (code);
+         tmp = op0;
+         op0 = op1;
+         op1 = tmp;
+       }
+
+      else if (GET_MODE_CLASS (mode) == MODE_FLOAT
+              && ! can_compare_p (code, mode, ccp_jump)
+
+              /* Never split ORDERED and UNORDERED.  These must be implemented.  */
+              && (code != ORDERED && code != UNORDERED)
+
+               /* Split a floating-point comparison if we can jump on other
+                 conditions...  */
+              && (have_insn_for (COMPARE, mode)
+
+                  /* ... or if there is no libcall for it.  */
+                  || code_to_optab[code] == NULL))
+        {
+         enum rtx_code first_code;
+         bool and_them = split_comparison (code, mode, &first_code, &code);
+
+         /* If there are no NaNs, the first comparison should always fall
+            through.  */
+         if (!HONOR_NANS (mode))
+           gcc_assert (first_code == (and_them ? ORDERED : UNORDERED));
 
 
-  emit_cmp_and_jump_insns (op0, op1, code, size, mode, unsignedp,
-                           if_true_label);
+         else
+           {
+             if (and_them)
+               {
+                 rtx dest_label;
+                 /* If we only jump if true, just bypass the second jump.  */
+                 if (! if_false_label)
+                   {
+                     if (! dummy_label)
+                       dummy_label = gen_label_rtx ();
+                     dest_label = dummy_label;
+                   }
+                 else
+                   dest_label = if_false_label;
+                  do_compare_rtx_and_jump (op0, op1, first_code, unsignedp, mode,
+                                          size, dest_label, NULL_RTX, prob);
+               }
+              else
+                do_compare_rtx_and_jump (op0, op1, first_code, unsignedp, mode,
+                                        size, NULL_RTX, if_true_label, prob);
+           }
+       }
+
+      last = get_last_insn ();
+      emit_cmp_and_jump_insns (op0, op1, code, size, mode, unsignedp,
+                              if_true_label);
+      if (prob != -1 && profile_status != PROFILE_ABSENT)
+       {
+         for (last = NEXT_INSN (last);
+              last && NEXT_INSN (last);
+              last = NEXT_INSN (last))
+           if (JUMP_P (last))
+             break;
+         if (!last
+             || !JUMP_P (last)
+             || NEXT_INSN (last)
+             || !any_condjump_p (last))
+           {
+             if (dump_file)
+               fprintf (dump_file, "Failed to add probability note\n");
+           }
+         else
+           {
+             gcc_assert (!find_reg_note (last, REG_BR_PROB, 0));
+             add_reg_note (last, REG_BR_PROB, GEN_INT (prob));
+           }
+       }
+    }
 
   if (if_false_label)
     emit_jump (if_false_label);
 
   if (if_false_label)
     emit_jump (if_false_label);
-  if (dummy_true_label)
-    emit_label (if_true_label);
+  if (dummy_label)
+    emit_label (dummy_label);
 }
 
 /* Generate code for a comparison expression EXP (including code to compute
 }
 
 /* Generate code for a comparison expression EXP (including code to compute
@@ -985,9 +1121,9 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
    things pushed on the stack that aren't yet used.  */
 
 static void
    things pushed on the stack that aren't yet used.  */
 
 static void
-do_compare_and_jump (tree exp, enum rtx_code signed_code,
+do_compare_and_jump (tree treeop0, tree treeop1, enum rtx_code signed_code,
                     enum rtx_code unsigned_code, rtx if_false_label,
                     enum rtx_code unsigned_code, rtx if_false_label,
-                    rtx if_true_label)
+                    rtx if_true_label, int prob)
 {
   rtx op0, op1;
   tree type;
 {
   rtx op0, op1;
   tree type;
@@ -996,63 +1132,58 @@ do_compare_and_jump (tree exp, enum rtx_code signed_code,
   enum rtx_code code;
 
   /* Don't crash if the comparison was erroneous.  */
   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)
+  op0 = expand_normal (treeop0);
+  if (TREE_CODE (treeop0) == ERROR_MARK)
     return;
 
     return;
 
-  op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
-  if (TREE_CODE (TREE_OPERAND (exp, 1)) == ERROR_MARK)
+  op1 = expand_normal (treeop1);
+  if (TREE_CODE (treeop1) == ERROR_MARK)
     return;
 
     return;
 
-  type = TREE_TYPE (TREE_OPERAND (exp, 0));
+  type = TREE_TYPE (treeop0);
   mode = TYPE_MODE (type);
   mode = TYPE_MODE (type);
-  if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
-      && (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST
+  if (TREE_CODE (treeop0) == INTEGER_CST
+      && (TREE_CODE (treeop1) != INTEGER_CST
           || (GET_MODE_BITSIZE (mode)
           || (GET_MODE_BITSIZE (mode)
-              > GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp,
-                                                                      1)))))))
+              > GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (treeop1))))))
     {
       /* op0 might have been replaced by promoted constant, in which
          case the type of second argument should be used.  */
     {
       /* op0 might have been replaced by promoted constant, in which
          case the type of second argument should be used.  */
-      type = TREE_TYPE (TREE_OPERAND (exp, 1));
+      type = TREE_TYPE (treeop1);
       mode = TYPE_MODE (type);
     }
       mode = TYPE_MODE (type);
     }
-  unsignedp = TREE_UNSIGNED (type);
+  unsignedp = TYPE_UNSIGNED (type);
   code = unsignedp ? unsigned_code : signed_code;
 
 #ifdef HAVE_canonicalize_funcptr_for_compare
   /* If function pointers need to be "canonicalized" before they can
   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.  */
+     be reliably compared, then canonicalize them.
+     Only do this if *both* sides of the comparison are function pointers.
+     If one side isn't, we want a noncanonicalized comparison.  See PR
+     middle-end/17564.  */
   if (HAVE_canonicalize_funcptr_for_compare
   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))
+      && TREE_CODE (TREE_TYPE (treeop0)) == POINTER_TYPE
+      && TREE_CODE (TREE_TYPE (TREE_TYPE (treeop0)))
+          == FUNCTION_TYPE
+      && TREE_CODE (TREE_TYPE (treeop1)) == POINTER_TYPE
+      && TREE_CODE (TREE_TYPE (TREE_TYPE (treeop1)))
+          == FUNCTION_TYPE)
     {
       rtx new_op0 = gen_reg_rtx (mode);
     {
       rtx new_op0 = gen_reg_rtx (mode);
+      rtx new_op1 = gen_reg_rtx (mode);
 
       emit_insn (gen_canonicalize_funcptr_for_compare (new_op0, op0));
       op0 = new_op0;
 
       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
 
 
       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)
   do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode,
                            ((mode == BLKmode)
-                            ? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX),
-                           if_false_label, if_true_label);
+                            ? expr_size (treeop0) : NULL_RTX),
+                          if_false_label, if_true_label, prob);
 }
 
 #include "gt-dojump.h"
 }
 
 #include "gt-dojump.h"