OSDN Git Service

2005-10-18 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / dojump.c
index 83af19b..6dca9d3 100644 (file)
@@ -1,6 +1,6 @@
 /* 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 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -16,8 +16,8 @@ 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.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -50,6 +50,15 @@ init_pending_stack_adjust (void)
   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.
 
@@ -62,12 +71,8 @@ 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;
-    }
+      && ! (DECL_INLINE (current_function_decl) && ! flag_no_inline))
+    discard_pending_stack_adjust ();
 }
 
 /* Pop any previously-pushed arguments that have not been popped yet.  */
@@ -135,7 +140,7 @@ prefer_and_bit_test (enum machine_mode mode, int bitnum)
     }
 
   /* Fill in the integers.  */
-  XEXP (and_test, 0) = GEN_INT ((unsigned HOST_WIDE_INT) 1 << bitnum);
+  XEXP (and_test, 1) = GEN_INT ((unsigned HOST_WIDE_INT) 1 << bitnum);
   XEXP (XEXP (shift_test, 0), 1) = GEN_INT (bitnum);
 
   return (rtx_cost (and_test, IF_THEN_ELSE)
@@ -149,25 +154,17 @@ prefer_and_bit_test (enum machine_mode mode, int bitnum)
 
    do_jump always does any pending stack adjust except when it does not
    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.  */
+   is when EXP is `(foo (), 0)' and IF_FALSE_LABEL is null.  */
 
 void
 do_jump (tree exp, rtx if_false_label, rtx if_true_label)
 {
   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;
-
-  emit_queue ();
+  rtx drop_through_label = 0;
 
   switch (code)
     {
@@ -189,12 +186,6 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
       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
@@ -208,7 +199,6 @@ 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:
-    case REFERENCE_EXPR:
     case ABS_EXPR:
     case NEGATE_EXPR:
     case LROTATE_EXPR:
@@ -217,56 +207,56 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
       do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
       break;
 
-    case WITH_RECORD_EXPR:
-      /* Put the object on the placeholder list, recurse through our first
-         operand, and pop the list.  */
-      placeholder_list = tree_cons (TREE_OPERAND (exp, 1), NULL_TREE,
-                                    placeholder_list);
-      do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
-      placeholder_list = TREE_CHAIN (placeholder_list);
-      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)))
+      if (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)))
+         tree exp0 = TREE_OPERAND (exp, 0);
+         rtx set_label, clr_label;
+
+         /* Strip narrowing integral type conversions.  */
+         while ((TREE_CODE (exp0) == NOP_EXPR
+                 || TREE_CODE (exp0) == CONVERT_EXPR
+                 || TREE_CODE (exp0) == NON_LVALUE_EXPR)
+                && 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)))
            {
-             do_jump (build (BIT_AND_EXPR, argtype, arg,
-                             fold (build (LSHIFT_EXPR, argtype, one, shift))),
-                      if_false_label, if_true_label);
-             break;
+             exp0 = TREE_OPERAND (exp0, 0);
+             clr_label = if_true_label;
+             set_label = if_false_label;
+           }
+         else
+           {
+             clr_label = if_false_label;
+             set_label = if_true_label;
+           }
+
+         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)))
+               {
+                 HOST_WIDE_INT mask = (HOST_WIDE_INT) 1
+                                      << TREE_INT_CST_LOW (shift);
+                 do_jump (build2 (BIT_AND_EXPR, argtype, arg,
+                                  build_int_cst_type (argtype, mask)),
+                          clr_label, set_label);
+                 break;
+               }
            }
        }
 
@@ -296,34 +286,31 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
       do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
       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);
+        do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
+        emit_label (label1);
+        do_jump (TREE_OPERAND (exp, 2), if_false_label, if_true_label);
+       break;
+      }
 
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_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:
@@ -340,14 +327,14 @@ 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,
-                             &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))
             && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code
-          != CODE_FOR_nothing))
+               != CODE_FOR_nothing))
           {
             do_jump (convert (type, exp), if_false_label, if_true_label);
             break;
@@ -355,72 +342,17 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
         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 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)))
+        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 (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);
@@ -429,38 +361,23 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
         break;
       }
 
+    case MINUS_EXPR:
+      /* Nonzero iff operands of minus differ.  */
+      exp = build2 (NE_EXPR, TREE_TYPE (exp),
+                   TREE_OPERAND (exp, 0),
+                   TREE_OPERAND (exp, 1));
+      /* FALLTHRU */
     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)))
+        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 (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);
@@ -534,28 +451,40 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
 
     {
       enum rtx_code rcode1;
-      enum tree_code tcode2;
+      enum tree_code tcode1, tcode2;
 
       case UNLT_EXPR:
         rcode1 = UNLT;
+        tcode1 = UNORDERED_EXPR;
         tcode2 = LT_EXPR;
         goto unordered_bcc;
       case UNLE_EXPR:
         rcode1 = UNLE;
+        tcode1 = UNORDERED_EXPR;
         tcode2 = LE_EXPR;
         goto unordered_bcc;
       case UNGT_EXPR:
         rcode1 = UNGT;
+        tcode1 = UNORDERED_EXPR;
         tcode2 = GT_EXPR;
         goto unordered_bcc;
       case UNGE_EXPR:
         rcode1 = UNGE;
+        tcode1 = UNORDERED_EXPR;
         tcode2 = GE_EXPR;
         goto unordered_bcc;
       case UNEQ_EXPR:
         rcode1 = UNEQ;
+        tcode1 = UNORDERED_EXPR;
         tcode2 = EQ_EXPR;
         goto unordered_bcc;
+      case LTGT_EXPR:
+       /* It is ok for LTGT_EXPR to trap when the result is unordered,
+          so expand to (a < b) || (a > b).  */
+        rcode1 = LTGT;
+        tcode1 = LT_EXPR;
+        tcode2 = GT_EXPR;
+        goto unordered_bcc;
 
       unordered_bcc:
         mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
@@ -569,15 +498,54 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
             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);
+               compares, decompose into two comparisons.  */
+           if (if_true_label == 0)
+             drop_through_label = if_true_label = gen_label_rtx ();
+             
+            cmp0 = fold_build2 (tcode1, TREE_TYPE (exp), op0, op1);
+            cmp1 = fold_build2 (tcode2, TREE_TYPE (exp), op0, op1);
+           do_jump (cmp0, 0, if_true_label);
+           do_jump (cmp1, if_false_label, if_true_label);
           }
       }
       break;
 
+    case TRUTH_AND_EXPR:
+      /* High branch cost, expand as the bitwise AND of the conditions.  */
+      if (BRANCH_COST >= 4)
+       goto normal;
+
+      if (if_false_label == NULL_RTX)
+        {
+         drop_through_label = gen_label_rtx ();
+          do_jump (TREE_OPERAND (exp, 0), drop_through_label, NULL_RTX);
+          do_jump (TREE_OPERAND (exp, 1), NULL_RTX, if_true_label);
+       }
+      else
+       {
+         do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
+          do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
+       }
+      break;
+
+    case TRUTH_OR_EXPR:
+      /* High branch cost, expand as the bitwise OR of the conditions.  */
+      if (BRANCH_COST >= 4)
+       goto normal;
+
+      if (if_true_label == NULL_RTX)
+       {
+          drop_through_label = gen_label_rtx ();
+          do_jump (TREE_OPERAND (exp, 0), NULL_RTX, drop_through_label);
+          do_jump (TREE_OPERAND (exp, 1), if_false_label, NULL_RTX);
+       }
+      else
+       {
+          do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
+          do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
+       }
+      break;
+
       /* Special case:
           __builtin_expect (<test>, 0) and
           __builtin_expect (<test>, 1)
@@ -593,7 +561,7 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
        tree arglist = TREE_OPERAND (exp, 1);
 
        if (fndecl
-           && DECL_BUILT_IN (fndecl)
+           && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
            && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
            && arglist != NULL_TREE
            && TREE_CHAIN (arglist) != NULL_TREE)
@@ -608,23 +576,12 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
              }
          }
       }
       /* Fall through and generate the normal code.  */
-
     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
       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)
@@ -638,32 +595,29 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
                && ! 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)
+      else
        {
+         gcc_assert (GET_MODE (temp) != VOIDmode);
+         
          /* 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)
+                 && REG_P (XEXP (temp, 0)))
                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)),
+                                  NE, TYPE_UNSIGNED (TREE_TYPE (exp)),
                                   GET_MODE (temp), NULL_RTX,
                                   if_false_label, if_true_label);
        }
-      else
-        abort ();
     }
 
   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);
     }
@@ -681,9 +635,10 @@ do_jump_by_parts_greater (tree exp, int swap, rtx if_false_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)));
+  int unsignedp = TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)));
 
-  do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true_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.
@@ -756,7 +711,7 @@ do_jump_by_parts_equality (tree exp, rtx if_false_label, rtx if_true_label)
   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)),
+                             EQ, TYPE_UNSIGNED (TREE_TYPE (exp)),
                              word_mode, NULL_RTX, if_false_label, NULL_RTX);
 
   if (if_true_label)
@@ -814,9 +769,10 @@ do_jump_by_parts_equality_rtx (rtx op0, rtx if_false_label, rtx if_true_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.
+   MODE is the machine mode of the comparison, not of the result.
+   (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.
@@ -828,7 +784,6 @@ rtx
 compare_from_rtx (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
                  enum machine_mode mode, rtx size)
 {
-  enum rtx_code ucode;
   rtx tem;
 
   /* If one operand is constant, make it the second one.  Only do this
@@ -842,40 +797,25 @@ compare_from_rtx (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
       code = swap_condition (code);
     }
 
-  if (flag_force_mem)
-    {
-      op0 = force_not_mem (op0);
-      op1 = force_not_mem (op1);
-    }
-
   do_pending_stack_adjust ();
 
-  ucode = unsignedp ? unsigned_condition (code) : code;
-  tem = simplify_const_relational_operation (ucode, mode, op0, op1);
-  if (tem != 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)
+  code = unsignedp ? unsigned_condition (code) : code;
+  tem = simplify_relational_operation (code, VOIDmode, mode, op0, op1);
+  if (tem)
     {
-      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;
+      if (CONSTANT_P (tem))
+       return tem;
+
+      if (COMPARISON_P (tem))
+       {
+         code = GET_CODE (tem);
+         op0 = XEXP (tem, 0);
+         op1 = XEXP (tem, 1);
+         mode = GET_MODE (op0);
+         unsignedp = (code == GTU || code == LTU
+                      || code == GEU || code == LEU);
+       }
     }
-#endif
 
   emit_cmp_insn (op0, op1, code, size, mode, unsignedp);
 
@@ -897,7 +837,6 @@ 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)
 {
-  enum rtx_code ucode;
   rtx tem;
   int dummy_true_label = 0;
 
@@ -921,52 +860,27 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
       code = swap_condition (code);
     }
 
-  if (flag_force_mem)
-    {
-      op0 = force_not_mem (op0);
-      op1 = force_not_mem (op1);
-    }
-
   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)
     {
@@ -1026,38 +940,34 @@ do_compare_and_jump (tree exp, enum rtx_code signed_code,
       type = TREE_TYPE (TREE_OPERAND (exp, 1));
       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
-     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
       && 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 (TREE_TYPE (TREE_OPERAND (exp, 0))))
+          == FUNCTION_TYPE
+      && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE
+      && TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))))
+          == FUNCTION_TYPE)
     {
       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;
-    }
-
-  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),