OSDN Git Service

PR optimization/13424 (hppa), bootstrap/14462, c/14828
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 0db618e..568862d 100644 (file)
@@ -91,10 +91,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "toplev.h"
 #include "target.h"
 
-#ifndef SHIFT_COUNT_TRUNCATED
-#define SHIFT_COUNT_TRUNCATED 0
-#endif
-
 /* Number of attempts to combine instructions in this function.  */
 
 static int combine_attempts;
@@ -352,10 +348,10 @@ static void undo_all (void);
 static void undo_commit (void);
 static rtx *find_split_point (rtx *, rtx);
 static rtx subst (rtx, rtx, rtx, int, int);
-static rtx combine_simplify_rtx (rtx, enum machine_mode, int, int);
+static rtx combine_simplify_rtx (rtx, enum machine_mode, int);
 static rtx simplify_if_then_else (rtx);
 static rtx simplify_set (rtx);
-static rtx simplify_logical (rtx, int);
+static rtx simplify_logical (rtx);
 static rtx expand_compound_operation (rtx);
 static rtx expand_field_assignment (rtx);
 static rtx make_extraction (enum machine_mode, rtx, HOST_WIDE_INT,
@@ -411,6 +407,8 @@ static int insn_cuid (rtx);
 static void record_promoted_value (rtx, rtx);
 static rtx reversed_comparison (rtx, enum machine_mode, rtx, rtx);
 static enum rtx_code combine_reversed_comparison_code (rtx);
+static int unmentioned_reg_p_1 (rtx *, void *);
+static bool unmentioned_reg_p (rtx, rtx);
 \f
 /* Substitute NEWVAL, an rtx expression, into INTO, a place in some
    insn.  The substitution can be undone by undo_all.  If INTO is already
@@ -724,6 +722,31 @@ combine_instructions (rtx f, unsigned int nregs)
                                           &new_direct_jump_p)) != 0)
                    goto retry;
 
+             /* Try this insn with each REG_EQUAL note it links back to.  */
+             for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
+               {
+                 rtx set, note;
+                 rtx temp = XEXP (links, 0);
+                 if ((set = single_set (temp)) != 0
+                     && (note = find_reg_equal_equiv_note (temp)) != 0
+                     && GET_CODE (XEXP (note, 0)) != EXPR_LIST
+                     /* Avoid using a register that may already been marked
+                        dead by an earlier instruction.  */
+                     && ! unmentioned_reg_p (XEXP (note, 0), SET_SRC (set)))
+                   {
+                     /* Temporarily replace the set's source with the
+                        contents of the REG_EQUAL note.  The insn will
+                        be deleted or recognized by try_combine.  */
+                     rtx orig = SET_SRC (set);
+                     SET_SRC (set) = XEXP (note, 0);
+                     next = try_combine (insn, temp, NULL_RTX,
+                                         &new_direct_jump_p);
+                     if (next)
+                       goto retry;
+                     SET_SRC (set) = orig;
+                   }
+               }
+
              if (GET_CODE (insn) != NOTE)
                record_dead_and_set_regs (insn);
 
@@ -813,9 +836,6 @@ setup_incoming_promotions (void)
 
   if (targetm.calls.promote_function_args (TREE_TYPE (cfun->decl)))
     {
-#ifndef OUTGOING_REGNO
-#define OUTGOING_REGNO(N) N
-#endif
       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
        /* Check whether this register can hold an incoming pointer
           argument.  FUNCTION_ARG_REGNO_P tests outgoing register
@@ -963,6 +983,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
       for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
        {
          rtx elt = XVECEXP (PATTERN (insn), 0, i);
+         rtx note;
 
          switch (GET_CODE (elt))
            {
@@ -1013,6 +1034,8 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
              /* Ignore SETs whose result isn't used but not those that
                 have side-effects.  */
              if (find_reg_note (insn, REG_UNUSED, SET_DEST (elt))
+                 && (!(note = find_reg_note (insn, REG_EH_REGION, NULL_RTX))
+                     || INTVAL (XEXP (note, 0)) <= 0)
                  && ! side_effects_p (elt))
                break;
 
@@ -1344,18 +1367,14 @@ contains_muldiv (rtx x)
       return ! (GET_CODE (XEXP (x, 1)) == CONST_INT
                && exact_log2 (INTVAL (XEXP (x, 1))) >= 0);
     default:
-      switch (GET_RTX_CLASS (GET_CODE (x)))
-       {
-       case 'c':  case '<':  case '2':
-         return contains_muldiv (XEXP (x, 0))
+      if (BINARY_P (x))
+       return contains_muldiv (XEXP (x, 0))
            || contains_muldiv (XEXP (x, 1));
 
-       case '1':
-         return contains_muldiv (XEXP (x, 0));
+      if (UNARY_P (x))
+       return contains_muldiv (XEXP (x, 0));
 
-       default:
-         return 0;
-       }
+      return 0;
     }
 }
 \f
@@ -1456,7 +1475,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   int added_sets_1, added_sets_2;
   /* Total number of SETs to put into I3.  */
   int total_sets;
-  /* Nonzero is I2's body now appears in I3.  */
+  /* Nonzero if I2's body now appears in I3.  */
   int i2_is_used;
   /* INSN_CODEs for new I3, new I2, and user of condition code.  */
   int insn_code_number, i2_code_number = 0, other_code_number = 0;
@@ -1826,9 +1845,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
   if (flag_expensive_optimizations)
     {
-      /* Pass pc_rtx so no substitutions are done, just simplifications.
-        The cases that we are interested in here do not involve the few
-        cases were is_replaced is checked.  */
+      /* Pass pc_rtx so no substitutions are done, just simplifications.  */
       if (i1)
        {
          subst_low_cuid = INSN_CUID (i1);
@@ -2017,15 +2034,26 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
 
   /* If the result isn't valid, see if it is a PARALLEL of two SETs where
-     the second SET's destination is a register that is unused.  In that case,
+     the second SET's destination is a register that is unused and isn't
+     marked as an instruction that might trap in an EH region.  In that case,
      we just need the first SET.   This can occur when simplifying a divmod
      insn.  We *must* test for this case here because the code below that
      splits two independent SETs doesn't handle this case correctly when it
-     updates the register status.  Also check the case where the first
-     SET's destination is unused.  That would not cause incorrect code, but
-     does cause an unneeded insn to remain.  */
+     updates the register status.
+
+     It's pointless doing this if we originally had two sets, one from
+     i3, and one from i2.  Combining then splitting the parallel results
+     in the original i2 again plus an invalid insn (which we delete).
+     The net effect is only to move instructions around, which makes
+     debug info less accurate.
+
+     Also check the case where the first SET's destination is unused.
+     That would not cause incorrect code, but does cause an unneeded
+     insn to remain.  */
 
-  if (insn_code_number < 0 && GET_CODE (newpat) == PARALLEL
+  if (insn_code_number < 0
+      && !(added_sets_2 && i1 == 0)
+      && GET_CODE (newpat) == PARALLEL
       && XVECLEN (newpat, 0) == 2
       && GET_CODE (XVECEXP (newpat, 0, 0)) == SET
       && GET_CODE (XVECEXP (newpat, 0, 1)) == SET
@@ -2033,37 +2061,42 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
     {
       rtx set0 = XVECEXP (newpat, 0, 0);
       rtx set1 = XVECEXP (newpat, 0, 1);
-  
+      rtx note;
+
       if (((GET_CODE (SET_DEST (set1)) == REG
-            && find_reg_note (i3, REG_UNUSED, SET_DEST (set1)))
-          || (GET_CODE (SET_DEST (set1)) == SUBREG
-              && find_reg_note (i3, REG_UNUSED, SUBREG_REG (SET_DEST (set1)))))
-          && ! side_effects_p (SET_SRC (set1)))
-        {
-          newpat = set0;
-          insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
-        }
-  
+           && find_reg_note (i3, REG_UNUSED, SET_DEST (set1)))
+          || (GET_CODE (SET_DEST (set1)) == SUBREG
+              && find_reg_note (i3, REG_UNUSED, SUBREG_REG (SET_DEST (set1)))))
+         && (!(note = find_reg_note (i3, REG_EH_REGION, NULL_RTX))
+             || INTVAL (XEXP (note, 0)) <= 0)
+         && ! side_effects_p (SET_SRC (set1)))
+       {
+         newpat = set0;
+         insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+       }
+
       else if (((GET_CODE (SET_DEST (set0)) == REG
-                && find_reg_note (i3, REG_UNUSED, SET_DEST (set0)))
-                || (GET_CODE (SET_DEST (set0)) == SUBREG
-                    && find_reg_note (i3, REG_UNUSED,
-                                      SUBREG_REG (SET_DEST (set0)))))
-              && ! side_effects_p (SET_SRC (set0)))
-        {
-          newpat = set1;
-          insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
-    
-          if (insn_code_number >= 0)
-            {
-              /* If we will be able to accept this, we have made a
-                 change to the destination of I3.  This requires us to
-                 do a few adjustments.  */
-            
-              PATTERN (i3) = newpat;
-              adjust_for_new_dest (i3);
-            }
-        }
+                && find_reg_note (i3, REG_UNUSED, SET_DEST (set0)))
+               || (GET_CODE (SET_DEST (set0)) == SUBREG
+                   && find_reg_note (i3, REG_UNUSED,
+                                     SUBREG_REG (SET_DEST (set0)))))
+              && (!(note = find_reg_note (i3, REG_EH_REGION, NULL_RTX))
+                  || INTVAL (XEXP (note, 0)) <= 0)
+              && ! side_effects_p (SET_SRC (set0)))
+       {
+         newpat = set1;
+         insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+
+         if (insn_code_number >= 0)
+           {
+             /* If we will be able to accept this, we have made a
+                change to the destination of I3.  This requires us to
+                do a few adjustments.  */
+
+             PATTERN (i3) = newpat;
+             adjust_for_new_dest (i3);
+           }
+       }
     }
 
   /* If we were combining three insns and the result is a simple SET
@@ -2949,10 +2982,9 @@ find_split_point (rtx *loc, rtx insn)
             This will occur on machines that just support REG + CONST
             and have a constant moved through some previous computation.  */
 
-         else if (GET_RTX_CLASS (GET_CODE (XEXP (XEXP (x, 0), 0))) != 'o'
+         else if (!OBJECT_P (XEXP (XEXP (x, 0), 0))
                   && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
-                        && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (XEXP (x, 0), 0))))
-                            == 'o')))
+                        && OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
            return &XEXP (XEXP (x, 0), 0);
        }
       break;
@@ -2967,9 +2999,9 @@ find_split_point (rtx *loc, rtx insn)
       if (SET_DEST (x) == cc0_rtx
          && GET_CODE (SET_SRC (x)) != COMPARE
          && GET_CODE (SET_SRC (x)) != ZERO_EXTRACT
-         && GET_RTX_CLASS (GET_CODE (SET_SRC (x))) != 'o'
+         && !OBJECT_P (SET_SRC (x))
          && ! (GET_CODE (SET_SRC (x)) == SUBREG
-               && GET_RTX_CLASS (GET_CODE (SUBREG_REG (SET_SRC (x)))) == 'o'))
+               && OBJECT_P (SUBREG_REG (SET_SRC (x)))))
        return &SET_SRC (x);
 #endif
 
@@ -3160,14 +3192,11 @@ find_split_point (rtx *loc, rtx insn)
       /* See if this is a simple operation with a constant as the second
         operand.  It might be that this constant is out of range and hence
         could be used as a split point.  */
-      if ((GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '2'
-          || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == 'c'
-          || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '<')
+      if (BINARY_P (SET_SRC (x))
          && CONSTANT_P (XEXP (SET_SRC (x), 1))
-         && (GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (x), 0))) == 'o'
+         && (OBJECT_P (XEXP (SET_SRC (x), 0))
              || (GET_CODE (XEXP (SET_SRC (x), 0)) == SUBREG
-                 && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (SET_SRC (x), 0))))
-                     == 'o'))))
+                 && OBJECT_P (SUBREG_REG (XEXP (SET_SRC (x), 0))))))
        return &XEXP (SET_SRC (x), 1);
 
       /* Finally, see if this is a simple operation with its first operand
@@ -3175,10 +3204,7 @@ find_split_point (rtx *loc, rtx insn)
         register, so return it as a split point.  We can always do this
         because if the first operand were another operation, we would have
         already found it as a split point.  */
-      if ((GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '2'
-          || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == 'c'
-          || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '<'
-          || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '1')
+      if ((BINARY_P (SET_SRC (x)) || UNARY_P (SET_SRC (x)))
          && ! register_operand (XEXP (SET_SRC (x), 0), VOIDmode))
        return &XEXP (SET_SRC (x), 0);
 
@@ -3218,20 +3244,21 @@ find_split_point (rtx *loc, rtx insn)
   /* Otherwise, select our actions depending on our rtx class.  */
   switch (GET_RTX_CLASS (code))
     {
-    case 'b':                  /* This is ZERO_EXTRACT and SIGN_EXTRACT.  */
-    case '3':
+    case RTX_BITFIELD_OPS:             /* This is ZERO_EXTRACT and SIGN_EXTRACT.  */
+    case RTX_TERNARY:
       split = find_split_point (&XEXP (x, 2), insn);
       if (split)
        return split;
       /* ... fall through ...  */
-    case '2':
-    case 'c':
-    case '<':
+    case RTX_BIN_ARITH:
+    case RTX_COMM_ARITH:
+    case RTX_COMPARE:
+    case RTX_COMM_COMPARE:
       split = find_split_point (&XEXP (x, 1), insn);
       if (split)
        return split;
       /* ... fall through ...  */
-    case '1':
+    case RTX_UNARY:
       /* Some machines have (and (shift ...) ...) insns.  If X is not
         an AND, but XEXP (X, 0) is, use it as our split point.  */
       if (GET_CODE (x) != AND && GET_CODE (XEXP (x, 0)) == AND)
@@ -3241,10 +3268,11 @@ find_split_point (rtx *loc, rtx insn)
       if (split)
        return split;
       return loc;
-    }
 
-  /* Otherwise, we don't have a split point.  */
-  return 0;
+    default:
+      /* Otherwise, we don't have a split point.  */
+      return 0;
+    }
 }
 \f
 /* Throughout X, replace FROM with TO, and return the result.
@@ -3303,7 +3331,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
 
   /* If this is an object, we are done unless it is a MEM or LO_SUM, both
      of which may contain things that can be combined.  */
-  if (code != MEM && code != LO_SUM && GET_RTX_CLASS (code) == 'o')
+  if (code != MEM && code != LO_SUM && OBJECT_P (x))
     return x;
 
   /* It is possible to have a subexpression appear twice in the insn.
@@ -3515,7 +3543,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
       /* If X is sufficiently simple, don't bother trying to do anything
         with it.  */
       if (code != CONST_INT && code != REG && code != CLOBBER)
-       x = combine_simplify_rtx (x, op0_mode, i == 3, in_dest);
+       x = combine_simplify_rtx (x, op0_mode, in_dest);
 
       if (GET_CODE (x) == code)
        break;
@@ -3534,13 +3562,11 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
    outer level; call `subst' to simplify recursively.  Return the new
    expression.
 
-   OP0_MODE is the original mode of XEXP (x, 0); LAST is nonzero if this
-   will be the iteration even if an expression with a code different from
-   X is returned; IN_DEST is nonzero if we are inside a SET_DEST.  */
+   OP0_MODE is the original mode of XEXP (x, 0).  IN_DEST is nonzero
+   if we are inside a SET_DEST.  */
 
 static rtx
-combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
-                     int in_dest)
+combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
 {
   enum rtx_code code = GET_CODE (x);
   enum machine_mode mode = GET_MODE (x);
@@ -3550,7 +3576,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
 
   /* If this is a commutative operation, put a constant last and a complex
      expression first.  We don't need to do this for comparisons here.  */
-  if (GET_RTX_CLASS (code) == 'c'
+  if (COMMUTATIVE_ARITH_P (x)
       && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
     {
       temp = XEXP (x, 0);
@@ -3606,21 +3632,17 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
 
      Don't do anything if all operands are very simple.  */
 
-  if (((GET_RTX_CLASS (code) == '2' || GET_RTX_CLASS (code) == 'c'
-       || GET_RTX_CLASS (code) == '<')
-       && ((GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) != 'o'
+  if ((BINARY_P (x)
+       && ((!OBJECT_P (XEXP (x, 0))
            && ! (GET_CODE (XEXP (x, 0)) == SUBREG
-                 && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0))))
-                     == 'o')))
-          || (GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) != 'o'
+                 && OBJECT_P (SUBREG_REG (XEXP (x, 0)))))
+          || (!OBJECT_P (XEXP (x, 1))
               && ! (GET_CODE (XEXP (x, 1)) == SUBREG
-                    && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 1))))
-                        == 'o')))))
-      || (GET_RTX_CLASS (code) == '1'
-         && ((GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) != 'o'
+                    && OBJECT_P (SUBREG_REG (XEXP (x, 1)))))))
+      || (UNARY_P (x)
+          && (!OBJECT_P (XEXP (x, 0))
               && ! (GET_CODE (XEXP (x, 0)) == SUBREG
-                    && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0))))
-                        == 'o'))))))
+                    && OBJECT_P (SUBREG_REG (XEXP (x, 0)))))))
     {
       rtx cond, true_rtx, false_rtx;
 
@@ -3628,14 +3650,13 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
       if (cond != 0
          /* If everything is a comparison, what we have is highly unlikely
             to be simpler, so don't use it.  */
-         && ! (GET_RTX_CLASS (code) == '<'
-               && (GET_RTX_CLASS (GET_CODE (true_rtx)) == '<'
-                   || GET_RTX_CLASS (GET_CODE (false_rtx)) == '<')))
+         && ! (COMPARISON_P (x)
+               && (COMPARISON_P (true_rtx) || COMPARISON_P (false_rtx))))
        {
          rtx cop1 = const0_rtx;
          enum rtx_code cond_code = simplify_comparison (NE, &cond, &cop1);
 
-         if (cond_code == NE && GET_RTX_CLASS (GET_CODE (cond)) == '<')
+         if (cond_code == NE && COMPARISON_P (cond))
            return x;
 
          /* Simplify the alternative arms; this may collapse the true and
@@ -3701,12 +3722,13 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
   temp = 0;
   switch (GET_RTX_CLASS (code))
     {
-    case '1':
+    case RTX_UNARY:
       if (op0_mode == VOIDmode)
        op0_mode = GET_MODE (XEXP (x, 0));
       temp = simplify_unary_operation (code, mode, XEXP (x, 0), op0_mode);
       break;
-    case '<':
+    case RTX_COMPARE:
+    case RTX_COMM_COMPARE:
       {
        enum machine_mode cmp_mode = GET_MODE (XEXP (x, 0));
        if (cmp_mode == VOIDmode)
@@ -3715,29 +3737,21 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
            if (cmp_mode == VOIDmode)
              cmp_mode = op0_mode;
          }
-       temp = simplify_relational_operation (code, cmp_mode,
+       temp = simplify_relational_operation (code, mode, cmp_mode,
                                              XEXP (x, 0), XEXP (x, 1));
       }
-#ifdef FLOAT_STORE_FLAG_VALUE
-      if (temp != 0 && GET_MODE_CLASS (mode) == MODE_FLOAT)
-       {
-         if (temp == const0_rtx)
-           temp = CONST0_RTX (mode);
-         else
-           temp = CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE (mode),
-                                                mode);
-       }
-#endif
       break;
-    case 'c':
-    case '2':
+    case RTX_COMM_ARITH:
+    case RTX_BIN_ARITH:
       temp = simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1));
       break;
-    case 'b':
-    case '3':
+    case RTX_BITFIELD_OPS:
+    case RTX_TERNARY:
       temp = simplify_ternary_operation (code, mode, op0_mode, XEXP (x, 0),
                                         XEXP (x, 1), XEXP (x, 2));
       break;
+    default:
+      break;
     }
 
   if (temp)
@@ -3775,7 +3789,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
 
          /* Make sure we pass the constant operand if any as the second
             one if this is a commutative operation.  */
-         if (CONSTANT_P (inner_op0) && GET_RTX_CLASS (code) == 'c')
+         if (CONSTANT_P (inner_op0) && COMMUTATIVE_ARITH_P (x))
            {
              rtx tem = inner_op0;
              inner_op0 = inner_op1;
@@ -3788,7 +3802,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
 
          /* For commutative operations, try the other pair if that one
             didn't simplify.  */
-         if (inner == 0 && GET_RTX_CLASS (code) == 'c')
+         if (inner == 0 && COMMUTATIVE_ARITH_P (x))
            {
              other = XEXP (XEXP (x, 0), 1);
              inner = simplify_binary_operation (code, mode,
@@ -3996,7 +4010,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
          but it works even if the comparison is done in a mode larger
          than HOST_BITS_PER_WIDE_INT.  */
       if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-         && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+         && COMPARISON_P (XEXP (x, 0))
          && ((HOST_WIDE_INT) STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0)
        return gen_lowpart (mode, XEXP (x, 0));
 
@@ -4006,7 +4020,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
       if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
          && ((HOST_WIDE_INT) STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0
          && (temp = get_last_value (XEXP (x, 0)))
-         && GET_RTX_CLASS (GET_CODE (temp)) == '<')
+         && COMPARISON_P (temp))
        return gen_lowpart (mode, XEXP (x, 0));
 
       break;
@@ -4172,7 +4186,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
         C is 1 and STORE_FLAG_VALUE is -1 or if C is -1 and STORE_FLAG_VALUE
         is 1.  This produces better code than the alternative immediately
         below.  */
-      if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+      if (COMPARISON_P (XEXP (x, 0))
          && ((STORE_FLAG_VALUE == -1 && XEXP (x, 1) == const1_rtx)
              || (STORE_FLAG_VALUE == 1 && XEXP (x, 1) == constm1_rtx))
          && (reversed = reversed_comparison (XEXP (x, 0), mode,
@@ -4207,7 +4221,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
        {
          /* Try to simplify the expression further.  */
          rtx tor = gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
-         temp = combine_simplify_rtx (tor, mode, last, in_dest);
+         temp = combine_simplify_rtx (tor, mode, in_dest);
 
          /* If we could, great.  If not, do not go ahead with the IOR
             replacement, since PLUS appears in many special purpose
@@ -4222,7 +4236,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
         by reversing the comparison code if valid.  */
       if (STORE_FLAG_VALUE == 1
          && XEXP (x, 0) == const1_rtx
-         && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<'
+         && COMPARISON_P (XEXP (x, 1))
          && (reversed = reversed_comparison (XEXP (x, 1), mode,
                                              XEXP (XEXP (x, 1), 0),
                                              XEXP (XEXP (x, 1), 1))))
@@ -4492,7 +4506,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
     case AND:
     case IOR:
     case XOR:
-      return simplify_logical (x, last);
+      return simplify_logical (x);
 
     case ABS:
       /* (abs (neg <foo>)) -> (abs <foo>) */
@@ -4615,7 +4629,7 @@ simplify_if_then_else (rtx x)
   rtx true_rtx = XEXP (x, 1);
   rtx false_rtx = XEXP (x, 2);
   enum rtx_code true_code = GET_CODE (cond);
-  int comparison_p = GET_RTX_CLASS (true_code) == '<';
+  int comparison_p = COMPARISON_P (cond);
   rtx temp;
   int i;
   enum rtx_code false_code;
@@ -4700,11 +4714,9 @@ simplify_if_then_else (rtx x)
          || (CONSTANT_P (true_rtx)
              && GET_CODE (false_rtx) != CONST_INT && false_rtx != pc_rtx)
          || true_rtx == const0_rtx
-         || (GET_RTX_CLASS (GET_CODE (true_rtx)) == 'o'
-             && GET_RTX_CLASS (GET_CODE (false_rtx)) != 'o')
-         || (GET_CODE (true_rtx) == SUBREG
-             && GET_RTX_CLASS (GET_CODE (SUBREG_REG (true_rtx))) == 'o'
-             && GET_RTX_CLASS (GET_CODE (false_rtx)) != 'o')
+         || (OBJECT_P (true_rtx) && !OBJECT_P (false_rtx))
+         || (GET_CODE (true_rtx) == SUBREG && OBJECT_P (SUBREG_REG (true_rtx))
+             && !OBJECT_P (false_rtx))
          || reg_mentioned_p (true_rtx, false_rtx)
          || rtx_equal_p (false_rtx, XEXP (cond, 0))))
     {
@@ -4721,7 +4733,7 @@ simplify_if_then_else (rtx x)
 
       /* It is possible that the conditional has been simplified out.  */
       true_code = GET_CODE (cond);
-      comparison_p = GET_RTX_CLASS (true_code) == '<';
+      comparison_p = COMPARISON_P (cond);
     }
 
   /* If the two arms are identical, we don't need the comparison.  */
@@ -4930,6 +4942,7 @@ simplify_if_then_else (rtx x)
   /* (IF_THEN_ELSE (NE REG 0) (0) (8)) is REG for nonzero_bits (REG) == 8.  */
   if (true_code == NE && XEXP (cond, 1) == const0_rtx
       && false_rtx == const0_rtx && GET_CODE (true_rtx) == CONST_INT
+      && GET_MODE (XEXP (cond, 0)) == mode
       && (INTVAL (true_rtx) & GET_MODE_MASK (mode))
          == nonzero_bits (XEXP (cond, 0), mode)
       && (i = exact_log2 (INTVAL (true_rtx) & GET_MODE_MASK (mode))) >= 0)
@@ -4973,7 +4986,7 @@ simplify_set (rtx x)
        || CC0_P (dest))
       && (cc_use = find_single_use (dest, subst_insn, &other_insn)) != 0
       && (undobuf.other_insn == 0 || other_insn == undobuf.other_insn)
-      && GET_RTX_CLASS (GET_CODE (*cc_use)) == '<'
+      && COMPARISON_P (*cc_use)
       && rtx_equal_p (XEXP (*cc_use, 0), dest))
     {
       enum rtx_code old_code = GET_CODE (*cc_use);
@@ -4995,7 +5008,8 @@ simplify_set (rtx x)
        tmp_mode = GET_MODE (op1);
       else
        tmp_mode = compare_mode;
-      tmp = simplify_relational_operation (old_code, tmp_mode, op0, op1);
+      tmp = simplify_const_relational_operation (old_code, tmp_mode,
+                                                op0, op1);
       if (tmp != NULL_RTX)
        {
          rtx pat = PATTERN (other_insn);
@@ -5136,7 +5150,7 @@ simplify_set (rtx x)
      as long as M1 and M2 have the same number of words.  */
 
   if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
-      && GET_RTX_CLASS (GET_CODE (SUBREG_REG (src))) != 'o'
+      && !OBJECT_P (SUBREG_REG (src))
       && (((GET_MODE_SIZE (GET_MODE (src)) + (UNITS_PER_WORD - 1))
           / UNITS_PER_WORD)
          == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
@@ -5200,8 +5214,8 @@ simplify_set (rtx x)
       && GET_CODE (SUBREG_REG (src)) == MEM)
     {
       SUBST (SET_SRC (x),
-            gen_rtx (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))),
-                     GET_MODE (src), SUBREG_REG (src)));
+            gen_rtx_fmt_e (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))),
+                           GET_MODE (src), SUBREG_REG (src)));
 
       src = SET_SRC (x);
     }
@@ -5274,10 +5288,10 @@ simplify_set (rtx x)
 }
 \f
 /* Simplify, X, and AND, IOR, or XOR operation, and return the simplified
-   result.  LAST is nonzero if this is the last retry.  */
+   result.  */
 
 static rtx
-simplify_logical (rtx x, int last)
+simplify_logical (rtx x)
 {
   enum machine_mode mode = GET_MODE (x);
   rtx op0 = XEXP (x, 0);
@@ -5327,11 +5341,13 @@ simplify_logical (rtx x, int last)
 
          /* If we have (ior (and (X C1) C2)) and the next restart would be
             the last, simplify this by making C1 as small as possible
-            and then exit.  */
-         if (last
-             && GET_CODE (x) == IOR && GET_CODE (op0) == AND
+            and then exit.  Only do this if C1 actually changes: for now
+            this only saves memory but, should this transformation be
+            moved to simplify-rtx.c, we'd risk unbounded recursion there.  */
+         if (GET_CODE (x) == IOR && GET_CODE (op0) == AND
              && GET_CODE (XEXP (op0, 1)) == CONST_INT
-             && GET_CODE (op1) == CONST_INT)
+             && GET_CODE (op1) == CONST_INT
+             && (INTVAL (XEXP (op0, 1)) & INTVAL (op1)) != 0)
            return gen_binary (IOR, mode,
                               gen_binary (AND, mode, XEXP (op0, 0),
                                           GEN_INT (INTVAL (XEXP (op0, 1))
@@ -5340,9 +5356,8 @@ simplify_logical (rtx x, int last)
          if (GET_CODE (x) != AND)
            return x;
 
-         if (GET_RTX_CLASS (GET_CODE (x)) == 'c'
-             || GET_RTX_CLASS (GET_CODE (x)) == '2')
-           op0 = XEXP (x, 0), op1 = XEXP (x, 1);
+         op0 = XEXP (x, 0);
+         op1 = XEXP (x, 1);
        }
 
       /* Convert (A | B) & A to A.  */
@@ -5537,7 +5552,7 @@ simplify_logical (rtx x, int last)
         comparison if STORE_FLAG_VALUE is 1.  */
       if (STORE_FLAG_VALUE == 1
          && op1 == const1_rtx
-         && GET_RTX_CLASS (GET_CODE (op0)) == '<'
+         && COMPARISON_P (op0)
          && (reversed = reversed_comparison (op0, mode, XEXP (op0, 0),
                                              XEXP (op0, 1))))
        return reversed;
@@ -5559,7 +5574,7 @@ simplify_logical (rtx x, int last)
          && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
              == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
          && op1 == const_true_rtx
-         && GET_RTX_CLASS (GET_CODE (op0)) == '<'
+         && COMPARISON_P (op0)
          && (reversed = reversed_comparison (op0, mode, XEXP (op0, 0),
                                              XEXP (op0, 1))))
        return reversed;
@@ -5723,7 +5738,7 @@ expand_compound_operation (rtx x)
          than HOST_WIDE_INT.  */
       if (GET_CODE (XEXP (x, 0)) == TRUNCATE
          && GET_MODE (XEXP (XEXP (x, 0), 0)) == GET_MODE (x)
-         && GET_RTX_CLASS (GET_CODE (XEXP (XEXP (x, 0), 0))) == '<'
+         && COMPARISON_P (XEXP (XEXP (x, 0), 0))
          && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
              <= HOST_BITS_PER_WIDE_INT)
          && ((HOST_WIDE_INT) STORE_FLAG_VALUE
@@ -5734,7 +5749,7 @@ expand_compound_operation (rtx x)
       if (GET_CODE (XEXP (x, 0)) == SUBREG
          && GET_MODE (SUBREG_REG (XEXP (x, 0))) == GET_MODE (x)
          && subreg_lowpart_p (XEXP (x, 0))
-         && GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) == '<'
+         && COMPARISON_P (SUBREG_REG (XEXP (x, 0)))
          && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
              <= HOST_BITS_PER_WIDE_INT)
          && ((HOST_WIDE_INT) STORE_FLAG_VALUE
@@ -6415,7 +6430,7 @@ make_compound_operation (rtx x, enum rtx_code in_code)
      but once inside, go back to our default of SET.  */
 
   next_code = (code == MEM || code == PLUS || code == MINUS ? MEM
-              : ((code == COMPARE || GET_RTX_CLASS (code) == '<')
+              : ((code == COMPARE || COMPARISON_P (x))
                  && XEXP (x, 1) == const0_rtx) ? COMPARE
               : in_code == COMPARE ? SET : in_code);
 
@@ -6581,9 +6596,9 @@ make_compound_operation (rtx x, enum rtx_code in_code)
         also do this for some cases of SIGN_EXTRACT, but it doesn't
         seem worth the effort; the case checked for occurs on Alpha.  */
 
-      if (GET_RTX_CLASS (GET_CODE (lhs)) != 'o'
+      if (!OBJECT_P (lhs)
          && ! (GET_CODE (lhs) == SUBREG
-               && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (lhs))) == 'o'))
+               && (OBJECT_P (SUBREG_REG (lhs))))
          && GET_CODE (rhs) == CONST_INT
          && INTVAL (rhs) < HOST_BITS_PER_WIDE_INT
          && (new = extract_left_shift (lhs, INTVAL (rhs))) != 0)
@@ -6855,7 +6870,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
              int width = GET_MODE_BITSIZE (GET_MODE (x));
              rtx y;
 
-             /* If MODE is narrower that HOST_WIDE_INT and CVAL is a negative
+             /* If MODE is narrower than HOST_WIDE_INT and CVAL is a negative
                 number, sign extend it.  */
              if (width > 0 && width < HOST_BITS_PER_WIDE_INT
                  && (cval & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
@@ -7266,7 +7281,7 @@ if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
 
   /* If this is a unary operation whose operand has one of two values, apply
      our opcode to compute those values.  */
-  else if (GET_RTX_CLASS (code) == '1'
+  else if (UNARY_P (x)
           && (cond0 = if_then_else_cond (XEXP (x, 0), &true0, &false0)) != 0)
     {
       *ptrue = simplify_gen_unary (code, mode, true0, GET_MODE (XEXP (x, 0)));
@@ -7283,8 +7298,7 @@ if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
   /* If this is a binary operation, see if either side has only one of two
      values.  If either one does or if both do and they are conditional on
      the same value, compute the new true and false values.  */
-  else if (GET_RTX_CLASS (code) == 'c' || GET_RTX_CLASS (code) == '2'
-          || GET_RTX_CLASS (code) == '<')
+  else if (BINARY_P (x))
     {
       cond0 = if_then_else_cond (XEXP (x, 0), &true0, &false0);
       cond1 = if_then_else_cond (XEXP (x, 1), &true1, &false1);
@@ -7320,8 +7334,8 @@ if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
          cond0 = XEXP (XEXP (x, 0), 0);
          cond1 = XEXP (XEXP (x, 1), 0);
 
-         if (GET_RTX_CLASS (GET_CODE (cond0)) == '<'
-             && GET_RTX_CLASS (GET_CODE (cond1)) == '<'
+         if (COMPARISON_P (cond0)
+             && COMPARISON_P (cond1)
              && ((GET_CODE (cond0) == combine_reversed_comparison_code (cond1)
                   && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
                   && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
@@ -7351,8 +7365,8 @@ if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
          cond0 = XEXP (XEXP (x, 0), 0);
          cond1 = XEXP (XEXP (x, 1), 0);
 
-         if (GET_RTX_CLASS (GET_CODE (cond0)) == '<'
-             && GET_RTX_CLASS (GET_CODE (cond1)) == '<'
+         if (COMPARISON_P (cond0)
+             && COMPARISON_P (cond1)
              && ((GET_CODE (cond0) == combine_reversed_comparison_code (cond1)
                   && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
                   && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
@@ -7391,12 +7405,16 @@ if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
           && 0 != (cond0 = if_then_else_cond (SUBREG_REG (x),
                                               &true0, &false0)))
     {
-      *ptrue = simplify_gen_subreg (mode, true0,
+      true0 = simplify_gen_subreg (mode, true0,
+                                  GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
+      false0 = simplify_gen_subreg (mode, false0,
                                    GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
-      *pfalse = simplify_gen_subreg (mode, false0,
-                                    GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
-
-      return cond0;
+      if (true0 && false0)
+       {
+         *ptrue = true0;
+         *pfalse = false0;
+         return cond0;
+       }
     }
 
   /* If X is a constant, this isn't special and will cause confusions
@@ -7486,14 +7504,14 @@ known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val)
   /* The only other cases we handle are MIN, MAX, and comparisons if the
      operands are the same as REG and VAL.  */
 
-  else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == 'c')
+  else if (COMPARISON_P (x) || COMMUTATIVE_ARITH_P (x))
     {
       if (rtx_equal_p (XEXP (x, 0), val))
        cond = swap_condition (cond), temp = val, val = reg, reg = temp;
 
       if (rtx_equal_p (XEXP (x, 0), reg) && rtx_equal_p (XEXP (x, 1), val))
        {
-         if (GET_RTX_CLASS (code) == '<')
+         if (COMPARISON_P (x))
            {
              if (comparison_dominates_p (cond, code))
                return const_true_rtx;
@@ -7785,8 +7803,7 @@ apply_distributive_law (rtx x)
 
   /* If either operand is a primitive we can't do anything, so get out
      fast.  */
-  if (GET_RTX_CLASS (GET_CODE (lhs)) == 'o'
-      || GET_RTX_CLASS (GET_CODE (rhs)) == 'o')
+  if (OBJECT_P (lhs) || OBJECT_P (rhs))
     return x;
 
   lhs = expand_compound_operation (lhs);
@@ -7848,15 +7865,15 @@ apply_distributive_law (rtx x)
 
   /* Set LHS and RHS to the inner operands (A and B in the example
      above) and set OTHER to the common operand (C in the example).
-     These is only one way to do this unless the inner operation is
+     There is only one way to do this unless the inner operation is
      commutative.  */
-  if (GET_RTX_CLASS (inner_code) == 'c'
+  if (COMMUTATIVE_ARITH_P (lhs)
       && rtx_equal_p (XEXP (lhs, 0), XEXP (rhs, 0)))
     other = XEXP (lhs, 0), lhs = XEXP (lhs, 1), rhs = XEXP (rhs, 1);
-  else if (GET_RTX_CLASS (inner_code) == 'c'
+  else if (COMMUTATIVE_ARITH_P (lhs)
           && rtx_equal_p (XEXP (lhs, 0), XEXP (rhs, 1)))
     other = XEXP (lhs, 0), lhs = XEXP (lhs, 1), rhs = XEXP (rhs, 0);
-  else if (GET_RTX_CLASS (inner_code) == 'c'
+  else if (COMMUTATIVE_ARITH_P (lhs)
           && rtx_equal_p (XEXP (lhs, 1), XEXP (rhs, 0)))
     other = XEXP (lhs, 1), lhs = XEXP (lhs, 0), rhs = XEXP (rhs, 1);
   else if (rtx_equal_p (XEXP (lhs, 1), XEXP (rhs, 1)))
@@ -8025,8 +8042,7 @@ cached_nonzero_bits (rtx x, enum machine_mode mode, rtx known_x,
      nonzero_bits1 on X with the subexpressions as KNOWN_X and the
      precomputed value for the subexpression as KNOWN_RET.  */
 
-  if (GET_RTX_CLASS (GET_CODE (x)) == '2'
-      || GET_RTX_CLASS (GET_CODE (x)) == 'c')
+  if (ARITHMETIC_P (x))
     {
       rtx x0 = XEXP (x, 0);
       rtx x1 = XEXP (x, 1);
@@ -8037,14 +8053,12 @@ cached_nonzero_bits (rtx x, enum machine_mode mode, rtx known_x,
                              nonzero_bits_with_known (x0, mode));
 
       /* Check the second level.  */
-      if ((GET_RTX_CLASS (GET_CODE (x0)) == '2'
-          || GET_RTX_CLASS (GET_CODE (x0)) == 'c')
+      if (ARITHMETIC_P (x0)
          && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
        return nonzero_bits1 (x, mode, x1, mode,
                              nonzero_bits_with_known (x1, mode));
 
-      if ((GET_RTX_CLASS (GET_CODE (x1)) == '2'
-          || GET_RTX_CLASS (GET_CODE (x1)) == 'c')
+      if (ARITHMETIC_P (x1)
          && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
        return nonzero_bits1 (x, mode, x0, mode,
                         nonzero_bits_with_known (x0, mode));
@@ -8554,8 +8568,7 @@ cached_num_sign_bit_copies (rtx x, enum machine_mode mode, rtx known_x,
      num_sign_bit_copies1 on X with the subexpressions as KNOWN_X and
      the precomputed value for the subexpression as KNOWN_RET.  */
 
-  if (GET_RTX_CLASS (GET_CODE (x)) == '2'
-      || GET_RTX_CLASS (GET_CODE (x)) == 'c')
+  if (ARITHMETIC_P (x))
     {
       rtx x0 = XEXP (x, 0);
       rtx x1 = XEXP (x, 1);
@@ -8567,15 +8580,13 @@ cached_num_sign_bit_copies (rtx x, enum machine_mode mode, rtx known_x,
                                num_sign_bit_copies_with_known (x0, mode));
 
       /* Check the second level.  */
-      if ((GET_RTX_CLASS (GET_CODE (x0)) == '2'
-          || GET_RTX_CLASS (GET_CODE (x0)) == 'c')
+      if (ARITHMETIC_P (x0)
          && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
        return
          num_sign_bit_copies1 (x, mode, x1, mode,
                                num_sign_bit_copies_with_known (x1, mode));
 
-      if ((GET_RTX_CLASS (GET_CODE (x1)) == '2'
-          || GET_RTX_CLASS (GET_CODE (x1)) == 'c')
+      if (ARITHMETIC_P (x1)
          && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
        return
          num_sign_bit_copies1 (x, mode, x0, mode,
@@ -9790,7 +9801,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
      If we were passed a value for X, see if we can use any pieces of
      it.  If not, make new rtx.  */
 
-  if (x && GET_RTX_CLASS (GET_CODE (x)) == '2'
+  if (x && GET_RTX_CLASS (GET_CODE (x)) == RTX_BIN_ARITH
       && GET_CODE (XEXP (x, 1)) == CONST_INT
       && (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) == count)
     const_rtx = XEXP (x, 1);
@@ -9849,7 +9860,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
        /* This means that we have determined that the result is
           equivalent to a constant.  This should be rare.  */
        x = GEN_INT (outer_const);
-      else if (GET_RTX_CLASS (outer_op) == '1')
+      else if (GET_RTX_CLASS (outer_op) == RTX_UNARY)
        x = simplify_gen_unary (outer_op, result_mode, x, result_mode);
       else
        x = gen_binary (outer_op, result_mode, x, GEN_INT (outer_const));
@@ -10036,7 +10047,7 @@ gen_lowpart_for_combine (enum machine_mode mode, rtx x)
        return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
 
       /* If we want to refer to something bigger than the original memref,
-        generate a perverse subreg instead.  That will force a reload
+        generate a paradoxical subreg instead.  That will force a reload
         of the original memref X.  */
       if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode))
        return gen_rtx_SUBREG (mode, x, 0);
@@ -10058,7 +10069,7 @@ gen_lowpart_for_combine (enum machine_mode mode, rtx x)
 
   /* If X is a comparison operator, rewrite it in a new mode.  This
      probably won't match, but may allow further simplifications.  */
-  else if (GET_RTX_CLASS (GET_CODE (x)) == '<')
+  else if (COMPARISON_P (x))
     return gen_rtx_fmt_ee (GET_CODE (x), mode, XEXP (x, 0), XEXP (x, 1));
 
   /* If we couldn't simplify X any other way, just enclose it in a
@@ -10099,11 +10110,12 @@ gen_binary (enum rtx_code code, enum machine_mode mode, rtx op0, rtx op1)
   else if (GET_CODE (op1) == CLOBBER)
     return op1;
   
-  if (GET_RTX_CLASS (code) == 'c'
+  if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
       && swap_commutative_operands_p (op0, op1))
     tem = op0, op0 = op1, op1 = tem;
 
-  if (GET_RTX_CLASS (code) == '<')
+  if (GET_RTX_CLASS (code) == RTX_COMPARE
+      || GET_RTX_CLASS (code) == RTX_COMM_COMPARE)
     {
       enum machine_mode op_mode = GET_MODE (op0);
 
@@ -10118,7 +10130,7 @@ gen_binary (enum rtx_code code, enum machine_mode mode, rtx op0, rtx op1)
 
       if (op_mode == VOIDmode)
        op_mode = GET_MODE (op1);
-      result = simplify_relational_operation (code, op_mode, op0, op1);
+      result = simplify_relational_operation (code, mode, op_mode, op0, op1);
     }
   else
     result = simplify_binary_operation (code, mode, op0, op1);
@@ -10127,7 +10139,7 @@ gen_binary (enum rtx_code code, enum machine_mode mode, rtx op0, rtx op1)
     return result;
 
   /* Put complex operands first and constants second.  */
-  if (GET_RTX_CLASS (code) == 'c'
+  if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
       && swap_commutative_operands_p (op0, op1))
     return gen_rtx_fmt_ee (code, mode, op1, op0);
 
@@ -10327,8 +10339,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
 
       if (GET_MODE_CLASS (mode) != MODE_INT
          && ! (mode == VOIDmode
-               && (GET_CODE (op0) == COMPARE
-                   || GET_RTX_CLASS (GET_CODE (op0)) == '<')))
+               && (GET_CODE (op0) == COMPARE || COMPARISON_P (op0))))
        break;
 
       /* Get the constant we are comparing against and turn off all bits
@@ -10903,9 +10914,9 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              mask = ((INTVAL (XEXP (op0, 1)) & GET_MODE_MASK (mode))
                      << INTVAL (XEXP (XEXP (op0, 0), 1)));
              if ((~STORE_FLAG_VALUE & mask) == 0
-                 && (GET_RTX_CLASS (GET_CODE (XEXP (XEXP (op0, 0), 0))) == '<'
+                 && (COMPARISON_P (XEXP (XEXP (op0, 0), 0))
                      || ((tem = get_last_value (XEXP (XEXP (op0, 0), 0))) != 0
-                         && GET_RTX_CLASS (GET_CODE (tem)) == '<')))
+                         && COMPARISON_P (tem))))
                {
                  op0 = XEXP (XEXP (op0, 0), 0);
                  continue;
@@ -11368,7 +11379,7 @@ update_table_tick (rtx x)
       unsigned int regno = REGNO (x);
       unsigned int endregno
        = regno + (regno < FIRST_PSEUDO_REGISTER
-                  ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
+                  ? hard_regno_nregs[regno][GET_MODE (x)] : 1);
       unsigned int r;
 
       for (r = regno; r < endregno; r++)
@@ -11385,9 +11396,7 @@ update_table_tick (rtx x)
        /* Check for identical subexpressions.  If x contains
           identical subexpression we only have to traverse one of
           them.  */
-       if (i == 0
-           && (GET_RTX_CLASS (code) == '2'
-               || GET_RTX_CLASS (code) == 'c'))
+       if (i == 0 && ARITHMETIC_P (x))
          {
            /* Note that at this point x1 has already been
               processed.  */
@@ -11402,15 +11411,13 @@ update_table_tick (rtx x)
            /* If x0 is identical to a subexpression of x1 then while
               processing x1, x0 has already been processed.  Thus we
               are done with x.  */
-           if ((GET_RTX_CLASS (GET_CODE (x1)) == '2'
-                || GET_RTX_CLASS (GET_CODE (x1)) == 'c')
+           if (ARITHMETIC_P (x1)
                && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
              break;
 
            /* If x1 is identical to a subexpression of x0 then we
               still have to process the rest of x0.  */
-           if ((GET_RTX_CLASS (GET_CODE (x0)) == '2'
-                || GET_RTX_CLASS (GET_CODE (x0)) == 'c')
+           if (ARITHMETIC_P (x0)
                && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
              {
                update_table_tick (XEXP (x0, x1 == XEXP (x0, 0) ? 1 : 0));
@@ -11433,7 +11440,7 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
   unsigned int regno = REGNO (reg);
   unsigned int endregno
     = regno + (regno < FIRST_PSEUDO_REGISTER
-              ? HARD_REGNO_NREGS (regno, GET_MODE (reg)) : 1);
+              ? hard_regno_nregs[regno][GET_MODE (reg)] : 1);
   unsigned int i;
 
   /* If VALUE contains REG and we have a previous value for REG, substitute
@@ -11453,8 +11460,7 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
 
       if (tem)
        {
-         if ((GET_RTX_CLASS (GET_CODE (tem)) == '2'
-              || GET_RTX_CLASS (GET_CODE (tem)) == 'c')
+         if (ARITHMETIC_P (tem)
              && GET_CODE (XEXP (tem, 0)) == CLOBBER
              && GET_CODE (XEXP (tem, 1)) == CLOBBER)
            tem = XEXP (tem, 0);
@@ -11590,7 +11596,7 @@ record_dead_and_set_regs (rtx insn)
          unsigned int regno = REGNO (XEXP (link, 0));
          unsigned int endregno
            = regno + (regno < FIRST_PSEUDO_REGISTER
-                      ? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (link, 0)))
+                      ? hard_regno_nregs[regno][GET_MODE (XEXP (link, 0))]
                       : 1);
 
          for (i = regno; i < endregno; i++)
@@ -11726,7 +11732,7 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
       unsigned int regno = REGNO (x);
       unsigned int endregno
        = regno + (regno < FIRST_PSEUDO_REGISTER
-                  ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
+                  ? hard_regno_nregs[regno][GET_MODE (x)] : 1);
       unsigned int j;
 
       for (j = regno; j < endregno; j++)
@@ -11764,9 +11770,7 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
          /* Check for identical subexpressions.  If x contains
             identical subexpression we only have to traverse one of
             them.  */
-         if (i == 1
-             && (GET_RTX_CLASS (GET_CODE (x)) == '2'
-                 || GET_RTX_CLASS (GET_CODE (x)) == 'c'))
+         if (i == 1 && ARITHMETIC_P (x))
            {
              /* Note that at this point x0 has already been checked
                 and found valid.  */
@@ -11780,15 +11784,13 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
              /* If x1 is identical to a subexpression of x0 then
                 while checking x0, x1 has already been checked.  Thus
                 it is valid and so as x.  */
-             if ((GET_RTX_CLASS (GET_CODE (x0)) == '2'
-                  || GET_RTX_CLASS (GET_CODE (x0)) == 'c')
+             if (ARITHMETIC_P (x0)
                  && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
                return 1;
 
              /* If x0 is identical to a subexpression of x1 then x is
                 valid iff the rest of x1 is valid.  */
-             if ((GET_RTX_CLASS (GET_CODE (x1)) == '2'
-                  || GET_RTX_CLASS (GET_CODE (x1)) == 'c')
+             if (ARITHMETIC_P (x1)
                  && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
                return
                  get_last_value_validate (&XEXP (x1,
@@ -11888,7 +11890,7 @@ use_crosses_set_p (rtx x, int from_cuid)
     {
       unsigned int regno = REGNO (x);
       unsigned endreg = regno + (regno < FIRST_PSEUDO_REGISTER
-                                ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
+                                ? hard_regno_nregs[regno][GET_MODE (x)] : 1);
 
 #ifdef PUSH_ROUNDING
       /* Don't allow uses of the stack pointer to be moved,
@@ -11945,7 +11947,7 @@ reg_dead_at_p_1 (rtx dest, rtx x, void *data ATTRIBUTE_UNUSED)
 
   regno = REGNO (dest);
   endregno = regno + (regno < FIRST_PSEUDO_REGISTER
-                     ? HARD_REGNO_NREGS (regno, GET_MODE (dest)) : 1);
+                     ? hard_regno_nregs[regno][GET_MODE (dest)] : 1);
 
   if (reg_dead_endregno > regno && reg_dead_regno < endregno)
     reg_dead_flag = (GET_CODE (x) == CLOBBER) ? 1 : -1;
@@ -11968,8 +11970,8 @@ reg_dead_at_p (rtx reg, rtx insn)
   /* Set variables for reg_dead_at_p_1.  */
   reg_dead_regno = REGNO (reg);
   reg_dead_endregno = reg_dead_regno + (reg_dead_regno < FIRST_PSEUDO_REGISTER
-                                       ? HARD_REGNO_NREGS (reg_dead_regno,
-                                                           GET_MODE (reg))
+                                       ? hard_regno_nregs[reg_dead_regno]
+                                                         [GET_MODE (reg)]
                                        : 1);
 
   reg_dead_flag = 0;
@@ -12070,7 +12072,7 @@ mark_used_regs_combine (rtx x)
              || regno == FRAME_POINTER_REGNUM)
            return;
 
-         endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+         endregno = regno + hard_regno_nregs[regno][GET_MODE (x)];
          for (r = regno; r < endregno; r++)
            SET_HARD_REG_BIT (newpat_used_regs, r);
        }
@@ -12199,10 +12201,10 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
            {
              unsigned int deadregno = REGNO (XEXP (note, 0));
              unsigned int deadend
-               = (deadregno + HARD_REGNO_NREGS (deadregno,
-                                                GET_MODE (XEXP (note, 0))));
+               = (deadregno + hard_regno_nregs[deadregno]
+                                              [GET_MODE (XEXP (note, 0))]);
              unsigned int ourend
-               = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+               = regno + hard_regno_nregs[regno][GET_MODE (x)];
              unsigned int i;
 
              for (i = deadregno; i < deadend; i++)
@@ -12223,15 +12225,15 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
                        && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
                            < GET_MODE_SIZE (GET_MODE (x)))))
                   && regno < FIRST_PSEUDO_REGISTER
-                  && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
+                  && hard_regno_nregs[regno][GET_MODE (x)] > 1)
            {
              unsigned int ourend
-               = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+               = regno + hard_regno_nregs[regno][GET_MODE (x)];
              unsigned int i, offset;
              rtx oldnotes = 0;
 
              if (note)
-               offset = HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0)));
+               offset = hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))];
              else
                offset = 1;
 
@@ -12344,8 +12346,8 @@ reg_bitfield_target_p (rtx x, rtx body)
       if (tregno >= FIRST_PSEUDO_REGISTER || regno >= FIRST_PSEUDO_REGISTER)
        return target == x;
 
-      endtregno = tregno + HARD_REGNO_NREGS (tregno, GET_MODE (target));
-      endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+      endtregno = tregno + hard_regno_nregs[tregno][GET_MODE (target)];
+      endregno = regno + hard_regno_nregs[regno][GET_MODE (x)];
 
       return endregno > tregno && regno < endtregno;
     }
@@ -12716,26 +12718,16 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                            }
 #endif
                        }
-                     /* If the register is both set and used here, put the
-                        REG_DEAD note here, but place a REG_UNUSED note
-                        here too unless there already is one.  */
-                     else if (reg_referenced_p (XEXP (note, 0),
-                                                PATTERN (tem)))
-                       {
-                         place = tem;
-
-                         if (! find_regno_note (tem, REG_UNUSED,
-                                                REGNO (XEXP (note, 0))))
-                           REG_NOTES (tem)
-                             = gen_rtx_EXPR_LIST (REG_UNUSED, XEXP (note, 0),
-                                                  REG_NOTES (tem));
-                       }
                      else
                        {
                          PUT_REG_NOTE_KIND (note, REG_UNUSED);
 
                          /*  If there isn't already a REG_UNUSED note, put one
-                             here.  */
+                             here.  Do not place a REG_DEAD note, even if
+                             the register is also used here; that would not
+                             match the algorithm used in lifetime analysis
+                             and can cause the consistency check in the
+                             scheduler to fail.  */
                          if (! find_regno_note (tem, REG_UNUSED,
                                                 REGNO (XEXP (note, 0))))
                            place = tem;
@@ -12821,11 +12813,11 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                 the previous insn that used this register.  */
 
              if (place && regno < FIRST_PSEUDO_REGISTER
-                 && HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0))) > 1)
+                 && hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))] > 1)
                {
                  unsigned int endregno
-                   = regno + HARD_REGNO_NREGS (regno,
-                                               GET_MODE (XEXP (note, 0)));
+                   = regno + hard_regno_nregs[regno]
+                                             [GET_MODE (XEXP (note, 0))];
                  int all_used = 1;
                  unsigned int i;
 
@@ -12841,7 +12833,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                         not already dead or set.  */
 
                      for (i = regno; i < endregno;
-                          i += HARD_REGNO_NREGS (i, reg_raw_mode[i]))
+                          i += hard_regno_nregs[i][reg_raw_mode[i]])
                        {
                          rtx piece = regno_reg_rtx[i];
                          basic_block bb = this_basic_block;
@@ -13014,6 +13006,33 @@ distribute_links (rtx links)
     }
 }
 \f
+/* Subroutine of unmentioned_reg_p and callback from for_each_rtx.
+   Check whether the expression pointer to by LOC is a register or
+   memory, and if so return 1 if it isn't mentioned in the rtx EXPR.
+   Otherwise return zero.  */
+
+static int
+unmentioned_reg_p_1 (rtx *loc, void *expr)
+{
+  rtx x = *loc;
+
+  if (x != NULL_RTX
+      && (GET_CODE (x) == REG || GET_CODE (x) == MEM)
+      && ! reg_mentioned_p (x, (rtx) expr))
+    return 1;
+  return 0;
+}
+
+/* Check for any register or memory mentioned in EQUIV that is not
+   mentioned in EXPR.  This is used to restrict EQUIV to "specializations"
+   of EXPR where some registers may have been replaced by constants.  */
+
+static bool
+unmentioned_reg_p (rtx equiv, rtx expr)
+{
+  return for_each_rtx (&equiv, unmentioned_reg_p_1, expr);
+}
+\f
 /* Compute INSN_CUID for INSN, which is an insn made by combine.  */
 
 static int