OSDN Git Service

* gfortran.texi: Use @table @emph instead of @itemize @emph.
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index c36d922..2abd3d8 100644 (file)
@@ -1,6 +1,6 @@
 /* Optimize by combining instructions for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -91,10 +91,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "toplev.h"
 #include "target.h"
 
-/* It is not safe to use ordinary gen_lowpart in combine.
-   Use gen_lowpart_for_combine instead.  See comments there.  */
-#define gen_lowpart dont_use_gen_lowpart_you_dummy
-
 /* Number of attempts to combine instructions in this function.  */
 
 static int combine_attempts;
@@ -147,13 +143,103 @@ static int max_uid_cuid;
 
 static unsigned int combine_max_regno;
 
-/* Record last point of death of (hard or pseudo) register n.  */
+struct reg_stat {
+  /* Record last point of death of (hard or pseudo) register n.  */
+  rtx                          last_death;
+
+  /* Record last point of modification of (hard or pseudo) register n.  */
+  rtx                          last_set;
+
+  /* The next group of fields allows the recording of the last value assigned
+     to (hard or pseudo) register n.  We use this information to see if an
+     operation being processed is redundant given a prior operation performed
+     on the register.  For example, an `and' with a constant is redundant if
+     all the zero bits are already known to be turned off.
+
+     We use an approach similar to that used by cse, but change it in the
+     following ways:
+
+     (1) We do not want to reinitialize at each label.
+     (2) It is useful, but not critical, to know the actual value assigned
+         to a register.  Often just its form is helpful.
+
+     Therefore, we maintain the following fields:
+
+     last_set_value            the last value assigned
+     last_set_label            records the value of label_tick when the
+                               register was assigned
+     last_set_table_tick       records the value of label_tick when a
+                               value using the register is assigned
+     last_set_invalid          set to nonzero when it is not valid
+                               to use the value of this register in some
+                               register's value
+
+     To understand the usage of these tables, it is important to understand
+     the distinction between the value in last_set_value being valid and
+     the register being validly contained in some other expression in the
+     table.
+
+     (The next two parameters are out of date).
+
+     reg_stat[i].last_set_value is valid if it is nonzero, and either
+     reg_n_sets[i] is 1 or reg_stat[i].last_set_label == label_tick.
+
+     Register I may validly appear in any expression returned for the value
+     of another register if reg_n_sets[i] is 1.  It may also appear in the
+     value for register J if reg_stat[j].last_set_invalid is zero, or
+     reg_stat[i].last_set_label < reg_stat[j].last_set_label.
+
+     If an expression is found in the table containing a register which may
+     not validly appear in an expression, the register is replaced by
+     something that won't match, (clobber (const_int 0)).  */
+
+  /* Record last value assigned to (hard or pseudo) register n.  */
+
+  rtx                          last_set_value;
+
+  /* Record the value of label_tick when an expression involving register n
+     is placed in last_set_value.  */
+
+  int                          last_set_table_tick;
+
+  /* Record the value of label_tick when the value for register n is placed in
+     last_set_value.  */
+
+  int                          last_set_label;
 
-static rtx *reg_last_death;
+  /* These fields are maintained in parallel with last_set_value and are
+     used to store the mode in which the register was last set, te bits
+     that were known to be zero when it was last set, and the number of
+     sign bits copies it was known to have when it was last set.  */
 
-/* Record last point of modification of (hard or pseudo) register n.  */
+  unsigned HOST_WIDE_INT       last_set_nonzero_bits;
+  char                         last_set_sign_bit_copies;
+  ENUM_BITFIELD(machine_mode)  last_set_mode : 8; 
 
-static rtx *reg_last_set;
+  /* Set nonzero if references to register n in expressions should not be
+     used.  last_set_invalid is set nonzero when this register is being
+     assigned to and last_set_table_tick == label_tick.  */
+
+  char                         last_set_invalid;
+
+  /* Some registers that are set more than once and used in more than one
+     basic block are nevertheless always set in similar ways.  For example,
+     a QImode register may be loaded from memory in two places on a machine
+     where byte loads zero extend.
+
+     We record in the following fields if a register has some leading bits
+     that are always equal to the sign bit, and what we know about the
+     nonzero bits of a register, specifically which bits are known to be
+     zero.
+
+     If an entry is zero, it means that we don't know anything special.  */
+
+  unsigned char                        sign_bit_copies;
+
+  unsigned HOST_WIDE_INT       nonzero_bits;
+};
+
+static struct reg_stat *reg_stat;
 
 /* Record the cuid of the last insn that invalidated memory
    (anything that writes memory, and subroutine calls, but not pushes).  */
@@ -201,110 +287,23 @@ static basic_block this_basic_block;
    those blocks as starting points.  */
 static sbitmap refresh_blocks;
 \f
-/* The next group of arrays allows the recording of the last value assigned
-   to (hard or pseudo) register n.  We use this information to see if an
-   operation being processed is redundant given a prior operation performed
-   on the register.  For example, an `and' with a constant is redundant if
-   all the zero bits are already known to be turned off.
-
-   We use an approach similar to that used by cse, but change it in the
-   following ways:
-
-   (1) We do not want to reinitialize at each label.
-   (2) It is useful, but not critical, to know the actual value assigned
-       to a register.  Often just its form is helpful.
-
-   Therefore, we maintain the following arrays:
-
-   reg_last_set_value          the last value assigned
-   reg_last_set_label          records the value of label_tick when the
-                               register was assigned
-   reg_last_set_table_tick     records the value of label_tick when a
-                               value using the register is assigned
-   reg_last_set_invalid                set to nonzero when it is not valid
-                               to use the value of this register in some
-                               register's value
-
-   To understand the usage of these tables, it is important to understand
-   the distinction between the value in reg_last_set_value being valid
-   and the register being validly contained in some other expression in the
-   table.
-
-   Entry I in reg_last_set_value is valid if it is nonzero, and either
-   reg_n_sets[i] is 1 or reg_last_set_label[i] == label_tick.
-
-   Register I may validly appear in any expression returned for the value
-   of another register if reg_n_sets[i] is 1.  It may also appear in the
-   value for register J if reg_last_set_label[i] < reg_last_set_label[j] or
-   reg_last_set_invalid[j] is zero.
-
-   If an expression is found in the table containing a register which may
-   not validly appear in an expression, the register is replaced by
-   something that won't match, (clobber (const_int 0)).
-
-   reg_last_set_invalid[i] is set nonzero when register I is being assigned
-   to and reg_last_set_table_tick[i] == label_tick.  */
-
-/* Record last value assigned to (hard or pseudo) register n.  */
-
-static rtx *reg_last_set_value;
-
-/* Record the value of label_tick when the value for register n is placed in
-   reg_last_set_value[n].  */
-
-static int *reg_last_set_label;
-
-/* Record the value of label_tick when an expression involving register n
-   is placed in reg_last_set_value.  */
-
-static int *reg_last_set_table_tick;
-
-/* Set nonzero if references to register n in expressions should not be
-   used.  */
-
-static char *reg_last_set_invalid;
-
 /* Incremented for each label.  */
 
 static int label_tick;
 
-/* Some registers that are set more than once and used in more than one
-   basic block are nevertheless always set in similar ways.  For example,
-   a QImode register may be loaded from memory in two places on a machine
-   where byte loads zero extend.
-
-   We record in the following array what we know about the nonzero
-   bits of a register, specifically which bits are known to be zero.
-
-   If an entry is zero, it means that we don't know anything special.  */
-
-static unsigned HOST_WIDE_INT *reg_nonzero_bits;
-
-/* Mode used to compute significance in reg_nonzero_bits.  It is the largest
-   integer mode that can fit in HOST_BITS_PER_WIDE_INT.  */
+/* Mode used to compute significance in reg_stat[].nonzero_bits.  It is the
+   largest integer mode that can fit in HOST_BITS_PER_WIDE_INT.  */
 
 static enum machine_mode nonzero_bits_mode;
 
-/* Nonzero if we know that a register has some leading bits that are always
-   equal to the sign bit.  */
-
-static unsigned char *reg_sign_bit_copies;
-
-/* Nonzero when reg_nonzero_bits and reg_sign_bit_copies can be safely used.
-   It is zero while computing them and after combine has completed.  This
-   former test prevents propagating values based on previously set values,
-   which can be incorrect if a variable is modified in a loop.  */
+/* Nonzero when reg_stat[].nonzero_bits and reg_stat[].sign_bit_copies can
+   be safely used.  It is zero while computing them and after combine has
+   completed.  This former test prevents propagating values based on
+   previously set values, which can be incorrect if a variable is modified
+   in a loop.  */
 
 static int nonzero_sign_valid;
 
-/* These arrays are maintained in parallel with reg_last_set_value
-   and are used to store the mode in which the register was last set,
-   the bits that were known to be zero when it was last set, and the
-   number of sign bits copies it was known to have when it was last set.  */
-
-static enum machine_mode *reg_last_set_mode;
-static unsigned HOST_WIDE_INT *reg_last_set_nonzero_bits;
-static char *reg_last_set_sign_bit_copies;
 \f
 /* Record one modification to rtl structure
    to be undone by storing old_contents into *where.
@@ -340,12 +339,11 @@ static int n_occurrences;
 
 static void do_SUBST (rtx *, rtx);
 static void do_SUBST_INT (int *, int);
-static void init_reg_last_arrays (void);
+static void init_reg_last (void);
 static void setup_incoming_promotions (void);
 static void set_nonzero_bits_and_sign_copies (rtx, rtx, void *);
 static int cant_combine_insn_p (rtx);
 static int can_combine_p (rtx, rtx, rtx, rtx, rtx *, rtx *);
-static int sets_function_arg_p (rtx);
 static int combinable_i3pat (rtx, rtx *, rtx, rtx, int, rtx *);
 static int contains_muldiv (rtx);
 static rtx try_combine (rtx, rtx, rtx, int *);
@@ -353,10 +351,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,
@@ -412,6 +410,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
@@ -522,20 +522,11 @@ combine_instructions (rtx f, unsigned int nregs)
 
   combine_max_regno = nregs;
 
-  reg_nonzero_bits = xcalloc (nregs, sizeof (unsigned HOST_WIDE_INT));
-  reg_sign_bit_copies = xcalloc (nregs, sizeof (unsigned char));
-
-  reg_last_death = xmalloc (nregs * sizeof (rtx));
-  reg_last_set = xmalloc (nregs * sizeof (rtx));
-  reg_last_set_value = xmalloc (nregs * sizeof (rtx));
-  reg_last_set_table_tick = xmalloc (nregs * sizeof (int));
-  reg_last_set_label = xmalloc (nregs * sizeof (int));
-  reg_last_set_invalid = xmalloc (nregs * sizeof (char));
-  reg_last_set_mode = xmalloc (nregs * sizeof (enum machine_mode));
-  reg_last_set_nonzero_bits = xmalloc (nregs * sizeof (HOST_WIDE_INT));
-  reg_last_set_sign_bit_copies = xmalloc (nregs * sizeof (char));
+  /* It is not safe to use ordinary gen_lowpart in combine.
+     See comments in gen_lowpart_for_combine.  */
+  gen_lowpart = gen_lowpart_for_combine;
 
-  init_reg_last_arrays ();
+  reg_stat = xcalloc (nregs, sizeof (struct reg_stat));
 
   init_recog_no_volatile ();
 
@@ -550,8 +541,8 @@ combine_instructions (rtx f, unsigned int nregs)
 
   nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
 
-  /* Don't use reg_nonzero_bits when computing it.  This can cause problems
-     when, for example, we have j <<= 1 in a loop.  */
+  /* Don't use reg_stat[].nonzero_bits when computing it.  This can cause
+     problems when, for example, we have j <<= 1 in a loop.  */
 
   nonzero_sign_valid = 0;
 
@@ -604,13 +595,13 @@ combine_instructions (rtx f, unsigned int nregs)
   label_tick = 1;
   last_call_cuid = 0;
   mem_last_set = 0;
-  init_reg_last_arrays ();
+  init_reg_last ();
   setup_incoming_promotions ();
 
   FOR_EACH_BB (this_basic_block)
     {
-      for (insn = this_basic_block->head;
-           insn != NEXT_INSN (this_basic_block->end);
+      for (insn = BB_HEAD (this_basic_block);
+           insn != NEXT_INSN (BB_END (this_basic_block));
           insn = next ? next : NEXT_INSN (insn))
        {
          next = 0;
@@ -721,6 +712,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);
 
@@ -742,17 +758,7 @@ combine_instructions (rtx f, unsigned int nregs)
 
   /* Clean up.  */
   sbitmap_free (refresh_blocks);
-  free (reg_nonzero_bits);
-  free (reg_sign_bit_copies);
-  free (reg_last_death);
-  free (reg_last_set);
-  free (reg_last_set_value);
-  free (reg_last_set_table_tick);
-  free (reg_last_set_label);
-  free (reg_last_set_invalid);
-  free (reg_last_set_mode);
-  free (reg_last_set_nonzero_bits);
-  free (reg_last_set_sign_bit_copies);
+  free (reg_stat);
   free (uid_cuid);
 
   {
@@ -771,6 +777,7 @@ combine_instructions (rtx f, unsigned int nregs)
   total_successes += combine_successes;
 
   nonzero_sign_valid = 0;
+  gen_lowpart = gen_lowpart_general;
 
   /* Make recognizer allow volatile MEMs again.  */
   init_recog ();
@@ -778,22 +785,14 @@ combine_instructions (rtx f, unsigned int nregs)
   return new_direct_jump_p;
 }
 
-/* Wipe the reg_last_xxx arrays in preparation for another pass.  */
+/* Wipe the last_xxx fields of reg_stat in preparation for another pass.  */
 
 static void
-init_reg_last_arrays (void)
+init_reg_last (void)
 {
-  unsigned int nregs = combine_max_regno;
-
-  memset (reg_last_death, 0, nregs * sizeof (rtx));
-  memset (reg_last_set, 0, nregs * sizeof (rtx));
-  memset (reg_last_set_value, 0, nregs * sizeof (rtx));
-  memset (reg_last_set_table_tick, 0, nregs * sizeof (int));
-  memset (reg_last_set_label, 0, nregs * sizeof (int));
-  memset (reg_last_set_invalid, 0, nregs * sizeof (char));
-  memset (reg_last_set_mode, 0, nregs * sizeof (enum machine_mode));
-  memset (reg_last_set_nonzero_bits, 0, nregs * sizeof (HOST_WIDE_INT));
-  memset (reg_last_set_sign_bit_copies, 0, nregs * sizeof (char));
+  unsigned int i;
+  for (i = 0; i < combine_max_regno; i++)
+    memset (reg_stat + i, 0, offsetof (struct reg_stat, sign_bit_copies));
 }
 \f
 /* Set up any promoted values for incoming argument registers.  */
@@ -809,9 +808,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
@@ -854,8 +850,8 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set,
     {
       if (set == 0 || GET_CODE (set) == CLOBBER)
        {
-         reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
-         reg_sign_bit_copies[REGNO (x)] = 1;
+         reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x));
+         reg_stat[REGNO (x)].sign_bit_copies = 1;
          return;
        }
 
@@ -877,7 +873,7 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set,
 #ifdef SHORT_IMMEDIATES_SIGN_EXTEND
          /* If X is narrower than a word and SRC is a non-negative
             constant that would appear negative in the mode of X,
-            sign-extend it for use in reg_nonzero_bits because some
+            sign-extend it for use in reg_stat[].nonzero_bits because some
             machines (maybe most) will actually do the sign-extension
             and this is the conservative approach.
 
@@ -896,18 +892,18 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set,
 #endif
 
          /* Don't call nonzero_bits if it cannot change anything.  */
-         if (reg_nonzero_bits[REGNO (x)] != ~(unsigned HOST_WIDE_INT) 0)
-           reg_nonzero_bits[REGNO (x)]
+         if (reg_stat[REGNO (x)].nonzero_bits != ~(unsigned HOST_WIDE_INT) 0)
+           reg_stat[REGNO (x)].nonzero_bits
              |= nonzero_bits (src, nonzero_bits_mode);
          num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x));
-         if (reg_sign_bit_copies[REGNO (x)] == 0
-             || reg_sign_bit_copies[REGNO (x)] > num)
-           reg_sign_bit_copies[REGNO (x)] = num;
+         if (reg_stat[REGNO (x)].sign_bit_copies == 0
+             || reg_stat[REGNO (x)].sign_bit_copies > num)
+           reg_stat[REGNO (x)].sign_bit_copies = num;
        }
       else
        {
-         reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
-         reg_sign_bit_copies[REGNO (x)] = 1;
+         reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x));
+         reg_stat[REGNO (x)].sign_bit_copies = 1;
        }
     }
 }
@@ -959,6 +955,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))
            {
@@ -1009,6 +1006,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;
 
@@ -1074,7 +1073,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
         does not use any registers whose values alter in between.  However,
         If the insns are adjacent, a use can't cross a set even though we
         think it might (this can happen for a sequence of insns each setting
-        the same destination; reg_last_set of that register might point to
+        the same destination; last_set of that register might point to
         a NOTE).  If INSN has a REG_EQUIV note, the register is always
         equivalent to the memory so the substitution is valid even if there
         are intervening stores.  Also, don't move a volatile asm or
@@ -1205,45 +1204,6 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
   return 1;
 }
 \f
-/* Check if PAT is an insn - or a part of it - used to set up an
-   argument for a function in a hard register.  */
-
-static int
-sets_function_arg_p (rtx pat)
-{
-  int i;
-  rtx inner_dest;
-
-  switch (GET_CODE (pat))
-    {
-    case INSN:
-      return sets_function_arg_p (PATTERN (pat));
-
-    case PARALLEL:
-      for (i = XVECLEN (pat, 0); --i >= 0;)
-       if (sets_function_arg_p (XVECEXP (pat, 0, i)))
-         return 1;
-
-      break;
-
-    case SET:
-      inner_dest = SET_DEST (pat);
-      while (GET_CODE (inner_dest) == STRICT_LOW_PART
-            || GET_CODE (inner_dest) == SUBREG
-            || GET_CODE (inner_dest) == ZERO_EXTRACT)
-       inner_dest = XEXP (inner_dest, 0);
-
-      return (GET_CODE (inner_dest) == REG
-             && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
-             && FUNCTION_ARG_REGNO_P (REGNO (inner_dest)));
-
-    default:
-      break;
-    }
-
-  return 0;
-}
-
 /* LOC is the location within I3 that contains its pattern or the component
    of a PARALLEL of the pattern.  We validate that it is valid for combining.
 
@@ -1379,18 +1339,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
@@ -1491,7 +1447,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;
@@ -1861,9 +1817,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);
@@ -2052,45 +2006,68 @@ 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.
 
-  if (insn_code_number < 0 && GET_CODE (newpat) == PARALLEL
+     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
+      && !(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
-      && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == REG
-      && find_reg_note (i3, REG_UNUSED, SET_DEST (XVECEXP (newpat, 0, 1)))
-      && ! side_effects_p (SET_SRC (XVECEXP (newpat, 0, 1)))
       && asm_noperands (newpat) < 0)
     {
-      newpat = XVECEXP (newpat, 0, 0);
-      insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
-    }
+      rtx set0 = XVECEXP (newpat, 0, 0);
+      rtx set1 = XVECEXP (newpat, 0, 1);
+      rtx note;
 
-  else if (insn_code_number < 0 && GET_CODE (newpat) == PARALLEL
-          && XVECLEN (newpat, 0) == 2
-          && GET_CODE (XVECEXP (newpat, 0, 0)) == SET
-          && GET_CODE (XVECEXP (newpat, 0, 1)) == SET
-          && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) == REG
-          && find_reg_note (i3, REG_UNUSED, SET_DEST (XVECEXP (newpat, 0, 0)))
-          && ! side_effects_p (SET_SRC (XVECEXP (newpat, 0, 0)))
-          && asm_noperands (newpat) < 0)
-    {
-      newpat = XVECEXP (newpat, 0, 1);
-      insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
-      if (insn_code_number >= 0)
+      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)))))
+         && (!(note = find_reg_note (i3, REG_EH_REGION, NULL_RTX))
+             || INTVAL (XEXP (note, 0)) <= 0)
+         && ! side_effects_p (SET_SRC (set1)))
        {
-         /* 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);
+         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)))))
+              && (!(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);
+           }
        }
     }
 
@@ -2326,18 +2303,18 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
           && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART
           && ! (temp = SET_DEST (XVECEXP (newpat, 0, 1)),
                 (GET_CODE (temp) == REG
-                 && reg_nonzero_bits[REGNO (temp)] != 0
+                 && reg_stat[REGNO (temp)].nonzero_bits != 0
                  && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
                  && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
-                 && (reg_nonzero_bits[REGNO (temp)]
+                 && (reg_stat[REGNO (temp)].nonzero_bits
                      != GET_MODE_MASK (word_mode))))
           && ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG
                 && (temp = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))),
                     (GET_CODE (temp) == REG
-                     && reg_nonzero_bits[REGNO (temp)] != 0
+                     && reg_stat[REGNO (temp)].nonzero_bits != 0
                      && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
                      && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
-                     && (reg_nonzero_bits[REGNO (temp)]
+                     && (reg_stat[REGNO (temp)].nonzero_bits
                          != GET_MODE_MASK (word_mode)))))
           && ! reg_overlap_mentioned_p (SET_DEST (XVECEXP (newpat, 0, 1)),
                                         SET_SRC (XVECEXP (newpat, 0, 1)))
@@ -2350,7 +2327,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
       ni2dest = SET_DEST (XVECEXP (newpat, 0, 0));
       newpat = XVECEXP (newpat, 0, 1);
       SUBST (SET_SRC (newpat),
-            gen_lowpart_for_combine (GET_MODE (SET_SRC (newpat)), ni2dest));
+            gen_lowpart (GET_MODE (SET_SRC (newpat)), ni2dest));
       i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
 
       if (i2_code_number >= 0)
@@ -2377,7 +2354,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
          for (insn = NEXT_INSN (i3);
               insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR
-                       || insn != this_basic_block->next_bb->head);
+                       || insn != BB_HEAD (this_basic_block->next_bb));
               insn = NEXT_INSN (insn))
            {
              if (INSN_P (insn) && reg_referenced_p (ni2dest, PATTERN (insn)))
@@ -2496,7 +2473,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
                        undobuf.other_insn, NULL_RTX);
     }
 #ifdef HAVE_cc0
-  /* If I2 is the setter CC0 and I3 is the user CC0 then check whether
+  /* If I2 is the CC0 setter and I3 is the CC0 user then check whether
      they are adjacent to each other or not.  */
   {
     rtx p = prev_nonnote_insn (i3);
@@ -2586,7 +2563,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
                                  SET_DEST (XVECEXP (PATTERN (i2), 0, i))))
            for (temp = NEXT_INSN (i2);
                 temp && (this_basic_block->next_bb == EXIT_BLOCK_PTR
-                         || this_basic_block->head != temp);
+                         || BB_HEAD (this_basic_block) != temp);
                 temp = NEXT_INSN (temp))
              if (temp != i3 && INSN_P (temp))
                for (link = LOG_LINKS (temp); link; link = XEXP (link, 1))
@@ -2778,9 +2755,10 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
          REG_N_SETS (regno)--;
       }
 
-    /* Update reg_nonzero_bits et al for any changes that may have been made
-       to this insn.  The order of set_nonzero_bits_and_sign_copies() is
-       important.  Because newi2pat can affect nonzero_bits of newpat */
+    /* Update reg_stat[].nonzero_bits et al for any changes that may have
+       been made to this insn.  The order of
+       set_nonzero_bits_and_sign_copies() is important.  Because newi2pat
+       can affect nonzero_bits of newpat */
     if (newi2pat)
       note_stores (newi2pat, set_nonzero_bits_and_sign_copies, NULL);
     note_stores (newpat, set_nonzero_bits_and_sign_copies, NULL);
@@ -2977,10 +2955,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;
@@ -2995,9 +2972,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,7 +3137,7 @@ find_split_point (rtx *loc, rtx insn)
              SUBST (SET_SRC (x),
                     gen_rtx_AND (mode,
                                  gen_rtx_LSHIFTRT
-                                 (mode, gen_lowpart_for_combine (mode, inner),
+                                 (mode, gen_lowpart (mode, inner),
                                   GEN_INT (pos)),
                                  GEN_INT (((HOST_WIDE_INT) 1 << len) - 1)));
 
@@ -3174,7 +3151,7 @@ find_split_point (rtx *loc, rtx insn)
                     gen_rtx_fmt_ee
                     (unsignedp ? LSHIFTRT : ASHIFTRT, mode,
                      gen_rtx_ASHIFT (mode,
-                                     gen_lowpart_for_combine (mode, inner),
+                                     gen_lowpart (mode, inner),
                                      GEN_INT (GET_MODE_BITSIZE (mode)
                                               - len - pos)),
                      GEN_INT (GET_MODE_BITSIZE (mode) - len)));
@@ -3188,14 +3165,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
@@ -3203,10 +3177,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);
 
@@ -3246,20 +3217,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)
@@ -3269,10 +3241,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.
@@ -3331,7 +3304,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.
@@ -3543,7 +3516,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;
@@ -3562,13 +3535,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);
@@ -3578,7 +3549,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);
@@ -3634,21 +3605,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;
 
@@ -3656,14 +3623,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
@@ -3729,10 +3695,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)
@@ -3741,29 +3710,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)
@@ -3801,7 +3762,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;
@@ -3814,7 +3775,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,
@@ -3841,15 +3802,15 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
       if (op0_mode == VOIDmode)
        op0_mode = GET_MODE (SUBREG_REG (x));
 
-      /* simplify_subreg can't use gen_lowpart_for_combine.  */
+      /* See if this can be moved to simplify_subreg.  */
       if (CONSTANT_P (SUBREG_REG (x))
          && subreg_lowpart_offset (mode, op0_mode) == SUBREG_BYTE (x)
-            /* Don't call gen_lowpart_for_combine if the inner mode
+            /* Don't call gen_lowpart if the inner mode
                is VOIDmode and we cannot simplify it, as SUBREG without
                inner mode is invalid.  */
          && (GET_MODE (SUBREG_REG (x)) != VOIDmode
              || gen_lowpart_common (mode, SUBREG_REG (x))))
-       return gen_lowpart_for_combine (mode, SUBREG_REG (x));
+       return gen_lowpart (mode, SUBREG_REG (x));
 
       if (GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_CC)
         break;
@@ -3888,7 +3849,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
                              simplify_gen_unary (NOT, inner_mode, const1_rtx,
                                                  inner_mode),
                              XEXP (SUBREG_REG (XEXP (x, 0)), 1));
-         return gen_lowpart_for_combine (mode, x);
+         return gen_lowpart (mode, x);
        }
 
       /* Apply De Morgan's laws to reduce number of patterns for machines
@@ -4015,16 +3976,16 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
             >= (unsigned int) (GET_MODE_BITSIZE (mode) + 1)
          && ! (GET_CODE (XEXP (x, 0)) == LSHIFTRT
                && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT))
-       return gen_lowpart_for_combine (mode, XEXP (x, 0));
+       return gen_lowpart (mode, XEXP (x, 0));
 
       /* A truncate of a comparison can be replaced with a subreg if
          STORE_FLAG_VALUE permits.  This is like the previous test,
          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_for_combine (mode, XEXP (x, 0));
+       return gen_lowpart (mode, XEXP (x, 0));
 
       /* Similarly, a truncate of a register whose value is a
          comparison can be replaced with a subreg if STORE_FLAG_VALUE
@@ -4032,8 +3993,8 @@ 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)) == '<')
-       return gen_lowpart_for_combine (mode, XEXP (x, 0));
+         && COMPARISON_P (temp))
+       return gen_lowpart (mode, XEXP (x, 0));
 
       break;
 
@@ -4198,7 +4159,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,
@@ -4233,7 +4194,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
@@ -4248,7 +4209,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))))
@@ -4381,8 +4342,8 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
              && op1 == const0_rtx
              && mode == GET_MODE (op0)
              && nonzero_bits (op0, mode) == 1)
-           return gen_lowpart_for_combine (mode,
-                                           expand_compound_operation (op0));
+           return gen_lowpart (mode,
+                               expand_compound_operation (op0));
 
          else if (STORE_FLAG_VALUE == 1
                   && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
@@ -4393,7 +4354,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
            {
              op0 = expand_compound_operation (op0);
              return simplify_gen_unary (NEG, mode,
-                                        gen_lowpart_for_combine (mode, op0),
+                                        gen_lowpart (mode, op0),
                                         mode);
            }
 
@@ -4405,7 +4366,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
            {
              op0 = expand_compound_operation (op0);
              return gen_binary (XOR, mode,
-                                gen_lowpart_for_combine (mode, op0),
+                                gen_lowpart (mode, op0),
                                 const1_rtx);
            }
 
@@ -4417,7 +4378,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
                       == GET_MODE_BITSIZE (mode)))
            {
              op0 = expand_compound_operation (op0);
-             return plus_constant (gen_lowpart_for_combine (mode, op0), 1);
+             return plus_constant (gen_lowpart (mode, op0), 1);
            }
 
          /* If STORE_FLAG_VALUE is -1, we have cases similar to
@@ -4427,8 +4388,8 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
              && op1 == const0_rtx
              && (num_sign_bit_copies (op0, mode)
                  == GET_MODE_BITSIZE (mode)))
-           return gen_lowpart_for_combine (mode,
-                                           expand_compound_operation (op0));
+           return gen_lowpart (mode,
+                               expand_compound_operation (op0));
 
          else if (STORE_FLAG_VALUE == -1
                   && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
@@ -4438,7 +4399,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
            {
              op0 = expand_compound_operation (op0);
              return simplify_gen_unary (NEG, mode,
-                                        gen_lowpart_for_combine (mode, op0),
+                                        gen_lowpart (mode, op0),
                                         mode);
            }
 
@@ -4451,7 +4412,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
            {
              op0 = expand_compound_operation (op0);
              return simplify_gen_unary (NOT, mode,
-                                        gen_lowpart_for_combine (mode, op0),
+                                        gen_lowpart (mode, op0),
                                         mode);
            }
 
@@ -4463,7 +4424,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
                   && nonzero_bits (op0, mode) == 1)
            {
              op0 = expand_compound_operation (op0);
-             return plus_constant (gen_lowpart_for_combine (mode, op0), -1);
+             return plus_constant (gen_lowpart (mode, op0), -1);
            }
 
          /* If STORE_FLAG_VALUE says to just test the sign bit and X has just
@@ -4518,7 +4479,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>) */
@@ -4576,7 +4537,6 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
        return simplify_shift_const (x, code, mode, XEXP (x, 0),
                                     INTVAL (XEXP (x, 1)));
 
-#ifdef SHIFT_COUNT_TRUNCATED
       else if (SHIFT_COUNT_TRUNCATED && GET_CODE (XEXP (x, 1)) != REG)
        SUBST (XEXP (x, 1),
               force_to_mode (XEXP (x, 1), GET_MODE (XEXP (x, 1)),
@@ -4584,8 +4544,6 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
                               << exact_log2 (GET_MODE_BITSIZE (GET_MODE (x))))
                              - 1,
                              NULL_RTX, 0));
-#endif
-
       break;
 
     case VEC_SELECT:
@@ -4644,7 +4602,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;
@@ -4729,11 +4687,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))))
     {
@@ -4750,7 +4706,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.  */
@@ -4931,7 +4887,7 @@ simplify_if_then_else (rtx x)
          temp = gen_binary (MULT, m, temp,
                             gen_binary (MULT, m, c1, const_true_rtx));
          temp = subst (temp, pc_rtx, pc_rtx, 0, 0);
-         temp = gen_binary (op, m, gen_lowpart_for_combine (m, z), temp);
+         temp = gen_binary (op, m, gen_lowpart (m, z), temp);
 
          if (extend_op != NIL)
            temp = simplify_gen_unary (extend_op, mode, temp, m);
@@ -4954,11 +4910,12 @@ simplify_if_then_else (rtx x)
              && (i = exact_log2 (-INTVAL (true_rtx))) >= 0)))
     return
       simplify_shift_const (NULL_RTX, ASHIFT, mode,
-                           gen_lowpart_for_combine (mode, XEXP (cond, 0)), i);
+                           gen_lowpart (mode, XEXP (cond, 0)), i);
 
   /* (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)
@@ -5002,7 +4959,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);
@@ -5010,22 +4967,23 @@ simplify_set (rtx x)
       rtx op0, op1, tmp;
       int other_changed = 0;
       enum machine_mode compare_mode = GET_MODE (dest);
-      enum machine_mode tmp_mode;
 
       if (GET_CODE (src) == COMPARE)
        op0 = XEXP (src, 0), op1 = XEXP (src, 1);
       else
        op0 = src, op1 = const0_rtx;
 
-      /* Check whether the comparison is known at compile time.  */
-      if (GET_MODE (op0) != VOIDmode)
-       tmp_mode = GET_MODE (op0);
-      else if (GET_MODE (op1) != VOIDmode)
-       tmp_mode = GET_MODE (op1);
+      tmp = simplify_relational_operation (old_code, compare_mode, VOIDmode,
+                                          op0, op1);
+      if (!tmp)
+        new_code = old_code;
+      else if (!CONSTANT_P (tmp))
+        {
+          new_code = GET_CODE (tmp);
+          op0 = XEXP (tmp, 0);
+          op1 = XEXP (tmp, 1);
+        }
       else
-       tmp_mode = compare_mode;
-      tmp = simplify_relational_operation (old_code, tmp_mode, op0, op1);
-      if (tmp != NULL_RTX)
        {
          rtx pat = PATTERN (other_insn);
          undobuf.other_insn = other_insn;
@@ -5046,12 +5004,15 @@ simplify_set (rtx x)
        }
 
       /* Simplify our comparison, if possible.  */
-      new_code = simplify_comparison (old_code, &op0, &op1);
+      new_code = simplify_comparison (new_code, &op0, &op1);
 
 #ifdef SELECT_CC_MODE
       /* If this machine has CC modes other than CCmode, check to see if we
         need to use a different CC mode here.  */
-      compare_mode = SELECT_CC_MODE (new_code, op0, op1);
+      if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
+       compare_mode = GET_MODE (op0);
+      else
+       compare_mode = SELECT_CC_MODE (new_code, op0, op1);
 
 #ifndef HAVE_cc0
       /* If the mode changed, we have to change SET_DEST, the mode in the
@@ -5152,25 +5113,28 @@ simplify_set (rtx x)
       SUBST (SET_SRC (x), src);
     }
 
-#ifdef WORD_REGISTER_OPERATIONS
   /* If we have (set x (subreg:m1 (op:m2 ...) 0)) with OP being some operation,
      and X being a REG or (subreg (reg)), we may be able to convert this to
      (set (subreg:m2 x) (op)).
 
-     On a machine where WORD_REGISTER_OPERATIONS is defined, this
-     transformation is safe as long as M1 and M2 have the same number
-     of words.
+     We can always do this if M1 is narrower than M2 because that means that
+     we only care about the low bits of the result.
 
-     However, on a machine without WORD_REGISTER_OPERATIONS defined,
-     we cannot apply this transformation because it would create a
-     paradoxical subreg in SET_DEST.  */
+     However, on machines without WORD_REGISTER_OPERATIONS defined, we cannot
+     perform a narrower operation than requested since the high-order bits will
+     be undefined.  On machine where it is defined, this transformation is safe
+     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)))
               + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))
+#ifndef WORD_REGISTER_OPERATIONS
+      && (GET_MODE_SIZE (GET_MODE (src))
+        < GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))
+#endif
 #ifdef CANNOT_CHANGE_MODE_CLASS
       && ! (GET_CODE (dest) == REG && REGNO (dest) < FIRST_PSEUDO_REGISTER
            && REG_CANNOT_CHANGE_MODE_P (REGNO (dest),
@@ -5182,13 +5146,12 @@ simplify_set (rtx x)
              && GET_CODE (SUBREG_REG (dest)) == REG)))
     {
       SUBST (SET_DEST (x),
-            gen_lowpart_for_combine (GET_MODE (SUBREG_REG (src)),
+            gen_lowpart (GET_MODE (SUBREG_REG (src)),
                                      dest));
       SUBST (SET_SRC (x), SUBREG_REG (src));
 
       src = SET_SRC (x), dest = SET_DEST (x);
     }
-#endif
 
 #ifdef HAVE_cc0
   /* If we have (set (cc0) (subreg ...)), we try to remove the subreg
@@ -5227,8 +5190,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);
     }
@@ -5301,10 +5264,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);
@@ -5354,11 +5317,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))
@@ -5367,9 +5332,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.  */
@@ -5564,7 +5528,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;
@@ -5586,7 +5550,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;
@@ -5750,7 +5714,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
@@ -5761,7 +5725,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
@@ -5883,7 +5847,7 @@ expand_field_assignment (rtx x)
                        + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))
        {
          x = gen_rtx_SET (VOIDmode, SUBREG_REG (SET_DEST (x)),
-                          gen_lowpart_for_combine
+                          gen_lowpart
                           (GET_MODE (SUBREG_REG (SET_DEST (x))),
                            SET_SRC (x)));
          continue;
@@ -5911,7 +5875,7 @@ expand_field_assignment (rtx x)
            break;
 
          compute_mode = imode;
-         inner = gen_lowpart_for_combine (imode, inner);
+         inner = gen_lowpart (imode, inner);
        }
 
       /* Compute a mask of LEN bits, if we can do this on the host machine.  */
@@ -5935,7 +5899,7 @@ expand_field_assignment (rtx x)
                                 inner),
                     gen_binary (ASHIFT, compute_mode,
                                 gen_binary (AND, compute_mode,
-                                            gen_lowpart_for_combine
+                                            gen_lowpart
                                             (compute_mode, SET_SRC (x)),
                                             mask),
                                 pos)));
@@ -6083,10 +6047,11 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
        {
          if (tmode != inner_mode)
            {
-             if (in_dest)
+             /* We can't call gen_lowpart in a DEST since we
+                always want a SUBREG (see below) and it would sometimes
+                return a new hard register.  */
+             if (pos || in_dest)
                {
-                 /* We can't call gen_lowpart_for_combine here since we always want
-                    a SUBREG and it would sometimes return a new hard register.  */
                  HOST_WIDE_INT final_word = pos / BITS_PER_WORD;
 
                  if (WORDS_BIG_ENDIAN
@@ -6109,7 +6074,7 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
                  new = gen_rtx_SUBREG (tmode, inner, final_word);
                }
              else
-               new = gen_lowpart_for_combine (tmode, inner);
+               new = gen_lowpart (tmode, inner);
            }
          else
            new = inner;
@@ -6339,7 +6304,7 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
     }
   else if (pos_rtx != 0
           && GET_MODE_SIZE (pos_mode) < GET_MODE_SIZE (GET_MODE (pos_rtx)))
-    pos_rtx = gen_lowpart_for_combine (pos_mode, pos_rtx);
+    pos_rtx = gen_lowpart (pos_mode, pos_rtx);
 
   /* Make POS_RTX unless we already have it and it is correct.  If we don't
      have a POS_RTX but we do have an ORIG_POS_RTX, the latter must
@@ -6354,7 +6319,7 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
   new = gen_rtx_fmt_eee (unsignedp ? ZERO_EXTRACT : SIGN_EXTRACT,
                         extraction_mode, inner, GEN_INT (len), pos_rtx);
   if (! in_dest)
-    new = gen_lowpart_for_combine (mode, new);
+    new = gen_lowpart (mode, new);
 
   return new;
 }
@@ -6441,7 +6406,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);
 
@@ -6607,9 +6572,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)
@@ -6657,7 +6622,7 @@ make_compound_operation (rtx x, enum rtx_code in_code)
              tem = gen_rtx_fmt_e (GET_CODE (tem), mode, XEXP (tem, 0));
            }
          else
-           tem = gen_lowpart_for_combine (mode, XEXP (tem, 0));
+           tem = gen_lowpart (mode, XEXP (tem, 0));
          return tem;
        }
       break;
@@ -6668,7 +6633,7 @@ make_compound_operation (rtx x, enum rtx_code in_code)
 
   if (new)
     {
-      x = gen_lowpart_for_combine (mode, new);
+      x = gen_lowpart (mode, new);
       code = GET_CODE (x);
     }
 
@@ -6696,17 +6661,15 @@ get_pos_from_mask (unsigned HOST_WIDE_INT m, unsigned HOST_WIDE_INT *plen)
 {
   /* Get the bit number of the first 1 bit from the right, -1 if none.  */
   int pos = exact_log2 (m & -m);
-  int len;
-
-  if (pos < 0)
-    return -1;
+  int len = 0;
 
-  /* Now shift off the low-order zero bits and see if we have a power of
-     two minus 1.  */
-  len = exact_log2 ((m >> pos) + 1);
+  if (pos >= 0)
+    /* Now shift off the low-order zero bits and see if we have a
+       power of two minus 1.  */
+    len = exact_log2 ((m >> pos) + 1);
 
   if (len <= 0)
-    return -1;
+    pos = -1;
 
   *plen = len;
   return pos;
@@ -6743,7 +6706,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
      expression is VOIDmode.
 
      Also do nothing if X is a CLOBBER; this can happen if X was
-     the return value from a call to gen_lowpart_for_combine.  */
+     the return value from a call to gen_lowpart.  */
   if (code == CALL || code == ASM_OPERANDS || code == CLOBBER)
     return x;
 
@@ -6797,7 +6760,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
      get X in the proper mode.  */
   if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode)
       && (GET_MODE_MASK (GET_MODE (x)) & ~mask) == 0)
-    return gen_lowpart_for_combine (mode, x);
+    return gen_lowpart (mode, x);
 
   /* If we aren't changing the mode, X is not a SUBREG, and all zero bits in
      MASK are already known to be zero in X, we need not do anything.  */
@@ -6881,7 +6844,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)
@@ -6990,12 +6953,12 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       /* For most binary operations, just propagate into the operation and
         change the mode if we have an operation of that mode.  */
 
-      op0 = gen_lowpart_for_combine (op_mode,
-                                    force_to_mode (XEXP (x, 0), mode, mask,
-                                                   reg, next_select));
-      op1 = gen_lowpart_for_combine (op_mode,
-                                    force_to_mode (XEXP (x, 1), mode, mask,
-                                                   reg, next_select));
+      op0 = gen_lowpart (op_mode,
+                        force_to_mode (XEXP (x, 0), mode, mask,
+                                       reg, next_select));
+      op1 = gen_lowpart (op_mode,
+                        force_to_mode (XEXP (x, 1), mode, mask,
+                                       reg, next_select));
 
       if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
        x = gen_binary (code, op_mode, op0, op1);
@@ -7027,9 +6990,9 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       else
        mask = fuller_mask;
 
-      op0 = gen_lowpart_for_combine (op_mode,
-                                    force_to_mode (XEXP (x, 0), op_mode,
-                                                   mask, reg, next_select));
+      op0 = gen_lowpart (op_mode,
+                        force_to_mode (XEXP (x, 0), op_mode,
+                                       mask, reg, next_select));
 
       if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
        x = gen_binary (code, op_mode, op0, XEXP (x, 1));
@@ -7225,9 +7188,9 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       mask = fuller_mask;
 
     unop:
-      op0 = gen_lowpart_for_combine (op_mode,
-                                    force_to_mode (XEXP (x, 0), mode, mask,
-                                                   reg, next_select));
+      op0 = gen_lowpart (op_mode,
+                        force_to_mode (XEXP (x, 0), mode, mask,
+                                       reg, next_select));
       if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
        x = simplify_gen_unary (code, op_mode, op0, op_mode);
       break;
@@ -7249,11 +7212,11 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
         written in a narrower mode.  We play it safe and do not do so.  */
 
       SUBST (XEXP (x, 1),
-            gen_lowpart_for_combine (GET_MODE (x),
+            gen_lowpart (GET_MODE (x),
                                      force_to_mode (XEXP (x, 1), mode,
                                                     mask, reg, next_select)));
       SUBST (XEXP (x, 2),
-            gen_lowpart_for_combine (GET_MODE (x),
+            gen_lowpart (GET_MODE (x),
                                      force_to_mode (XEXP (x, 2), mode,
                                                     mask, reg, next_select)));
       break;
@@ -7263,7 +7226,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
     }
 
   /* Ensure we return a value of the proper mode.  */
-  return gen_lowpart_for_combine (mode, x);
+  return gen_lowpart (mode, x);
 }
 \f
 /* Return nonzero if X is an expression that has one of two values depending on
@@ -7292,7 +7255,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)));
@@ -7309,8 +7272,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);
@@ -7346,8 +7308,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)))
@@ -7377,8 +7339,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)))
@@ -7417,12 +7379,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
@@ -7512,14 +7478,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;
@@ -7637,13 +7603,13 @@ rtx_equal_for_field_assignment_p (rtx x, rtx y)
   if (GET_CODE (x) == MEM && GET_CODE (y) == SUBREG
       && GET_CODE (SUBREG_REG (y)) == MEM
       && rtx_equal_p (SUBREG_REG (y),
-                     gen_lowpart_for_combine (GET_MODE (SUBREG_REG (y)), x)))
+                     gen_lowpart (GET_MODE (SUBREG_REG (y)), x)))
     return 1;
 
   if (GET_CODE (y) == MEM && GET_CODE (x) == SUBREG
       && GET_CODE (SUBREG_REG (x)) == MEM
       && rtx_equal_p (SUBREG_REG (x),
-                     gen_lowpart_for_combine (GET_MODE (SUBREG_REG (x)), y)))
+                     gen_lowpart (GET_MODE (SUBREG_REG (x)), y)))
     return 1;
 
   /* We used to see if get_last_value of X and Y were the same but that's
@@ -7811,8 +7777,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);
@@ -7866,7 +7831,7 @@ apply_distributive_law (rtx x)
 
       tem = gen_binary (code, GET_MODE (SUBREG_REG (lhs)),
                        SUBREG_REG (lhs), SUBREG_REG (rhs));
-      return gen_lowpart_for_combine (GET_MODE (x), tem);
+      return gen_lowpart (GET_MODE (x), tem);
 
     default:
       return x;
@@ -7874,15 +7839,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)))
@@ -7969,7 +7934,7 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
 
   if (GET_CODE (varop) == IOR || GET_CODE (varop) == XOR)
     return
-      gen_lowpart_for_combine
+      gen_lowpart
        (mode,
         apply_distributive_law
         (gen_binary (GET_CODE (varop), GET_MODE (varop),
@@ -8002,7 +7967,7 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
       && SUBREG_REG (XEXP (x, 0)) == varop)
     varop = XEXP (x, 0);
   else
-    varop = gen_lowpart_for_combine (mode, varop);
+    varop = gen_lowpart (mode, varop);
 
   /* If we can't make the SUBREG, try to return what we were given.  */
   if (GET_CODE (varop) == CLOBBER)
@@ -8051,8 +8016,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);
@@ -8063,14 +8027,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));
@@ -8180,17 +8142,17 @@ nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x,
         value.  Otherwise, use the previously-computed global nonzero bits
         for this register.  */
 
-      if (reg_last_set_value[REGNO (x)] != 0
-         && (reg_last_set_mode[REGNO (x)] == mode
-             || (GET_MODE_CLASS (reg_last_set_mode[REGNO (x)]) == MODE_INT
+      if (reg_stat[REGNO (x)].last_set_value != 0
+         && (reg_stat[REGNO (x)].last_set_mode == mode
+             || (GET_MODE_CLASS (reg_stat[REGNO (x)].last_set_mode) == MODE_INT
                  && GET_MODE_CLASS (mode) == MODE_INT))
-         && (reg_last_set_label[REGNO (x)] == label_tick
+         && (reg_stat[REGNO (x)].last_set_label == label_tick
              || (REGNO (x) >= FIRST_PSEUDO_REGISTER
                  && REG_N_SETS (REGNO (x)) == 1
                  && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start,
                                        REGNO (x))))
-         && INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid)
-       return reg_last_set_nonzero_bits[REGNO (x)] & nonzero;
+         && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid)
+       return reg_stat[REGNO (x)].last_set_nonzero_bits & nonzero;
 
       tem = get_last_value (x);
 
@@ -8199,8 +8161,8 @@ nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x,
 #ifdef SHORT_IMMEDIATES_SIGN_EXTEND
          /* If X is narrower than MODE and TEM is a non-negative
             constant that would appear negative in the mode of X,
-            sign-extend it for use in reg_nonzero_bits because some
-            machines (maybe most) will actually do the sign-extension
+            sign-extend it for use in reg_stat[].nonzero_bits because
+            some machines (maybe most) will actually do the sign-extension
             and this is the conservative approach.
 
             ??? For 2.5, try to tighten up the MD files in this regard
@@ -8218,9 +8180,9 @@ nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x,
 #endif
          return nonzero_bits_with_known (tem, mode) & nonzero;
        }
-      else if (nonzero_sign_valid && reg_nonzero_bits[REGNO (x)])
+      else if (nonzero_sign_valid && reg_stat[REGNO (x)].nonzero_bits)
        {
-         unsigned HOST_WIDE_INT mask = reg_nonzero_bits[REGNO (x)];
+         unsigned HOST_WIDE_INT mask = reg_stat[REGNO (x)].nonzero_bits;
 
          if (GET_MODE_BITSIZE (GET_MODE (x)) < mode_width)
            /* We don't know anything about the upper bits.  */
@@ -8580,8 +8542,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);
@@ -8593,15 +8554,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,
@@ -8679,23 +8638,23 @@ num_sign_bit_copies1 (rtx x, enum machine_mode mode, rtx known_x,
        return GET_MODE_BITSIZE (Pmode) - GET_MODE_BITSIZE (ptr_mode) + 1;
 #endif
 
-      if (reg_last_set_value[REGNO (x)] != 0
-         && reg_last_set_mode[REGNO (x)] == mode
-         && (reg_last_set_label[REGNO (x)] == label_tick
+      if (reg_stat[REGNO (x)].last_set_value != 0
+         && reg_stat[REGNO (x)].last_set_mode == mode
+         && (reg_stat[REGNO (x)].last_set_label == label_tick
              || (REGNO (x) >= FIRST_PSEUDO_REGISTER
                  && REG_N_SETS (REGNO (x)) == 1
                  && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start,
                                        REGNO (x))))
-         && INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid)
-       return reg_last_set_sign_bit_copies[REGNO (x)];
+         && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid)
+       return reg_stat[REGNO (x)].last_set_sign_bit_copies;
 
       tem = get_last_value (x);
       if (tem != 0)
        return num_sign_bit_copies_with_known (tem, mode);
 
-      if (nonzero_sign_valid && reg_sign_bit_copies[REGNO (x)] != 0
+      if (nonzero_sign_valid && reg_stat[REGNO (x)].sign_bit_copies != 0
          && GET_MODE_BITSIZE (GET_MODE (x)) == bitwidth)
-       return reg_sign_bit_copies[REGNO (x)];
+       return reg_stat[REGNO (x)].sign_bit_copies;
       break;
 
     case MEM:
@@ -9152,10 +9111,8 @@ simplify_shift_const (rtx x, enum rtx_code code,
   /* Make sure and truncate the "natural" shift on the way in.  We don't
      want to do this inside the loop as it makes it more difficult to
      combine shifts.  */
-#ifdef SHIFT_COUNT_TRUNCATED
   if (SHIFT_COUNT_TRUNCATED)
     orig_count &= GET_MODE_BITSIZE (mode) - 1;
-#endif
 
   /* If we were given an invalid count, don't do anything except exactly
      what was requested.  */
@@ -9597,6 +9554,11 @@ simplify_shift_const (rtx x, enum rtx_code code,
             (and (shift)) insns.  */
 
          if (GET_CODE (XEXP (varop, 1)) == CONST_INT
+             /* We can't do this if we have (ashiftrt (xor))  and the
+                constant has its sign bit set in shift_mode.  */
+             && !(code == ASHIFTRT && GET_CODE (varop) == XOR
+                  && 0 > trunc_int_for_mode (INTVAL (XEXP (varop, 1)),
+                                             shift_mode))
              && (new = simplify_binary_operation (code, result_mode,
                                                   XEXP (varop, 1),
                                                   GEN_INT (count))) != 0
@@ -9610,18 +9572,22 @@ simplify_shift_const (rtx x, enum rtx_code code,
 
          /* If we can't do that, try to simplify the shift in each arm of the
             logical expression, make a new logical expression, and apply
-            the inverse distributive law.  */
-         {
-           rtx lhs = simplify_shift_const (NULL_RTX, code, shift_mode,
-                                           XEXP (varop, 0), count);
-           rtx rhs = simplify_shift_const (NULL_RTX, code, shift_mode,
-                                           XEXP (varop, 1), count);
+            the inverse distributive law.  This also can't be done
+            for some (ashiftrt (xor)).  */
+         if (code != ASHIFTRT || GET_CODE (varop)!= XOR
+             || 0 <= trunc_int_for_mode (INTVAL (XEXP (varop, 1)),
+                                         shift_mode))
+           {
+             rtx lhs = simplify_shift_const (NULL_RTX, code, shift_mode,
+                                             XEXP (varop, 0), count);
+             rtx rhs = simplify_shift_const (NULL_RTX, code, shift_mode,
+                                             XEXP (varop, 1), count);
 
-           varop = gen_binary (GET_CODE (varop), shift_mode, lhs, rhs);
-           varop = apply_distributive_law (varop);
+             varop = gen_binary (GET_CODE (varop), shift_mode, lhs, rhs);
+             varop = apply_distributive_law (varop);
 
-           count = 0;
-         }
+             count = 0;
+           }
          break;
 
        case EQ:
@@ -9809,7 +9775,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);
@@ -9821,7 +9787,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
       && SUBREG_REG (XEXP (x, 0)) == varop)
     varop = XEXP (x, 0);
   else if (GET_MODE (varop) != shift_mode)
-    varop = gen_lowpart_for_combine (shift_mode, varop);
+    varop = gen_lowpart (shift_mode, varop);
 
   /* If we can't make the SUBREG, try to return what we were given.  */
   if (GET_CODE (varop) == CLOBBER)
@@ -9850,7 +9816,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
                                GET_MODE_MASK (result_mode) >> orig_count);
 
   /* Do the remainder of the processing in RESULT_MODE.  */
-  x = gen_lowpart_for_combine (result_mode, x);
+  x = gen_lowpart (result_mode, x);
 
   /* If COMPLEMENT_P is set, we have to complement X before doing the outer
      operation.  */
@@ -9868,7 +9834,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));
@@ -9898,7 +9864,7 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
   int num_clobbers_to_add = 0;
   int i;
   rtx notes = 0;
-  rtx dummy_insn;
+  rtx old_notes, old_pat;
 
   /* If PAT is a PARALLEL, check to see if it contains the CLOBBER
      we use to indicate that something didn't match.  If we find such a
@@ -9909,13 +9875,12 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
          && XEXP (XVECEXP (pat, 0, i), 0) == const0_rtx)
        return -1;
 
-  /* *pnewpat does not have to be actual PATTERN (insn), so make a dummy
-     instruction for pattern recognition.  */
-  dummy_insn = shallow_copy_rtx (insn);
-  PATTERN (dummy_insn) = pat;
-  REG_NOTES (dummy_insn) = 0;
+  old_pat = PATTERN (insn);
+  old_notes = REG_NOTES (insn);
+  PATTERN (insn) = pat;
+  REG_NOTES (insn) = 0;
 
-  insn_code_number = recog (pat, dummy_insn, &num_clobbers_to_add);
+  insn_code_number = recog (pat, insn, &num_clobbers_to_add);
 
   /* If it isn't, there is the possibility that we previously had an insn
      that clobbered some register as a side effect, but the combined
@@ -9940,9 +9905,11 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
       if (pos == 1)
        pat = XVECEXP (pat, 0, 0);
 
-      PATTERN (dummy_insn) = pat;
-      insn_code_number = recog (pat, dummy_insn, &num_clobbers_to_add);
+      PATTERN (insn) = pat;
+      insn_code_number = recog (pat, insn, &num_clobbers_to_add);
     }
+  PATTERN (insn) = old_pat;
+  REG_NOTES (insn) = old_notes;
 
   /* Recognize all noop sets, these will be killed by followup pass.  */
   if (insn_code_number < 0 && GET_CODE (pat) == SET && set_noop_p (pat))
@@ -9984,17 +9951,16 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
   return insn_code_number;
 }
 \f
-/* Like gen_lowpart but for use by combine.  In combine it is not possible
-   to create any new pseudoregs.  However, it is safe to create
-   invalid memory addresses, because combine will try to recognize
-   them and all they will do is make the combine attempt fail.
+/* Like gen_lowpart_general but for use by combine.  In combine it
+   is not possible to create any new pseudoregs.  However, it is
+   safe to create invalid memory addresses, because combine will
+   try to recognize them and all they will do is make the combine
+   attempt fail.
 
    If for some reason this cannot do its job, an rtx
    (clobber (const_int 0)) is returned.
    An insn containing that will not be recognized.  */
 
-#undef gen_lowpart
-
 static rtx
 gen_lowpart_for_combine (enum machine_mode mode, rtx x)
 {
@@ -10055,7 +10021,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);
@@ -10077,7 +10043,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
@@ -10118,11 +10084,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);
 
@@ -10137,7 +10104,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);
@@ -10146,7 +10113,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);
 
@@ -10292,8 +10259,8 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
                 tmode != GET_MODE (op0); tmode = GET_MODE_WIDER_MODE (tmode))
              if ((unsigned HOST_WIDE_INT) c0 == GET_MODE_MASK (tmode))
                {
-                 op0 = gen_lowpart_for_combine (tmode, inner_op0);
-                 op1 = gen_lowpart_for_combine (tmode, inner_op1);
+                 op0 = gen_lowpart (tmode, inner_op0);
+                 op1 = gen_lowpart (tmode, inner_op1);
                  code = unsigned_condition (code);
                  changed = 1;
                  break;
@@ -10346,8 +10313,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
@@ -10551,8 +10517,10 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
             a constant that has only a single bit set and are comparing it
             with zero, we can convert this into an equality comparison
             between the position and the location of the single bit.  */
-
-         if (GET_CODE (XEXP (op0, 0)) == CONST_INT
+         /* Except we can't if SHIFT_COUNT_TRUNCATED is set, since we might
+            have already reduced the shift count modulo the word size.  */
+         if (!SHIFT_COUNT_TRUNCATED
+             && GET_CODE (XEXP (op0, 0)) == CONST_INT
              && XEXP (op0, 1) == const1_rtx
              && equality_comparison_p && const_op == 0
              && (i = exact_log2 (INTVAL (XEXP (op0, 0)))) >= 0)
@@ -10920,9 +10888,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;
@@ -10956,7 +10924,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              && const_op >> i == 0
              && (tmode = mode_for_size (i, MODE_INT, 1)) != BLKmode)
            {
-             op0 = gen_lowpart_for_combine (tmode, XEXP (op0, 0));
+             op0 = gen_lowpart (tmode, XEXP (op0, 0));
              continue;
            }
 
@@ -10996,7 +10964,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
                  op0 = gen_binary (AND, tmode,
                                    SUBREG_REG (XEXP (op0, 0)),
                                    gen_int_mode (c1, tmode));
-                 op0 = gen_lowpart_for_combine (mode, op0);
+                 op0 = gen_lowpart (mode, op0);
                  continue;
                }
            }
@@ -11118,7 +11086,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
                   + (GET_MODE_MASK (tmode) >> 1) + 1)
                  <= GET_MODE_MASK (tmode)))
            {
-             op0 = gen_lowpart_for_combine (tmode, XEXP (XEXP (op0, 0), 0));
+             op0 = gen_lowpart (tmode, XEXP (XEXP (op0, 0), 0));
              continue;
            }
 
@@ -11143,7 +11111,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
                                          XEXP (op0, 1));
 
              op0 = gen_binary (PLUS, tmode,
-                               gen_lowpart_for_combine (tmode, inner),
+                               gen_lowpart (tmode, inner),
                                new_const);
              continue;
            }
@@ -11237,7 +11205,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
           if (GET_CODE (SUBREG_REG (op0)) == REG)
            {
              op0 = SUBREG_REG (op0);
-             op1 = gen_lowpart_for_combine (GET_MODE (op0), op1);
+             op1 = gen_lowpart (GET_MODE (op0), op1);
            }
        }
       else if ((GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
@@ -11246,7 +11214,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
                                 GET_MODE (SUBREG_REG (op0)))
                   & ~GET_MODE_MASK (GET_MODE (op0))) == 0)
        {
-         tem = gen_lowpart_for_combine (GET_MODE (SUBREG_REG (op0)), op1);
+         tem = gen_lowpart (GET_MODE (SUBREG_REG (op0)), op1);
 
          if ((nonzero_bits (tem, GET_MODE (SUBREG_REG (op0)))
               & ~GET_MODE_MASK (GET_MODE (op0))) == 0)
@@ -11298,15 +11266,15 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              if (GET_CODE (op0) == AND
                  && !have_insn_for (AND, mode))
                op0 = gen_binary (AND, tmode,
-                                 gen_lowpart_for_combine (tmode,
-                                                          XEXP (op0, 0)),
-                                 gen_lowpart_for_combine (tmode,
-                                                          XEXP (op0, 1)));
+                                 gen_lowpart (tmode,
+                                              XEXP (op0, 0)),
+                                 gen_lowpart (tmode,
+                                              XEXP (op0, 1)));
 
-             op0 = gen_lowpart_for_combine (tmode, op0);
+             op0 = gen_lowpart (tmode, op0);
              if (zero_extended && GET_CODE (op1) == CONST_INT)
                op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (mode));
-             op1 = gen_lowpart_for_combine (tmode, op1);
+             op1 = gen_lowpart (tmode, op1);
              break;
            }
 
@@ -11317,7 +11285,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
            {
              op0 = gen_binary (AND, tmode,
-                               gen_lowpart_for_combine (tmode, op0),
+                               gen_lowpart (tmode, op0),
                                GEN_INT ((HOST_WIDE_INT) 1
                                         << (GET_MODE_BITSIZE (mode) - 1)));
              code = (code == LT) ? NE : EQ;
@@ -11370,7 +11338,7 @@ reversed_comparison (rtx exp, enum machine_mode mode, rtx op0, rtx op1)
 }
 \f
 /* Utility function for following routine.  Called when X is part of a value
-   being stored into reg_last_set_value.  Sets reg_last_set_table_tick
+   being stored into last_set_value.  Sets last_set_table_tick
    for each register mentioned.  Similar to mention_regs in cse.c  */
 
 static void
@@ -11385,11 +11353,11 @@ 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++)
-       reg_last_set_table_tick[r] = label_tick;
+       reg_stat[r].last_set_table_tick = label_tick;
 
       return;
     }
@@ -11402,9 +11370,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.  */
@@ -11419,15 +11385,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));
@@ -11441,8 +11405,9 @@ update_table_tick (rtx x)
 
 /* Record that REG is set to VALUE in insn INSN.  If VALUE is zero, we
    are saying that the register is clobbered and we no longer know its
-   value.  If INSN is zero, don't update reg_last_set; this is only permitted
-   with VALUE also zero and is used to invalidate the register.  */
+   value.  If INSN is zero, don't update reg_stat[].last_set; this is
+   only permitted with VALUE also zero and is used to invalidate the
+   register.  */
 
 static void
 record_value_for_reg (rtx reg, rtx insn, rtx value)
@@ -11450,7 +11415,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
@@ -11470,8 +11435,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);
@@ -11487,13 +11451,13 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
   for (i = regno; i < endregno; i++)
     {
       if (insn)
-       reg_last_set[i] = insn;
+       reg_stat[i].last_set = insn;
 
-      reg_last_set_value[i] = 0;
-      reg_last_set_mode[i] = 0;
-      reg_last_set_nonzero_bits[i] = 0;
-      reg_last_set_sign_bit_copies[i] = 0;
-      reg_last_death[i] = 0;
+      reg_stat[i].last_set_value = 0;
+      reg_stat[i].last_set_mode = 0;
+      reg_stat[i].last_set_nonzero_bits = 0;
+      reg_stat[i].last_set_sign_bit_copies = 0;
+      reg_stat[i].last_death = 0;
     }
 
   /* Mark registers that are being referenced in this value.  */
@@ -11509,40 +11473,40 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
 
   for (i = regno; i < endregno; i++)
     {
-      reg_last_set_label[i] = label_tick;
-      if (value && reg_last_set_table_tick[i] == label_tick)
-       reg_last_set_invalid[i] = 1;
+      reg_stat[i].last_set_label = label_tick;
+      if (value && reg_stat[i].last_set_table_tick == label_tick)
+       reg_stat[i].last_set_invalid = 1;
       else
-       reg_last_set_invalid[i] = 0;
+       reg_stat[i].last_set_invalid = 0;
     }
 
   /* The value being assigned might refer to X (like in "x++;").  In that
      case, we must replace it with (clobber (const_int 0)) to prevent
      infinite loops.  */
   if (value && ! get_last_value_validate (&value, insn,
-                                         reg_last_set_label[regno], 0))
+                                         reg_stat[regno].last_set_label, 0))
     {
       value = copy_rtx (value);
       if (! get_last_value_validate (&value, insn,
-                                    reg_last_set_label[regno], 1))
+                                    reg_stat[regno].last_set_label, 1))
        value = 0;
     }
 
   /* For the main register being modified, update the value, the mode, the
      nonzero bits, and the number of sign bit copies.  */
 
-  reg_last_set_value[regno] = value;
+  reg_stat[regno].last_set_value = value;
 
   if (value)
     {
       enum machine_mode mode = GET_MODE (reg);
       subst_low_cuid = INSN_CUID (insn);
-      reg_last_set_mode[regno] = mode;
+      reg_stat[regno].last_set_mode = mode;
       if (GET_MODE_CLASS (mode) == MODE_INT
          && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
        mode = nonzero_bits_mode;
-      reg_last_set_nonzero_bits[regno] = nonzero_bits (value, mode);
-      reg_last_set_sign_bit_copies[regno]
+      reg_stat[regno].last_set_nonzero_bits = nonzero_bits (value, mode);
+      reg_stat[regno].last_set_sign_bit_copies
        = num_sign_bit_copies (value, GET_MODE (reg));
     }
 }
@@ -11572,7 +11536,7 @@ record_dead_and_set_regs_1 (rtx dest, rtx setter, void *data)
               && GET_MODE_BITSIZE (GET_MODE (dest)) <= BITS_PER_WORD
               && subreg_lowpart_p (SET_DEST (setter)))
        record_value_for_reg (dest, record_dead_insn,
-                             gen_lowpart_for_combine (GET_MODE (dest),
+                             gen_lowpart (GET_MODE (dest),
                                                       SET_SRC (setter)));
       else
        record_value_for_reg (dest, record_dead_insn, NULL_RTX);
@@ -11587,11 +11551,11 @@ record_dead_and_set_regs_1 (rtx dest, rtx setter, void *data)
    for the things done by INSN.  This is the last thing done in processing
    INSN in the combiner loop.
 
-   We update reg_last_set, reg_last_set_value, reg_last_set_mode,
-   reg_last_set_nonzero_bits, reg_last_set_sign_bit_copies, reg_last_death,
-   and also the similar information mem_last_set (which insn most recently
-   modified memory) and last_call_cuid (which insn was the most recent
-   subroutine call).  */
+   We update reg_stat[], in particular fields last_set, last_set_value,
+   last_set_mode, last_set_nonzero_bits, last_set_sign_bit_copies,
+   last_death, and also the similar information mem_last_set (which insn
+   most recently modified memory) and last_call_cuid (which insn was the
+   most recent subroutine call).  */
 
 static void
 record_dead_and_set_regs (rtx insn)
@@ -11607,11 +11571,11 @@ 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++)
-           reg_last_death[i] = insn;
+           reg_stat[i].last_death = insn;
        }
       else if (REG_NOTE_KIND (link) == REG_INC)
        record_value_for_reg (XEXP (link, 0), insn, NULL_RTX);
@@ -11622,11 +11586,11 @@ record_dead_and_set_regs (rtx insn)
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
          {
-           reg_last_set_value[i] = 0;
-           reg_last_set_mode[i] = 0;
-           reg_last_set_nonzero_bits[i] = 0;
-           reg_last_set_sign_bit_copies[i] = 0;
-           reg_last_death[i] = 0;
+           reg_stat[i].last_set_value = 0;
+           reg_stat[i].last_set_mode = 0;
+           reg_stat[i].last_set_nonzero_bits = 0;
+           reg_stat[i].last_set_sign_bit_copies = 0;
+           reg_stat[i].last_death = 0;
          }
 
       last_call_cuid = mem_last_set = INSN_CUID (insn);
@@ -11674,10 +11638,10 @@ record_promoted_value (rtx insn, rtx subreg)
          continue;
        }
 
-      if (reg_last_set[regno] == insn)
+      if (reg_stat[regno].last_set == insn)
        {
          if (SUBREG_PROMOTED_UNSIGNED_P (subreg) > 0)
-           reg_last_set_nonzero_bits[regno] &= GET_MODE_MASK (mode);
+           reg_stat[regno].last_set_nonzero_bits &= GET_MODE_MASK (mode);
        }
 
       if (GET_CODE (SET_SRC (set)) == REG)
@@ -11743,18 +11707,18 @@ 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++)
-       if (reg_last_set_invalid[j]
+       if (reg_stat[j].last_set_invalid
            /* If this is a pseudo-register that was only set once and not
               live at the beginning of the function, it is always valid.  */
            || (! (regno >= FIRST_PSEUDO_REGISTER
                   && REG_N_SETS (regno) == 1
                   && (! REGNO_REG_SET_P
                       (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, regno)))
-               && reg_last_set_label[j] > tick))
+               && reg_stat[j].last_set_label > tick))
          {
            if (replace)
              *loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
@@ -11781,9 +11745,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.  */
@@ -11797,15 +11759,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,
@@ -11844,13 +11804,13 @@ get_last_value (rtx x)
       && (GET_MODE_SIZE (GET_MODE (x))
          <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
       && (value = get_last_value (SUBREG_REG (x))) != 0)
-    return gen_lowpart_for_combine (GET_MODE (x), value);
+    return gen_lowpart (GET_MODE (x), value);
 
   if (GET_CODE (x) != REG)
     return 0;
 
   regno = REGNO (x);
-  value = reg_last_set_value[regno];
+  value = reg_stat[regno].last_set_value;
 
   /* If we don't have a value, or if it isn't for this basic block and
      it's either a hard register, set more than once, or it's a live
@@ -11863,7 +11823,7 @@ get_last_value (rtx x)
      block.  */
 
   if (value == 0
-      || (reg_last_set_label[regno] != label_tick
+      || (reg_stat[regno].last_set_label != label_tick
          && (regno < FIRST_PSEUDO_REGISTER
              || REG_N_SETS (regno) != 1
              || (REGNO_REG_SET_P
@@ -11872,20 +11832,20 @@ get_last_value (rtx x)
 
   /* If the value was set in a later insn than the ones we are processing,
      we can't use it even if the register was only set once.  */
-  if (INSN_CUID (reg_last_set[regno]) >= subst_low_cuid)
+  if (INSN_CUID (reg_stat[regno].last_set) >= subst_low_cuid)
     return 0;
 
   /* If the value has all its registers valid, return it.  */
-  if (get_last_value_validate (&value, reg_last_set[regno],
-                              reg_last_set_label[regno], 0))
+  if (get_last_value_validate (&value, reg_stat[regno].last_set,
+                              reg_stat[regno].last_set_label, 0))
     return value;
 
   /* Otherwise, make a copy and replace any invalid register with
      (clobber (const_int 0)).  If that fails for some reason, return 0.  */
 
   value = copy_rtx (value);
-  if (get_last_value_validate (&value, reg_last_set[regno],
-                              reg_last_set_label[regno], 1))
+  if (get_last_value_validate (&value, reg_stat[regno].last_set,
+                              reg_stat[regno].last_set_label, 1))
     return value;
 
   return 0;
@@ -11905,7 +11865,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,
@@ -11914,8 +11874,8 @@ use_crosses_set_p (rtx x, int from_cuid)
        return 1;
 #endif
       for (; regno < endreg; regno++)
-       if (reg_last_set[regno]
-           && INSN_CUID (reg_last_set[regno]) > from_cuid)
+       if (reg_stat[regno].last_set
+           && INSN_CUID (reg_stat[regno].last_set) > from_cuid)
          return 1;
       return 0;
     }
@@ -11962,7 +11922,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;
@@ -11985,8 +11945,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;
@@ -12018,7 +11978,7 @@ reg_dead_at_p (rtx reg, rtx insn)
   else
     {
       FOR_EACH_BB (block)
-       if (insn == block->head)
+       if (insn == BB_HEAD (block))
          break;
 
       if (block == EXIT_BLOCK_PTR)
@@ -12087,7 +12047,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);
        }
@@ -12175,7 +12135,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
   if (code == REG)
     {
       unsigned int regno = REGNO (x);
-      rtx where_dead = reg_last_death[regno];
+      rtx where_dead = reg_stat[regno].last_death;
       rtx before_dead, after_dead;
 
       /* Don't move the register if it gets killed in between from and to.  */
@@ -12202,7 +12162,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
          rtx note = remove_death (regno, where_dead);
 
          /* It is possible for the call above to return 0.  This can occur
-            when reg_last_death points to I2 or I1 that we combined with.
+            when last_death points to I2 or I1 that we combined with.
             In that case make a new note.
 
             We must also check for the case where X is a hard register
@@ -12216,10 +12176,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++)
@@ -12240,15 +12200,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;
 
@@ -12361,8 +12321,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;
     }
@@ -12604,6 +12564,9 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                 libcall sequence, don't add the notes.  */
              else if (XEXP (note, 0) == from_insn)
                tem = place = 0;
+             /* Don't add the dangling REG_RETVAL note.  */
+             else if (! tem)
+               place = 0;
            }
          break;
 
@@ -12621,6 +12584,9 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                 libcall sequence, don't add the notes.  */
              else if (XEXP (note, 0) == from_insn)
                tem = place = 0;
+             /* Don't add the dangling REG_LIBCALL note.  */
+             else if (! tem)
+               place = 0;
            }
          break;
 
@@ -12657,7 +12623,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                {
                  if (! INSN_P (tem))
                    {
-                     if (tem == bb->head)
+                     if (tem == BB_HEAD (bb))
                        break;
                      continue;
                    }
@@ -12702,11 +12668,12 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                             This might delete other dead insns recursively.
                             First set the pattern to something that won't use
                             any register.  */
+                         rtx old_notes = REG_NOTES (tem);
 
                          PATTERN (tem) = pc_rtx;
+                         REG_NOTES (tem) = NULL;
 
-                         distribute_notes (REG_NOTES (tem), tem, tem,
-                                           NULL_RTX);
+                         distribute_notes (old_notes, tem, tem, NULL_RTX);
                          distribute_links (LOG_LINKS (tem));
 
                          PUT_CODE (tem, NOTE);
@@ -12718,10 +12685,11 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                          if (cc0_setter)
                            {
                              PATTERN (cc0_setter) = pc_rtx;
+                             old_notes = REG_NOTES (cc0_setter);
+                             REG_NOTES (cc0_setter) = NULL;
 
-                             distribute_notes (REG_NOTES (cc0_setter),
-                                               cc0_setter, cc0_setter,
-                                               NULL_RTX);
+                             distribute_notes (old_notes, cc0_setter,
+                                               cc0_setter, NULL_RTX);
                              distribute_links (LOG_LINKS (cc0_setter));
 
                              PUT_CODE (cc0_setter, NOTE);
@@ -12731,26 +12699,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;
@@ -12782,7 +12740,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                      break;
                    }
 
-                 if (tem == bb->head)
+                 if (tem == BB_HEAD (bb))
                    break;
                }
 
@@ -12817,14 +12775,14 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                  || reg_bitfield_target_p (XEXP (note, 0), PATTERN (place)))
                {
                  /* Unless the register previously died in PLACE, clear
-                    reg_last_death.  [I no longer understand why this is
+                    last_death.  [I no longer understand why this is
                     being done.] */
-                 if (reg_last_death[regno] != place)
-                   reg_last_death[regno] = 0;
+                 if (reg_stat[regno].last_death != place)
+                   reg_stat[regno].last_death = 0;
                  place = 0;
                }
              else
-               reg_last_death[regno] = place;
+               reg_stat[regno].last_death = place;
 
              /* If this is a death note for a hard reg that is occupying
                 multiple registers, ensure that we are still using all
@@ -12836,11 +12794,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;
 
@@ -12856,7 +12814,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;
@@ -12879,7 +12837,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                              {
                                if (! INSN_P (tem))
                                  {
-                                   if (tem == bb->head)
+                                   if (tem == BB_HEAD (bb))
                                      {
                                        SET_BIT (refresh_blocks,
                                                 this_basic_block->index);
@@ -12986,7 +12944,7 @@ distribute_links (rtx links)
 
       for (insn = NEXT_INSN (XEXP (link, 0));
           (insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR
-                    || this_basic_block->next_bb->head != insn));
+                    || BB_HEAD (this_basic_block->next_bb) != insn));
           insn = NEXT_INSN (insn))
        if (INSN_P (insn) && reg_overlap_mentioned_p (reg, PATTERN (insn)))
          {
@@ -13029,6 +12987,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