OSDN Git Service

* c-typeck.c (common_type): Correct comment.
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index bbbb16e..eb07dbb 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.
 
@@ -53,10 +53,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    flow.c aren't completely updated:
 
    - reg_live_length is not updated
-   - reg_n_refs is not adjusted in the rare case when a register is
-     no longer required in a computation
-   - there are extremely rare cases (see distribute_regnotes) when a
-     REG_DEAD note is lost
    - a LOG_LINKS entry that refers to an insn with multiple SETs may be
      removed because there is no way to know which register it was
      linking
@@ -79,6 +75,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "coretypes.h"
 #include "tm.h"
 #include "rtl.h"
+#include "tree.h"
 #include "tm_p.h"
 #include "flags.h"
 #include "regs.h"
@@ -92,10 +89,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "recog.h"
 #include "real.h"
 #include "toplev.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
+#include "target.h"
+#include "rtlhooks-def.h"
 
 /* Number of attempts to combine instructions in this function.  */
 
@@ -139,23 +134,107 @@ static int max_uid_cuid;
 #define UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD(val) \
   (((unsigned HOST_WIDE_INT) (val) << (BITS_PER_WORD - 1)) << 1)
 
-#define nonzero_bits(X, M) \
-  cached_nonzero_bits (X, M, NULL_RTX, VOIDmode, 0)
-
-#define num_sign_bit_copies(X, M) \
-  cached_num_sign_bit_copies (X, M, NULL_RTX, VOIDmode, 0)
-
 /* Maximum register number, which is the size of the tables below.  */
 
 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;
+
+  /* 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.  */
+
+  unsigned HOST_WIDE_INT       last_set_nonzero_bits;
+  char                         last_set_sign_bit_copies;
+  ENUM_BITFIELD(machine_mode)  last_set_mode : 8; 
+
+  /* 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.  */
 
-static rtx *reg_last_death;
+  unsigned char                        sign_bit_copies;
 
-/* Record last point of modification of (hard or pseudo) register n.  */
+  unsigned HOST_WIDE_INT       nonzero_bits;
+};
 
-static rtx *reg_last_set;
+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).  */
@@ -203,110 +282,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,86 +332,92 @@ static struct undobuf undobuf;
 
 static int n_occurrences;
 
-static void do_SUBST                   PARAMS ((rtx *, rtx));
-static void do_SUBST_INT               PARAMS ((int *, int));
-static void init_reg_last_arrays       PARAMS ((void));
-static void setup_incoming_promotions   PARAMS ((void));
-static void set_nonzero_bits_and_sign_copies  PARAMS ((rtx, rtx, void *));
-static int cant_combine_insn_p PARAMS ((rtx));
-static int can_combine_p       PARAMS ((rtx, rtx, rtx, rtx, rtx *, rtx *));
-static int sets_function_arg_p PARAMS ((rtx));
-static int combinable_i3pat    PARAMS ((rtx, rtx *, rtx, rtx, int, rtx *));
-static int contains_muldiv     PARAMS ((rtx));
-static rtx try_combine         PARAMS ((rtx, rtx, rtx, int *));
-static void undo_all           PARAMS ((void));
-static void undo_commit                PARAMS ((void));
-static rtx *find_split_point   PARAMS ((rtx *, rtx));
-static rtx subst               PARAMS ((rtx, rtx, rtx, int, int));
-static rtx combine_simplify_rtx        PARAMS ((rtx, enum machine_mode, int, int));
-static rtx simplify_if_then_else  PARAMS ((rtx));
-static rtx simplify_set                PARAMS ((rtx));
-static rtx simplify_logical    PARAMS ((rtx, int));
-static rtx expand_compound_operation  PARAMS ((rtx));
-static rtx expand_field_assignment  PARAMS ((rtx));
-static rtx make_extraction     PARAMS ((enum machine_mode, rtx, HOST_WIDE_INT,
-                                        rtx, unsigned HOST_WIDE_INT, int,
-                                        int, int));
-static rtx extract_left_shift  PARAMS ((rtx, int));
-static rtx make_compound_operation  PARAMS ((rtx, enum rtx_code));
-static int get_pos_from_mask   PARAMS ((unsigned HOST_WIDE_INT,
-                                        unsigned HOST_WIDE_INT *));
-static rtx force_to_mode       PARAMS ((rtx, enum machine_mode,
-                                        unsigned HOST_WIDE_INT, rtx, int));
-static rtx if_then_else_cond   PARAMS ((rtx, rtx *, rtx *));
-static rtx known_cond          PARAMS ((rtx, enum rtx_code, rtx, rtx));
-static int rtx_equal_for_field_assignment_p PARAMS ((rtx, rtx));
-static rtx make_field_assignment  PARAMS ((rtx));
-static rtx apply_distributive_law  PARAMS ((rtx));
-static rtx simplify_and_const_int  PARAMS ((rtx, enum machine_mode, rtx,
-                                           unsigned HOST_WIDE_INT));
-static unsigned HOST_WIDE_INT cached_nonzero_bits
-                               PARAMS ((rtx, enum machine_mode, rtx,
+static rtx reg_nonzero_bits_for_combine (rtx, enum machine_mode, rtx,
                                         enum machine_mode,
-                                        unsigned HOST_WIDE_INT));
-static unsigned HOST_WIDE_INT nonzero_bits1
-                               PARAMS ((rtx, enum machine_mode, rtx,
-                                        enum machine_mode,
-                                        unsigned HOST_WIDE_INT));
-static unsigned int cached_num_sign_bit_copies
-                               PARAMS ((rtx, enum machine_mode, rtx,
-                                        enum machine_mode, unsigned int));
-static unsigned int num_sign_bit_copies1
-                               PARAMS ((rtx, enum machine_mode, rtx,
-                                        enum machine_mode, unsigned int));
-static int merge_outer_ops     PARAMS ((enum rtx_code *, HOST_WIDE_INT *,
-                                        enum rtx_code, HOST_WIDE_INT,
-                                        enum machine_mode, int *));
-static rtx simplify_shift_const        PARAMS ((rtx, enum rtx_code, enum machine_mode,
-                                        rtx, int));
-static int recog_for_combine   PARAMS ((rtx *, rtx, rtx *));
-static rtx gen_lowpart_for_combine  PARAMS ((enum machine_mode, rtx));
-static rtx gen_binary          PARAMS ((enum rtx_code, enum machine_mode,
-                                        rtx, rtx));
-static enum rtx_code simplify_comparison  PARAMS ((enum rtx_code, rtx *, rtx *));
-static void update_table_tick  PARAMS ((rtx));
-static void record_value_for_reg  PARAMS ((rtx, rtx, rtx));
-static void check_promoted_subreg PARAMS ((rtx, rtx));
-static void record_dead_and_set_regs_1  PARAMS ((rtx, rtx, void *));
-static void record_dead_and_set_regs  PARAMS ((rtx));
-static int get_last_value_validate  PARAMS ((rtx *, rtx, int, int));
-static rtx get_last_value      PARAMS ((rtx));
-static int use_crosses_set_p   PARAMS ((rtx, int));
-static void reg_dead_at_p_1    PARAMS ((rtx, rtx, void *));
-static int reg_dead_at_p       PARAMS ((rtx, rtx));
-static void move_deaths                PARAMS ((rtx, rtx, int, rtx, rtx *));
-static int reg_bitfield_target_p  PARAMS ((rtx, rtx));
-static void distribute_notes   PARAMS ((rtx, rtx, rtx, rtx, rtx, rtx));
-static void distribute_links   PARAMS ((rtx));
-static void mark_used_regs_combine PARAMS ((rtx));
-static int insn_cuid           PARAMS ((rtx));
-static void record_promoted_value PARAMS ((rtx, rtx));
-static rtx reversed_comparison  PARAMS ((rtx, enum machine_mode, rtx, rtx));
-static enum rtx_code combine_reversed_comparison_code PARAMS ((rtx));
+                                        unsigned HOST_WIDE_INT,
+                                        unsigned HOST_WIDE_INT *);
+static rtx reg_num_sign_bit_copies_for_combine (rtx, enum machine_mode, rtx,
+                                               enum machine_mode,
+                                               unsigned int, unsigned int *);
+static void do_SUBST (rtx *, rtx);
+static void do_SUBST_INT (int *, int);
+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 combinable_i3pat (rtx, rtx *, rtx, rtx, int, rtx *);
+static int contains_muldiv (rtx);
+static rtx try_combine (rtx, rtx, rtx, int *);
+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);
+static rtx simplify_if_then_else (rtx);
+static rtx simplify_set (rtx);
+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,
+                           rtx, unsigned HOST_WIDE_INT, int, int, int);
+static rtx extract_left_shift (rtx, int);
+static rtx make_compound_operation (rtx, enum rtx_code);
+static int get_pos_from_mask (unsigned HOST_WIDE_INT,
+                             unsigned HOST_WIDE_INT *);
+static rtx force_to_mode (rtx, enum machine_mode,
+                         unsigned HOST_WIDE_INT, rtx, int);
+static rtx if_then_else_cond (rtx, rtx *, rtx *);
+static rtx known_cond (rtx, enum rtx_code, rtx, rtx);
+static int rtx_equal_for_field_assignment_p (rtx, rtx);
+static rtx make_field_assignment (rtx);
+static rtx apply_distributive_law (rtx);
+static rtx distribute_and_simplify_rtx (rtx);
+static rtx simplify_and_const_int (rtx, enum machine_mode, rtx,
+                                  unsigned HOST_WIDE_INT);
+static int merge_outer_ops (enum rtx_code *, HOST_WIDE_INT *, enum rtx_code,
+                           HOST_WIDE_INT, enum machine_mode, int *);
+static rtx simplify_shift_const        (rtx, enum rtx_code, enum machine_mode, rtx,
+                                int);
+static int recog_for_combine (rtx *, rtx, rtx *);
+static rtx gen_lowpart_for_combine (enum machine_mode, rtx);
+static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *);
+static void update_table_tick (rtx);
+static void record_value_for_reg (rtx, rtx, rtx);
+static void check_promoted_subreg (rtx, rtx);
+static void record_dead_and_set_regs_1 (rtx, rtx, void *);
+static void record_dead_and_set_regs (rtx);
+static int get_last_value_validate (rtx *, rtx, int, int);
+static rtx get_last_value (rtx);
+static int use_crosses_set_p (rtx, int);
+static void reg_dead_at_p_1 (rtx, rtx, void *);
+static int reg_dead_at_p (rtx, rtx);
+static void move_deaths (rtx, rtx, int, rtx, rtx *);
+static int reg_bitfield_target_p (rtx, rtx);
+static void distribute_notes (rtx, rtx, rtx, rtx);
+static void distribute_links (rtx);
+static void mark_used_regs_combine (rtx);
+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
+
+/* It is not safe to use ordinary gen_lowpart in combine.
+   See comments in gen_lowpart_for_combine.  */
+#undef RTL_HOOKS_GEN_LOWPART
+#define RTL_HOOKS_GEN_LOWPART              gen_lowpart_for_combine
+
+#undef RTL_HOOKS_REG_NONZERO_REG_BITS
+#define RTL_HOOKS_REG_NONZERO_REG_BITS     reg_nonzero_bits_for_combine
+
+#undef RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES
+#define RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES  reg_num_sign_bit_copies_for_combine
+
+static const struct rtl_hooks combine_rtl_hooks = RTL_HOOKS_INITIALIZER;
+
 \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
@@ -428,8 +426,7 @@ static enum rtx_code combine_reversed_comparison_code PARAMS ((rtx));
    the undo table.  */
 
 static void
-do_SUBST (into, newval)
-     rtx *into, newval;
+do_SUBST (rtx *into, rtx newval)
 {
   struct undo *buf;
   rtx oldval = *into;
@@ -467,7 +464,7 @@ do_SUBST (into, newval)
   if (undobuf.frees)
     buf = undobuf.frees, undobuf.frees = buf->next;
   else
-    buf = (struct undo *) xmalloc (sizeof (struct undo));
+    buf = xmalloc (sizeof (struct undo));
 
   buf->is_int = 0;
   buf->where.r = into;
@@ -484,8 +481,7 @@ do_SUBST (into, newval)
    not safe.  */
 
 static void
-do_SUBST_INT (into, newval)
-     int *into, newval;
+do_SUBST_INT (int *into, int newval)
 {
   struct undo *buf;
   int oldval = *into;
@@ -496,7 +492,7 @@ do_SUBST_INT (into, newval)
   if (undobuf.frees)
     buf = undobuf.frees, undobuf.frees = buf->next;
   else
-    buf = (struct undo *) xmalloc (sizeof (struct undo));
+    buf = xmalloc (sizeof (struct undo));
 
   buf->is_int = 1;
   buf->where.i = into;
@@ -514,9 +510,7 @@ do_SUBST_INT (into, newval)
    Return nonzero if the combiner has turned an indirect jump
    instruction into a direct jump.  */
 int
-combine_instructions (f, nregs)
-     rtx f;
-     unsigned int nregs;
+combine_instructions (rtx f, unsigned int nregs)
 {
   rtx insn, next;
 #ifdef HAVE_cc0
@@ -534,25 +528,9 @@ combine_instructions (f, nregs)
 
   combine_max_regno = nregs;
 
-  reg_nonzero_bits = ((unsigned HOST_WIDE_INT *)
-                     xcalloc (nregs, sizeof (unsigned HOST_WIDE_INT)));
-  reg_sign_bit_copies
-    = (unsigned char *) xcalloc (nregs, sizeof (unsigned char));
-
-  reg_last_death = (rtx *) xmalloc (nregs * sizeof (rtx));
-  reg_last_set = (rtx *) xmalloc (nregs * sizeof (rtx));
-  reg_last_set_value = (rtx *) xmalloc (nregs * sizeof (rtx));
-  reg_last_set_table_tick = (int *) xmalloc (nregs * sizeof (int));
-  reg_last_set_label = (int *) xmalloc (nregs * sizeof (int));
-  reg_last_set_invalid = (char *) xmalloc (nregs * sizeof (char));
-  reg_last_set_mode
-    = (enum machine_mode *) xmalloc (nregs * sizeof (enum machine_mode));
-  reg_last_set_nonzero_bits
-    = (unsigned HOST_WIDE_INT *) xmalloc (nregs * sizeof (HOST_WIDE_INT));
-  reg_last_set_sign_bit_copies
-    = (char *) xmalloc (nregs * sizeof (char));
-
-  init_reg_last_arrays ();
+  rtl_hooks = combine_rtl_hooks;
+
+  reg_stat = xcalloc (nregs, sizeof (struct reg_stat));
 
   init_recog_no_volatile ();
 
@@ -562,13 +540,13 @@ combine_instructions (f, nregs)
     if (INSN_UID (insn) > i)
       i = INSN_UID (insn);
 
-  uid_cuid = (int *) xmalloc ((i + 1) * sizeof (int));
+  uid_cuid = xmalloc ((i + 1) * sizeof (int));
   max_uid_cuid = i;
 
   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;
 
@@ -621,13 +599,13 @@ combine_instructions (f, 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;
@@ -738,6 +716,31 @@ combine_instructions (f, 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);
 
@@ -751,7 +754,7 @@ combine_instructions (f, nregs)
   EXECUTE_IF_SET_IN_SBITMAP (refresh_blocks, 0, i,
                             BASIC_BLOCK (i)->flags |= BB_DIRTY);
   new_direct_jump_p |= purge_all_dead_edges (0);
-  delete_noop_moves (f);
+  delete_noop_moves ();
 
   update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
                                    PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
@@ -759,17 +762,7 @@ combine_instructions (f, 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);
 
   {
@@ -788,6 +781,7 @@ combine_instructions (f, nregs)
   total_successes += combine_successes;
 
   nonzero_sign_valid = 0;
+  rtl_hooks = general_rtl_hooks;
 
   /* Make recognizer allow volatile MEMs again.  */
   init_recog ();
@@ -795,53 +789,43 @@ combine_instructions (f, 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 ()
+init_reg_last (void)
 {
-  unsigned int nregs = combine_max_regno;
-
-  memset ((char *) reg_last_death, 0, nregs * sizeof (rtx));
-  memset ((char *) reg_last_set, 0, nregs * sizeof (rtx));
-  memset ((char *) reg_last_set_value, 0, nregs * sizeof (rtx));
-  memset ((char *) reg_last_set_table_tick, 0, nregs * sizeof (int));
-  memset ((char *) reg_last_set_label, 0, nregs * sizeof (int));
-  memset (reg_last_set_invalid, 0, nregs * sizeof (char));
-  memset ((char *) reg_last_set_mode, 0, nregs * sizeof (enum machine_mode));
-  memset ((char *) 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.  */
 
 static void
-setup_incoming_promotions ()
+setup_incoming_promotions (void)
 {
-#ifdef PROMOTE_FUNCTION_ARGS
   unsigned int regno;
   rtx reg;
   enum machine_mode mode;
   int unsignedp;
   rtx first = get_insns ();
 
-#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
-       numbers, so translate if necessary due to register windows.  */
-    if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (regno))
-       && (reg = promoted_input_arg (regno, &mode, &unsignedp)) != 0)
-      {
-       record_value_for_reg
-         (reg, first, gen_rtx_fmt_e ((unsignedp ? ZERO_EXTEND
-                                      : SIGN_EXTEND),
-                                     GET_MODE (reg),
-                                     gen_rtx_CLOBBER (mode, const0_rtx)));
-      }
-#endif
+  if (targetm.calls.promote_function_args (TREE_TYPE (cfun->decl)))
+    {
+      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
+          numbers, so translate if necessary due to register windows.  */
+       if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (regno))
+           && (reg = promoted_input_arg (regno, &mode, &unsignedp)) != 0)
+         {
+           record_value_for_reg
+             (reg, first, gen_rtx_fmt_e ((unsignedp ? ZERO_EXTEND
+                                          : SIGN_EXTEND),
+                                         GET_MODE (reg),
+                                         gen_rtx_CLOBBER (mode, const0_rtx)));
+         }
+    }
 }
 \f
 /* Called via note_stores.  If X is a pseudo that is narrower than
@@ -856,10 +840,8 @@ setup_incoming_promotions ()
    by any set of X.  */
 
 static void
-set_nonzero_bits_and_sign_copies (x, set, data)
-     rtx x;
-     rtx set;
-     void *data ATTRIBUTE_UNUSED;
+set_nonzero_bits_and_sign_copies (rtx x, rtx set,
+                                 void *data ATTRIBUTE_UNUSED)
 {
   unsigned int num;
 
@@ -872,8 +854,8 @@ set_nonzero_bits_and_sign_copies (x, set, data)
     {
       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;
        }
 
@@ -895,7 +877,7 @@ set_nonzero_bits_and_sign_copies (x, set, data)
 #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.
 
@@ -914,18 +896,18 @@ set_nonzero_bits_and_sign_copies (x, set, data)
 #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;
        }
     }
 }
@@ -941,12 +923,8 @@ set_nonzero_bits_and_sign_copies (x, set, data)
    will return 1.  */
 
 static int
-can_combine_p (insn, i3, pred, succ, pdest, psrc)
-     rtx insn;
-     rtx i3;
-     rtx pred ATTRIBUTE_UNUSED;
-     rtx succ;
-     rtx *pdest, *psrc;
+can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
+              rtx *pdest, rtx *psrc)
 {
   int i;
   rtx set = 0, src, dest;
@@ -981,6 +959,7 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
       for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
        {
          rtx elt = XVECEXP (PATTERN (insn), 0, i);
+         rtx note;
 
          switch (GET_CODE (elt))
            {
@@ -1031,6 +1010,8 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
              /* 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;
 
@@ -1065,8 +1046,6 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
 
   /* Don't eliminate a store in the stack pointer.  */
   if (dest == stack_pointer_rtx
-      /* If we couldn't eliminate a field assignment, we can't combine.  */
-      || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == STRICT_LOW_PART
       /* Don't combine with an insn that sets a register to itself if it has
         a REG_EQUAL note.  This may be part of a REG_NO_CONFLICT sequence.  */
       || (rtx_equal_p (src, dest) && find_reg_note (insn, REG_EQUAL, NULL_RTX))
@@ -1098,7 +1077,7 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
         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
@@ -1229,46 +1208,6 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
   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 (pat)
-     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.
 
@@ -1307,61 +1246,31 @@ sets_function_arg_p (pat)
    Return 1 if the combination is valid, zero otherwise.  */
 
 static int
-combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
-     rtx i3;
-     rtx *loc;
-     rtx i2dest;
-     rtx i1dest;
-     int i1_not_in_src;
-     rtx *pi3dest_killed;
+combinable_i3pat (rtx i3, rtx *loc, rtx i2dest, rtx i1dest,
+                 int i1_not_in_src, rtx *pi3dest_killed)
 {
   rtx x = *loc;
 
   if (GET_CODE (x) == SET)
     {
-      rtx set = expand_field_assignment (x);
+      rtx set = ;
       rtx dest = SET_DEST (set);
       rtx src = SET_SRC (set);
       rtx inner_dest = dest;
 
-#if 0
-      rtx inner_src = src;
-#endif
-
-      SUBST (*loc, set);
-
       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);
 
-  /* We probably don't need this any more now that LIMIT_RELOAD_CLASS
-     was added.  */
-#if 0
-      while (GET_CODE (inner_src) == STRICT_LOW_PART
-            || GET_CODE (inner_src) == SUBREG
-            || GET_CODE (inner_src) == ZERO_EXTRACT)
-       inner_src = XEXP (inner_src, 0);
-
-      /* If it is better that two different modes keep two different pseudos,
-        avoid combining them.  This avoids producing the following pattern
-        on a 386:
-         (set (subreg:SI (reg/v:QI 21) 0)
-              (lshiftrt:SI (reg/v:SI 20)
-                  (const_int 24)))
-        If that were made, reload could not handle the pair of
-        reg 20/21, since it would try to get any GENERAL_REGS
-        but some of them don't handle QImode.  */
-
-      if (rtx_equal_p (inner_src, i2dest)
-         && GET_CODE (inner_dest) == REG
-         && ! MODES_TIEABLE_P (GET_MODE (i2dest), GET_MODE (inner_dest)))
-       return 0;
-#endif
-
-      /* Check for the case where I3 modifies its output, as
-        discussed above.  */
-      if ((inner_dest != dest
+      /* Check for the case where I3 modifies its output, as discussed
+        above.  We don't want to prevent pseudos from being combined
+        into the address of a MEM, so only prevent the combination if
+        i1 or i2 set the same MEM.  */
+      if ((inner_dest != dest &&
+          (GET_CODE (inner_dest) != MEM
+           || rtx_equal_p (i2dest, inner_dest)
+           || (i1dest && rtx_equal_p (i1dest, inner_dest)))
           && (reg_overlap_mentioned_p (i2dest, inner_dest)
               || (i1dest && reg_overlap_mentioned_p (i1dest, inner_dest))))
 
@@ -1423,8 +1332,7 @@ combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
    and division.  We don't count multiplications by powers of two here.  */
 
 static int
-contains_muldiv (x)
-     rtx x;
+contains_muldiv (rtx x)
 {
   switch (GET_CODE (x))
     {
@@ -1435,18 +1343,14 @@ contains_muldiv (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
@@ -1455,8 +1359,7 @@ contains_muldiv (x)
    can't perform combinations.  */
 
 static int
-cant_combine_insn_p (insn)
-     rtx insn;
+cant_combine_insn_p (rtx insn)
 {
   rtx set;
   rtx src, dest;
@@ -1467,10 +1370,10 @@ cant_combine_insn_p (insn)
   if (! INSN_P (insn))
     return 1;
 
-  /* Never combine loads and stores involving hard regs.  The register
-     allocator can usually handle such reg-reg moves by tying.  If we allow
-     the combiner to make substitutions of hard regs, we risk aborting in
-     reload on machines that have SMALL_REGISTER_CLASSES.
+  /* Never combine loads and stores involving hard regs that are likely
+     to be spilled.  The register allocator can usually handle such
+     reg-reg moves by tying.  If we allow the combiner to make
+     substitutions of likely-spilled regs, we may abort in reload.
      As an exception, we allow combinations involving fixed regs; these are
      not available to the register allocator so there's no risk involved.  */
 
@@ -1485,14 +1388,43 @@ cant_combine_insn_p (insn)
     dest = SUBREG_REG (dest);
   if (REG_P (src) && REG_P (dest)
       && ((REGNO (src) < FIRST_PSEUDO_REGISTER
-          && ! fixed_regs[REGNO (src)])
+          && ! fixed_regs[REGNO (src)]
+          && CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (src))))
          || (REGNO (dest) < FIRST_PSEUDO_REGISTER
-             && ! fixed_regs[REGNO (dest)])))
+             && ! fixed_regs[REGNO (dest)]
+             && CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (dest))))))
     return 1;
 
   return 0;
 }
 
+/* Adjust INSN after we made a change to its destination.
+
+   Changing the destination can invalidate notes that say something about
+   the results of the insn and a LOG_LINK pointing to the insn.  */
+
+static void
+adjust_for_new_dest (rtx insn)
+{
+  rtx *loc;
+
+  /* For notes, be conservative and simply remove them.  */
+  loc = &REG_NOTES (insn);
+  while (*loc)
+    {
+      enum reg_note kind = REG_NOTE_KIND (*loc);
+      if (kind == REG_EQUAL || kind == REG_EQUIV)
+       *loc = XEXP (*loc, 1);
+      else
+       loc = &XEXP (*loc, 1);
+    }
+
+  /* The new insn will have a destination that was previously the destination
+     of an insn just above it.  Call distribute_links to make a LOG_LINK from
+     the next use of that destination.  */
+  distribute_links (gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX));
+}
+
 /* Try to combine the insns I1 and I2 into I3.
    Here I1 and I2 appear earlier than I3.
    I1 can be zero; then we combine just I2 into I3.
@@ -1510,9 +1442,7 @@ cant_combine_insn_p (insn)
    new direct jump instruction.  */
 
 static rtx
-try_combine (i3, i2, i1, new_direct_jump_p)
-     rtx i3, i2, i1;
-     int *new_direct_jump_p;
+try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 {
   /* New patterns for I3 and I2, respectively.  */
   rtx newpat, newi2pat = 0;
@@ -1521,7 +1451,7 @@ try_combine (i3, i2, i1, 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;
@@ -1689,7 +1619,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
            abort ();
 
          lo &= ~(UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1);
-         lo |= (INTVAL (SET_SRC (PATTERN (i3))) 
+         lo |= (INTVAL (SET_SRC (PATTERN (i3)))
                 & (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1));
        }
       else if (HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
@@ -1762,7 +1692,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
             as I2 will not cause a problem.  */
 
          i1 = gen_rtx_INSN (VOIDmode, INSN_UID (i2), NULL_RTX, i2,
-                            BLOCK_FOR_INSN (i2), INSN_SCOPE (i2),
+                            BLOCK_FOR_INSN (i2), INSN_LOCATOR (i2),
                             XVECEXP (PATTERN (i2), 0, 1), -1, NULL_RTX,
                             NULL_RTX);
 
@@ -1891,9 +1821,7 @@ try_combine (i3, i2, i1, 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);
@@ -1923,7 +1851,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
       && XEXP (SET_SRC (PATTERN (i3)), 1) == const0_rtx
       && rtx_equal_p (XEXP (SET_SRC (PATTERN (i3)), 0), i2dest))
     {
-#ifdef EXTRA_CC_MODES
+#ifdef SELECT_CC_MODE
       rtx *cc_use;
       enum machine_mode compare_mode;
 #endif
@@ -1933,7 +1861,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
 
       i2_is_used = 1;
 
-#ifdef EXTRA_CC_MODES
+#ifdef SELECT_CC_MODE
       /* See if a COMPARE with the operand we substituted in should be done
         with the mode that is currently being used.  If not, do the same
         processing we do in `subst' for a SET; namely, if the destination
@@ -2082,38 +2010,69 @@ try_combine (i3, i2, i1, 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 (((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)))
+       {
+         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);
+           }
+       }
     }
 
   /* If we were combining three insns and the result is a simple SET
@@ -2348,18 +2307,18 @@ try_combine (i3, i2, i1, 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)))
@@ -2372,7 +2331,7 @@ try_combine (i3, i2, i1, 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)
@@ -2384,16 +2343,9 @@ try_combine (i3, i2, i1, new_direct_jump_p)
          rtx link;
 
          /* If we will be able to accept this, we have made a change to the
-            destination of I3.  This can invalidate a LOG_LINKS pointing
-            to I3.  No other part of combine.c makes such a transformation.
-
-            The new I3 will have a destination that was previously the
-            destination of I1 or I2 and which was used in i2 or I3.  Call
-            distribute_links to make a LOG_LINK from the next use of
-            that destination.  */
-
+            destination of I3.  This requires us to do a few adjustments.  */
          PATTERN (i3) = newpat;
-         distribute_links (gen_rtx_INSN_LIST (VOIDmode, i3, NULL_RTX));
+         adjust_for_new_dest (i3);
 
          /* I3 now uses what used to be its destination and which is
             now I2's destination.  That means we need a LOG_LINK from
@@ -2406,7 +2358,7 @@ try_combine (i3, i2, i1, 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)))
@@ -2522,10 +2474,10 @@ try_combine (i3, i2, i1, new_direct_jump_p)
          REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
 
       distribute_notes (new_other_notes, undobuf.other_insn,
-                       undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
+                       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);
@@ -2546,15 +2498,6 @@ try_combine (i3, i2, i1, new_direct_jump_p)
     rtx i3links, i2links, i1links = 0;
     rtx midnotes = 0;
     unsigned int regno;
-    /* Compute which registers we expect to eliminate.  newi2pat may be setting
-       either i3dest or i2dest, so we must check it.  Also, i1dest may be the
-       same as i3dest, in which case newi2pat may be setting i1dest.  */
-    rtx elim_i2 = ((newi2pat && reg_set_p (i2dest, newi2pat))
-                  || i2dest_in_i2src || i2dest_in_i1src
-                  ? 0 : i2dest);
-    rtx elim_i1 = (i1 == 0 || i1dest_in_i1src
-                  || (newi2pat && reg_set_p (i1dest, newi2pat))
-                  ? 0 : i1dest);
 
     /* Get the old REG_NOTES and LOG_LINKS from all our insns and
        clear them.  */
@@ -2624,7 +2567,7 @@ try_combine (i3, i2, i1, 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))
@@ -2685,17 +2628,13 @@ try_combine (i3, i2, i1, new_direct_jump_p)
 
     /* Distribute all the LOG_LINKS and REG_NOTES from I1, I2, and I3.  */
     if (i3notes)
-      distribute_notes (i3notes, i3, i3, newi2pat ? i2 : NULL_RTX,
-                       elim_i2, elim_i1);
+      distribute_notes (i3notes, i3, i3, newi2pat ? i2 : NULL_RTX);
     if (i2notes)
-      distribute_notes (i2notes, i2, i3, newi2pat ? i2 : NULL_RTX,
-                       elim_i2, elim_i1);
+      distribute_notes (i2notes, i2, i3, newi2pat ? i2 : NULL_RTX);
     if (i1notes)
-      distribute_notes (i1notes, i1, i3, newi2pat ? i2 : NULL_RTX,
-                       elim_i2, elim_i1);
+      distribute_notes (i1notes, i1, i3, newi2pat ? i2 : NULL_RTX);
     if (midnotes)
-      distribute_notes (midnotes, NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
-                       elim_i2, elim_i1);
+      distribute_notes (midnotes, NULL_RTX, i3, newi2pat ? i2 : NULL_RTX);
 
     /* Distribute any notes added to I2 or I3 by recog_for_combine.  We
        know these are REG_UNUSED and want them to go to the desired insn,
@@ -2708,7 +2647,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
          if (GET_CODE (XEXP (temp, 0)) == REG)
            REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
 
-       distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
+       distribute_notes (new_i2_notes, i2, i2, NULL_RTX);
       }
 
     if (new_i3_notes)
@@ -2717,7 +2656,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
          if (GET_CODE (XEXP (temp, 0)) == REG)
            REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
 
-       distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
+       distribute_notes (new_i3_notes, i3, i3, NULL_RTX);
       }
 
     /* If I3DEST was used in I3SRC, it really died in I3.  We may need to
@@ -2735,12 +2674,11 @@ try_combine (i3, i2, i1, new_direct_jump_p)
        if (newi2pat && reg_set_p (i3dest_killed, newi2pat))
          distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
                                               NULL_RTX),
-                           NULL_RTX, i2, NULL_RTX, elim_i2, elim_i1);
+                           NULL_RTX, i2, NULL_RTX);
        else
          distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
                                               NULL_RTX),
-                           NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
-                           elim_i2, elim_i1);
+                           NULL_RTX, i3, newi2pat ? i2 : NULL_RTX);
       }
 
     if (i2dest_in_i2src)
@@ -2750,11 +2688,10 @@ try_combine (i3, i2, i1, new_direct_jump_p)
 
        if (newi2pat && reg_set_p (i2dest, newi2pat))
          distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
-                           NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
+                           NULL_RTX, i2, NULL_RTX);
        else
          distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
-                           NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
-                           NULL_RTX, NULL_RTX);
+                           NULL_RTX, i3, newi2pat ? i2 : NULL_RTX);
       }
 
     if (i1dest_in_i1src)
@@ -2764,11 +2701,10 @@ try_combine (i3, i2, i1, new_direct_jump_p)
 
        if (newi2pat && reg_set_p (i1dest, newi2pat))
          distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
-                           NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
+                           NULL_RTX, i2, NULL_RTX);
        else
          distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
-                           NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
-                           NULL_RTX, NULL_RTX);
+                           NULL_RTX, i3, newi2pat ? i2 : NULL_RTX);
       }
 
     distribute_links (i3links);
@@ -2823,9 +2759,10 @@ try_combine (i3, i2, i1, 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);
@@ -2840,6 +2777,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
     if (returnjump_p (i3) || any_uncondjump_p (i3))
       {
        *new_direct_jump_p = 1;
+       mark_jump_label (PATTERN (i3), i3, 0);
 
        if ((temp = next_nonnote_insn (i3)) == NULL_RTX
            || GET_CODE (temp) != BARRIER)
@@ -2856,7 +2794,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
            || GET_CODE (temp) != BARRIER)
          emit_barrier_after (undobuf.other_insn);
       }
-       
+
     /* An NOOP jump does not need barrier, but it does need cleaning up
        of CFG.  */
     if (GET_CODE (newpat) == SET
@@ -2879,7 +2817,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
 /* Undo all the modifications recorded in undobuf.  */
 
 static void
-undo_all ()
+undo_all (void)
 {
   struct undo *undo, *next;
 
@@ -2902,7 +2840,7 @@ undo_all ()
    of the undos to the free list.  */
 
 static void
-undo_commit ()
+undo_commit (void)
 {
   struct undo *undo, *next;
 
@@ -2924,9 +2862,7 @@ undo_commit ()
    two insns.  */
 
 static rtx *
-find_split_point (loc, insn)
-     rtx *loc;
-     rtx insn;
+find_split_point (rtx *loc, rtx insn)
 {
   rtx x = *loc;
   enum rtx_code code = GET_CODE (x);
@@ -3023,10 +2959,9 @@ find_split_point (loc, 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;
@@ -3041,9 +2976,9 @@ find_split_point (loc, 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
 
@@ -3082,14 +3017,16 @@ find_split_point (loc, insn)
 
          if (src == mask)
            SUBST (SET_SRC (x),
-                  gen_binary (IOR, mode, dest, GEN_INT (src << pos)));
+                  simplify_gen_binary (IOR, mode, dest, GEN_INT (src << pos)));
          else
-           SUBST (SET_SRC (x),
-                  gen_binary (IOR, mode,
-                              gen_binary (AND, mode, dest,
-                                          gen_int_mode (~(mask << pos),
-                                                        mode)),
-                              GEN_INT (src << pos)));
+           {
+             rtx negmask = gen_int_mode (~(mask << pos), mode);
+             SUBST (SET_SRC (x),
+                    simplify_gen_binary (IOR, mode,
+                                         simplify_gen_binary (AND, mode,
+                                                              dest, negmask),
+                                         GEN_INT (src << pos)));
+           }
 
          SUBST (SET_DEST (x), dest);
 
@@ -3135,7 +3072,7 @@ find_split_point (loc, insn)
          break;
 
        case NE:
-         /* if STORE_FLAG_VALUE is -1, this is (NE X 0) and only one bit of X
+         /* If STORE_FLAG_VALUE is -1, this is (NE X 0) and only one bit of X
             is known to be on, this can be converted into a NEG of a shift.  */
          if (STORE_FLAG_VALUE == -1 && XEXP (SET_SRC (x), 1) == const0_rtx
              && GET_MODE (SET_SRC (x)) == GET_MODE (XEXP (SET_SRC (x), 0))
@@ -3206,7 +3143,7 @@ find_split_point (loc, 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)));
 
@@ -3220,7 +3157,7 @@ find_split_point (loc, 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)));
@@ -3234,14 +3171,11 @@ find_split_point (loc, 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
@@ -3249,10 +3183,7 @@ find_split_point (loc, 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);
 
@@ -3292,20 +3223,21 @@ find_split_point (loc, 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)
@@ -3315,10 +3247,11 @@ find_split_point (loc, 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.
@@ -3341,10 +3274,7 @@ find_split_point (loc, insn)
    by copying if `n_occurrences' is nonzero.  */
 
 static rtx
-subst (x, from, to, in_dest, unique_copy)
-     rtx x, from, to;
-     int in_dest;
-     int unique_copy;
+subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
 {
   enum rtx_code code = GET_CODE (x);
   enum machine_mode op0_mode = VOIDmode;
@@ -3380,7 +3310,7 @@ subst (x, from, to, in_dest, 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.
@@ -3557,7 +3487,9 @@ subst (x, from, to, in_dest, unique_copy)
              if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
                return new;
 
-             if (GET_CODE (new) == CONST_INT && GET_CODE (x) == SUBREG)
+             if (GET_CODE (x) == SUBREG
+                 && (GET_CODE (new) == CONST_INT
+                     || GET_CODE (new) == CONST_DOUBLE))
                {
                  enum machine_mode mode = GET_MODE (x);
 
@@ -3590,7 +3522,7 @@ subst (x, from, to, in_dest, 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;
@@ -3609,16 +3541,11 @@ subst (x, from, to, in_dest, 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 (x, op0_mode, last, in_dest)
-     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);
@@ -3628,7 +3555,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
 
   /* 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);
@@ -3674,7 +3601,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       new = simplify_shift_const (NULL_RTX, ASHIFTRT, mode, new,
                                  INTVAL (XEXP (XEXP (x, 0), 1)));
 
-      SUBST (XEXP (x, 0), gen_binary (PLUS, mode, new, temp));
+      SUBST (XEXP (x, 0), simplify_gen_binary (PLUS, mode, new, temp));
     }
 
   /* If this is a simple operation applied to an IF_THEN_ELSE, try
@@ -3684,21 +3611,17 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
 
      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;
 
@@ -3706,20 +3629,21 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       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
-            false arms to store-flag values.  */
-         true_rtx = subst (true_rtx, pc_rtx, pc_rtx, 0, 0);
-         false_rtx = subst (false_rtx, pc_rtx, pc_rtx, 0, 0);
+            false arms to store-flag values.  Be careful to use copy_rtx
+            here since true_rtx or false_rtx might share RTL with x as a
+            result of the if_then_else_cond call above.  */
+         true_rtx = subst (copy_rtx (true_rtx), pc_rtx, pc_rtx, 0, 0);
+         false_rtx = subst (copy_rtx (false_rtx), pc_rtx, pc_rtx, 0, 0);
 
          /* If true_rtx and false_rtx are not general_operands, an if_then_else
             is unlikely to be simpler.  */
@@ -3734,12 +3658,14 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
              /* If the result values are STORE_FLAG_VALUE and zero, we can
                 just make the comparison operation.  */
              if (true_rtx == const_true_rtx && false_rtx == const0_rtx)
-               x = gen_binary (cond_code, mode, cond, cop1);
+               x = simplify_gen_relational (cond_code, mode, VOIDmode,
+                                            cond, cop1);
              else if (true_rtx == const0_rtx && false_rtx == const_true_rtx
                       && ((reversed = reversed_comparison_code_parts
-                                       (cond_code, cond, cop1, NULL))
+                                       (cond_code, cond, cop1, NULL))
                           != UNKNOWN))
-               x = gen_binary (reversed, mode, cond, cop1);
+               x = simplify_gen_relational (reversed, mode, VOIDmode,
+                                            cond, cop1);
 
              /* Likewise, we can make the negate of a comparison operation
                 if the result values are - STORE_FLAG_VALUE and zero.  */
@@ -3747,23 +3673,28 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
                       && INTVAL (true_rtx) == - STORE_FLAG_VALUE
                       && false_rtx == const0_rtx)
                x = simplify_gen_unary (NEG, mode,
-                                       gen_binary (cond_code, mode, cond,
-                                                   cop1),
+                                       simplify_gen_relational (cond_code,
+                                                                mode, VOIDmode,
+                                                                cond, cop1),
                                        mode);
              else if (GET_CODE (false_rtx) == CONST_INT
                       && INTVAL (false_rtx) == - STORE_FLAG_VALUE
                       && true_rtx == const0_rtx
                       && ((reversed = reversed_comparison_code_parts
-                                       (cond_code, cond, cop1, NULL))
+                                       (cond_code, cond, cop1, NULL))
                           != UNKNOWN))
                x = simplify_gen_unary (NEG, mode,
-                                       gen_binary (reversed, mode,
-                                                   cond, cop1),
+                                       simplify_gen_relational (reversed,
+                                                                mode, VOIDmode,
+                                                                cond, cop1),
                                        mode);
              else
                return gen_rtx_IF_THEN_ELSE (mode,
-                                            gen_binary (cond_code, VOIDmode,
-                                                        cond, cop1),
+                                            simplify_gen_relational (cond_code,
+                                                                     mode,
+                                                                     VOIDmode,
+                                                                     cond,
+                                                                     cop1),
                                             true_rtx, false_rtx);
 
              code = GET_CODE (x);
@@ -3777,10 +3708,13 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
   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)
@@ -3789,29 +3723,21 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
            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)
@@ -3849,7 +3775,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
 
          /* 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;
@@ -3862,7 +3788,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
 
          /* 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,
@@ -3871,7 +3797,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
            }
 
          if (inner)
-           return gen_binary (code, mode, other, inner);
+           return simplify_gen_binary (code, mode, other, inner);
        }
     }
 
@@ -3889,15 +3815,15 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       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;
@@ -3923,33 +3849,6 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       break;
 
     case NOT:
-      /* (not (plus X -1)) can become (neg X).  */
-      if (GET_CODE (XEXP (x, 0)) == PLUS
-         && XEXP (XEXP (x, 0), 1) == constm1_rtx)
-       return gen_rtx_NEG (mode, XEXP (XEXP (x, 0), 0));
-
-      /* Similarly, (not (neg X)) is (plus X -1).  */
-      if (GET_CODE (XEXP (x, 0)) == NEG)
-       return gen_rtx_PLUS (mode, XEXP (XEXP (x, 0), 0), constm1_rtx);
-
-      /* (not (xor X C)) for C constant is (xor X D) with D = ~C.  */
-      if (GET_CODE (XEXP (x, 0)) == XOR
-         && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
-         && (temp = simplify_unary_operation (NOT, mode,
-                                              XEXP (XEXP (x, 0), 1),
-                                              mode)) != 0)
-       return gen_binary (XOR, mode, XEXP (XEXP (x, 0), 0), temp);
-
-      /* (not (ashift 1 X)) is (rotate ~1 X).  We used to do this for operands
-        other than 1, but that is not valid.  We could do a similar
-        simplification for (not (lshiftrt C X)) where C is just the sign bit,
-        but this doesn't seem common enough to bother with.  */
-      if (GET_CODE (XEXP (x, 0)) == ASHIFT
-         && XEXP (XEXP (x, 0), 0) == const1_rtx)
-       return gen_rtx_ROTATE (mode, simplify_gen_unary (NOT, mode,
-                                                        const1_rtx, mode),
-                              XEXP (XEXP (x, 0), 1));
-
       if (GET_CODE (XEXP (x, 0)) == SUBREG
          && subreg_lowpart_p (XEXP (x, 0))
          && (GET_MODE_SIZE (GET_MODE (XEXP (x, 0)))
@@ -3963,27 +3862,9 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
                              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);
        }
 
-      /* If STORE_FLAG_VALUE is -1, (not (comparison foo bar)) can be done by
-        reversing the comparison code if valid.  */
-      if (STORE_FLAG_VALUE == -1
-         && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
-         && (reversed = reversed_comparison (x, mode, XEXP (XEXP (x, 0), 0),
-                                             XEXP (XEXP (x, 0), 1))))
-       return reversed;
-
-      /* (not (ashiftrt foo C)) where C is the number of bits in FOO minus 1
-        is (ge foo (const_int 0)) if STORE_FLAG_VALUE is -1, so we can
-        perform the above simplification.  */
-
-      if (STORE_FLAG_VALUE == -1
-         && GET_CODE (XEXP (x, 0)) == ASHIFTRT
-         && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
-         && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (mode) - 1)
-       return gen_rtx_GE (mode, XEXP (XEXP (x, 0), 0), const0_rtx);
-
       /* Apply De Morgan's laws to reduce number of patterns for machines
         with negating logical insns (and-not, nand, etc.).  If result has
         only one NOT, put it first, since that is how the patterns are
@@ -4014,60 +3895,12 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       break;
 
     case NEG:
-      /* (neg (plus X 1)) can become (not X).  */
-      if (GET_CODE (XEXP (x, 0)) == PLUS
-         && XEXP (XEXP (x, 0), 1) == const1_rtx)
-       return gen_rtx_NOT (mode, XEXP (XEXP (x, 0), 0));
-
-      /* Similarly, (neg (not X)) is (plus X 1).  */
-      if (GET_CODE (XEXP (x, 0)) == NOT)
-       return plus_constant (XEXP (XEXP (x, 0), 0), 1);
-
-      /* (neg (minus X Y)) can become (minus Y X).  This transformation
-        isn't safe for modes with signed zeros, since if X and Y are
-        both +0, (minus Y X) is the same as (minus X Y).  If the rounding
-        mode is towards +infinity (or -infinity) then the two expressions
-        will be rounded differently.  */
-      if (GET_CODE (XEXP (x, 0)) == MINUS
-         && !HONOR_SIGNED_ZEROS (mode)
-         && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
-       return gen_binary (MINUS, mode, XEXP (XEXP (x, 0), 1),
-                          XEXP (XEXP (x, 0), 0));
-
-      /* (neg (plus A B)) is canonicalized to (minus (neg A) B).  */
-      if (GET_CODE (XEXP (x, 0)) == PLUS
-         && !HONOR_SIGNED_ZEROS (mode)
-         && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
-       {
-         temp = simplify_gen_unary (NEG, mode, XEXP (XEXP (x, 0), 0), mode);
-         temp = combine_simplify_rtx (temp, mode, last, in_dest);
-         return gen_binary (MINUS, mode, temp, XEXP (XEXP (x, 0), 1));
-       }
-
-      /* (neg (mult A B)) becomes (mult (neg A) B).  
-         This works even for floating-point values.  */
-      if (GET_CODE (XEXP (x, 0)) == MULT)
-       {
-         temp = simplify_gen_unary (NEG, mode, XEXP (XEXP (x, 0), 0), mode);
-         return gen_binary (MULT, mode, temp, XEXP (XEXP (x, 0), 1));
-       }
-
       /* (neg (xor A 1)) is (plus A -1) if A is known to be either 0 or 1.  */
-      if (GET_CODE (XEXP (x, 0)) == XOR && XEXP (XEXP (x, 0), 1) == const1_rtx
+      if (GET_CODE (XEXP (x, 0)) == XOR
+         && XEXP (XEXP (x, 0), 1) == const1_rtx
          && nonzero_bits (XEXP (XEXP (x, 0), 0), mode) == 1)
-       return gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0), constm1_rtx);
-
-      /* NEG commutes with ASHIFT since it is multiplication.  Only do this
-        if we can then eliminate the NEG (e.g.,
-        if the operand is a constant).  */
-
-      if (GET_CODE (XEXP (x, 0)) == ASHIFT)
-       {
-         temp = simplify_unary_operation (NEG, mode,
-                                          XEXP (XEXP (x, 0), 0), mode);
-         if (temp)
-           return gen_binary (ASHIFT, mode, temp, XEXP (XEXP (x, 0), 1));
-       }
+       return simplify_gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0),
+                                   constm1_rtx);
 
       temp = expand_compound_operation (XEXP (x, 0));
 
@@ -4157,16 +3990,16 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
             >= (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
@@ -4174,8 +4007,8 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       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;
 
@@ -4185,23 +4018,23 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
          && GET_MODE (XEXP (XEXP (x, 0), 0)) == mode)
        return XEXP (XEXP (x, 0), 0);
 
-      /* (float_truncate:SF (float_truncate:DF foo:XF)) 
-         = (float_truncate:SF foo:XF). 
-        This may elliminate double rounding, so it is unsafe.
+      /* (float_truncate:SF (float_truncate:DF foo:XF))
+         = (float_truncate:SF foo:XF).
+        This may eliminate double rounding, so it is unsafe.
 
-         (float_truncate:SF (float_extend:XF foo:DF)) 
-         = (float_truncate:SF foo:DF). 
+         (float_truncate:SF (float_extend:XF foo:DF))
+         = (float_truncate:SF foo:DF).
 
-         (float_truncate:DF (float_extend:XF foo:SF)) 
+         (float_truncate:DF (float_extend:XF foo:SF))
          = (float_extend:SF foo:DF).  */
       if ((GET_CODE (XEXP (x, 0)) == FLOAT_TRUNCATE
           && flag_unsafe_math_optimizations)
          || GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND)
        return simplify_gen_unary (GET_MODE_SIZE (GET_MODE (XEXP (XEXP (x, 0),
-                                                           0)))
-                                  > GET_MODE_SIZE (mode)
+                                                           0)))
+                                  > GET_MODE_SIZE (mode)
                                   ? FLOAT_TRUNCATE : FLOAT_EXTEND,
-                                  mode,
+                                  mode,
                                   XEXP (XEXP (x, 0), 0), mode);
 
       /*  (float_truncate (float x)) is (float x)  */
@@ -4233,9 +4066,9 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       break;
     case FLOAT_EXTEND:
       /*  (float_extend (float_extend x)) is (float_extend x)
-        
+
          (float_extend (float x)) is (float x) assuming that double
-         rounding can't happen. 
+         rounding can't happen.
           */
       if (GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND
          || (GET_CODE (XEXP (x, 0)) == FLOAT
@@ -4288,15 +4121,16 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
     case PLUS:
       /* Canonicalize (plus (mult (neg B) C) A) to (minus A (mult B C)).
        */
-      if (GET_CODE (XEXP (x, 0)) == MULT 
+      if (GET_CODE (XEXP (x, 0)) == MULT
          && GET_CODE (XEXP (XEXP (x, 0), 0)) == NEG)
        {
          rtx in1, in2;
-        
+
          in1 = XEXP (XEXP (XEXP (x, 0), 0), 0);
          in2 = XEXP (XEXP (x, 0), 1);
-         return gen_binary (MINUS, mode, XEXP (x, 1),
-                            gen_binary (MULT, mode, in1, in2));
+         return simplify_gen_binary (MINUS, mode, XEXP (x, 1),
+                                     simplify_gen_binary (MULT, mode,
+                                                          in1, in2));
        }
 
       /* If we have (plus (plus (A const) B)), associate it so that CONST is
@@ -4305,10 +4139,11 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
         they are now checked elsewhere.  */
       if (GET_CODE (XEXP (x, 0)) == PLUS
          && CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1)))
-       return gen_binary (PLUS, mode,
-                          gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0),
-                                      XEXP (x, 1)),
-                          XEXP (XEXP (x, 0), 1));
+       return simplify_gen_binary (PLUS, mode,
+                                   simplify_gen_binary (PLUS, mode,
+                                                        XEXP (XEXP (x, 0), 0),
+                                                        XEXP (x, 1)),
+                                   XEXP (XEXP (x, 0), 1));
 
       /* (plus (xor (and <foo> (const_int pow2 - 1)) <c>) <-c>)
         when c is (const_int (pow2 + 1) / 2) is a sign extension of a
@@ -4340,7 +4175,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
         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,
@@ -4374,8 +4209,8 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
              & nonzero_bits (XEXP (x, 1), mode)) == 0)
        {
          /* 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);
+         rtx tor = simplify_gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
+         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
@@ -4390,7 +4225,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
         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))))
@@ -4407,37 +4242,42 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
 
       /* Canonicalize (minus A (mult (neg B) C)) to (plus (mult B C) A).
        */
-      if (GET_CODE (XEXP (x, 1)) == MULT 
+      if (GET_CODE (XEXP (x, 1)) == MULT
          && GET_CODE (XEXP (XEXP (x, 1), 0)) == NEG)
        {
          rtx in1, in2;
-        
+
          in1 = XEXP (XEXP (XEXP (x, 1), 0), 0);
          in2 = XEXP (XEXP (x, 1), 1);
-         return gen_binary (PLUS, mode, gen_binary (MULT, mode, in1, in2),
-                            XEXP (x, 0));
+         return simplify_gen_binary (PLUS, mode,
+                                     simplify_gen_binary (MULT, mode,
+                                                          in1, in2),
+                                     XEXP (x, 0));
        }
 
-      /* Canonicalize (minus (neg A) (mult B C)) to 
+      /* Canonicalize (minus (neg A) (mult B C)) to
         (minus (mult (neg B) C) A).  */
-      if (GET_CODE (XEXP (x, 1)) == MULT 
+      if (GET_CODE (XEXP (x, 1)) == MULT
          && GET_CODE (XEXP (x, 0)) == NEG)
        {
          rtx in1, in2;
-        
+
          in1 = simplify_gen_unary (NEG, mode, XEXP (XEXP (x, 1), 0), mode);
          in2 = XEXP (XEXP (x, 1), 1);
-         return gen_binary (MINUS, mode, gen_binary (MULT, mode, in1, in2),
-                            XEXP (XEXP (x, 0), 0));
+         return simplify_gen_binary (MINUS, mode,
+                                     simplify_gen_binary (MULT, mode,
+                                                          in1, in2),
+                                     XEXP (XEXP (x, 0), 0));
        }
 
       /* Canonicalize (minus A (plus B C)) to (minus (minus A B) C) for
         integers.  */
       if (GET_CODE (XEXP (x, 1)) == PLUS && INTEGRAL_MODE_P (mode))
-       return gen_binary (MINUS, mode,
-                          gen_binary (MINUS, mode, XEXP (x, 0),
-                                      XEXP (XEXP (x, 1), 0)),
-                          XEXP (XEXP (x, 1), 1));
+       return simplify_gen_binary (MINUS, mode,
+                                   simplify_gen_binary (MINUS, mode,
+                                                        XEXP (x, 0),
+                                                        XEXP (XEXP (x, 1), 0)),
+                                   XEXP (XEXP (x, 1), 1));
       break;
 
     case MULT:
@@ -4447,17 +4287,11 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
 
       if (GET_CODE (XEXP (x, 0)) == PLUS)
        {
-         x = apply_distributive_law
-           (gen_binary (PLUS, mode,
-                        gen_binary (MULT, mode,
-                                    XEXP (XEXP (x, 0), 0), XEXP (x, 1)),
-                        gen_binary (MULT, mode,
-                                    XEXP (XEXP (x, 0), 1),
-                                    copy_rtx (XEXP (x, 1)))));
-
-         if (GET_CODE (x) != MULT)
-           return x;
+         rtx result = distribute_and_simplify_rtx (x);
+         if (result)
+           return result;
        }
+
       /* Try simplify a*(b/c) as (a*b)/c.  */
       if (FLOAT_MODE_P (mode) && flag_unsafe_math_optimizations
          && GET_CODE (XEXP (x, 0)) == DIV)
@@ -4466,7 +4300,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
                                               XEXP (XEXP (x, 0), 0),
                                               XEXP (x, 1));
          if (tem)
-           return gen_binary (DIV, mode, tem, XEXP (XEXP (x, 0), 1));
+           return simplify_gen_binary (DIV, mode, tem, XEXP (XEXP (x, 0), 1));
        }
       break;
 
@@ -4523,8 +4357,8 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
              && 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
@@ -4535,7 +4369,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
            {
              op0 = expand_compound_operation (op0);
              return simplify_gen_unary (NEG, mode,
-                                        gen_lowpart_for_combine (mode, op0),
+                                        gen_lowpart (mode, op0),
                                         mode);
            }
 
@@ -4546,9 +4380,9 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
                   && nonzero_bits (op0, mode) == 1)
            {
              op0 = expand_compound_operation (op0);
-             return gen_binary (XOR, mode,
-                                gen_lowpart_for_combine (mode, op0),
-                                const1_rtx);
+             return simplify_gen_binary (XOR, mode,
+                                         gen_lowpart (mode, op0),
+                                         const1_rtx);
            }
 
          else if (STORE_FLAG_VALUE == 1
@@ -4559,7 +4393,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
                       == 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
@@ -4569,8 +4403,8 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
              && 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
@@ -4580,7 +4414,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
            {
              op0 = expand_compound_operation (op0);
              return simplify_gen_unary (NEG, mode,
-                                        gen_lowpart_for_combine (mode, op0),
+                                        gen_lowpart (mode, op0),
                                         mode);
            }
 
@@ -4593,7 +4427,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
            {
              op0 = expand_compound_operation (op0);
              return simplify_gen_unary (NOT, mode,
-                                        gen_lowpart_for_combine (mode, op0),
+                                        gen_lowpart (mode, op0),
                                         mode);
            }
 
@@ -4605,7 +4439,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
                   && 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
@@ -4660,7 +4494,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
     case AND:
     case IOR:
     case XOR:
-      return simplify_logical (x, last);
+      return simplify_logical (x);
 
     case ABS:
       /* (abs (neg <foo>)) -> (abs <foo>) */
@@ -4718,7 +4552,6 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
        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)),
@@ -4726,8 +4559,6 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
                               << exact_log2 (GET_MODE_BITSIZE (GET_MODE (x))))
                              - 1,
                              NULL_RTX, 0));
-#endif
-
       break;
 
     case VEC_SELECT:
@@ -4779,15 +4610,14 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
 /* Simplify X, an IF_THEN_ELSE expression.  Return the new expression.  */
 
 static rtx
-simplify_if_then_else (x)
-     rtx x;
+simplify_if_then_else (rtx x)
 {
   enum machine_mode mode = GET_MODE (x);
   rtx cond = XEXP (x, 0);
   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;
@@ -4795,7 +4625,8 @@ simplify_if_then_else (x)
 
   /* Simplify storing of the truth value.  */
   if (comparison_p && true_rtx == const_true_rtx && false_rtx == const0_rtx)
-    return gen_binary (true_code, mode, XEXP (cond, 0), XEXP (cond, 1));
+    return simplify_gen_relational (true_code, mode, VOIDmode,
+                                   XEXP (cond, 0), XEXP (cond, 1));
 
   /* Also when the truth value has to be reversed.  */
   if (comparison_p
@@ -4872,11 +4703,9 @@ simplify_if_then_else (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))))
     {
@@ -4893,7 +4722,7 @@ simplify_if_then_else (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.  */
@@ -4947,16 +4776,16 @@ simplify_if_then_else (x)
       {
       case GE:
       case GT:
-       return gen_binary (SMAX, mode, true_rtx, false_rtx);
+       return simplify_gen_binary (SMAX, mode, true_rtx, false_rtx);
       case LE:
       case LT:
-       return gen_binary (SMIN, mode, true_rtx, false_rtx);
+       return simplify_gen_binary (SMIN, mode, true_rtx, false_rtx);
       case GEU:
       case GTU:
-       return gen_binary (UMAX, mode, true_rtx, false_rtx);
+       return simplify_gen_binary (UMAX, mode, true_rtx, false_rtx);
       case LEU:
       case LTU:
-       return gen_binary (UMIN, mode, true_rtx, false_rtx);
+       return simplify_gen_binary (UMIN, mode, true_rtx, false_rtx);
       default:
        break;
       }
@@ -4969,7 +4798,9 @@ simplify_if_then_else (x)
      neither 1 or -1, but it isn't worth checking for.  */
 
   if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
-      && comparison_p && mode != VOIDmode && ! side_effects_p (x))
+      && comparison_p
+      && GET_MODE_CLASS (mode) == MODE_INT
+      && ! side_effects_p (x))
     {
       rtx t = make_compound_operation (true_rtx, SET);
       rtx f = make_compound_operation (false_rtx, SET);
@@ -5067,12 +4898,14 @@ simplify_if_then_else (x)
 
       if (z)
        {
-         temp = subst (gen_binary (true_code, m, cond_op0, cond_op1),
+         temp = subst (simplify_gen_relational (true_code, m, VOIDmode,
+                                                cond_op0, cond_op1),
                        pc_rtx, pc_rtx, 0, 0);
-         temp = gen_binary (MULT, m, temp,
-                            gen_binary (MULT, m, c1, const_true_rtx));
+         temp = simplify_gen_binary (MULT, m, temp,
+                                     simplify_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 = simplify_gen_binary (op, m, gen_lowpart (m, z), temp);
 
          if (extend_op != NIL)
            temp = simplify_gen_unary (extend_op, mode, temp, m);
@@ -5095,7 +4928,16 @@ simplify_if_then_else (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)
+    return XEXP (cond, 0);
 
   return x;
 }
@@ -5103,8 +4945,7 @@ simplify_if_then_else (x)
 /* Simplify X, a SET expression.  Return the new expression.  */
 
 static rtx
-simplify_set (x)
-     rtx x;
+simplify_set (rtx x)
 {
   rtx src = SET_SRC (x);
   rtx dest = SET_DEST (x);
@@ -5136,7 +4977,7 @@ simplify_set (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);
@@ -5144,22 +4985,23 @@ simplify_set (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;
@@ -5180,15 +5022,17 @@ simplify_set (x)
        }
 
       /* Simplify our comparison, if possible.  */
-      new_code = simplify_comparison (old_code, &op0, &op1);
+      new_code = simplify_comparison (new_code, &op0, &op1);
 
-#ifdef EXTRA_CC_MODES
+#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);
-#endif /* EXTRA_CC_MODES */
+      if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
+       compare_mode = GET_MODE (op0);
+      else
+       compare_mode = SELECT_CC_MODE (new_code, op0, op1);
 
-#if !defined (HAVE_cc0) && defined (EXTRA_CC_MODES)
+#ifndef HAVE_cc0
       /* If the mode changed, we have to change SET_DEST, the mode in the
         compare, and the mode in the place SET_DEST is used.  If SET_DEST is
         a hard register, just build new versions with the proper mode.  If it
@@ -5212,16 +5056,19 @@ simplify_set (x)
              dest = new_dest;
            }
        }
-#endif
+#endif  /* cc0 */
+#endif  /* SELECT_CC_MODE */
 
       /* If the code changed, we have to build a new comparison in
         undobuf.other_insn.  */
       if (new_code != old_code)
        {
+         int other_changed_previously = other_changed;
          unsigned HOST_WIDE_INT mask;
 
          SUBST (*cc_use, gen_rtx_fmt_ee (new_code, GET_MODE (*cc_use),
                                          dest, const0_rtx));
+         other_changed = 1;
 
          /* If the only change we made was to change an EQ into an NE or
             vice versa, OP0 has only one bit that might be nonzero, and OP1
@@ -5231,7 +5078,7 @@ simplify_set (x)
 
          if (((old_code == NE && new_code == EQ)
               || (old_code == EQ && new_code == NE))
-             && ! other_changed && op1 == const0_rtx
+             && ! other_changed_previously && op1 == const0_rtx
              && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT
              && exact_log2 (mask = nonzero_bits (op0, GET_MODE (op0))) >= 0)
            {
@@ -5241,13 +5088,12 @@ simplify_set (x)
                   && ! check_asm_operands (pat)))
                {
                  PUT_CODE (*cc_use, old_code);
-                 other_insn = 0;
+                 other_changed = 0;
 
-                 op0 = gen_binary (XOR, GET_MODE (op0), op0, GEN_INT (mask));
+                 op0 = simplify_gen_binary (XOR, GET_MODE (op0),
+                                            op0, GEN_INT (mask));
                }
            }
-
-         other_changed = 1;
        }
 
       if (other_changed)
@@ -5299,19 +5145,19 @@ simplify_set (x)
      as long as M1 and M2 have the same number of words.  */
 
   if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
-      && GET_RTX_CLASS (GET_CODE (SUBREG_REG (src))) != 'o'
+      && !OBJECT_P (SUBREG_REG (src))
       && (((GET_MODE_SIZE (GET_MODE (src)) + (UNITS_PER_WORD - 1))
           / UNITS_PER_WORD)
          == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
               + (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))))
+        < 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),
-                                        GET_MODE (SUBREG_REG (src)), 
+                                        GET_MODE (SUBREG_REG (src)),
                                         GET_MODE (src)))
 #endif
       && (GET_CODE (dest) == REG
@@ -5319,7 +5165,7 @@ simplify_set (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));
 
@@ -5363,8 +5209,8 @@ simplify_set (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);
     }
@@ -5409,18 +5255,19 @@ simplify_set (x)
               && rtx_equal_p (XEXP (false_rtx, 1), true_rtx))
        term1 = true_rtx, false_rtx = XEXP (false_rtx, 0), true_rtx = const0_rtx;
 
-      term2 = gen_binary (AND, GET_MODE (src),
-                         XEXP (XEXP (src, 0), 0), true_rtx);
-      term3 = gen_binary (AND, GET_MODE (src),
-                         simplify_gen_unary (NOT, GET_MODE (src),
-                                             XEXP (XEXP (src, 0), 0),
-                                             GET_MODE (src)),
-                         false_rtx);
+      term2 = simplify_gen_binary (AND, GET_MODE (src),
+                                  XEXP (XEXP (src, 0), 0), true_rtx);
+      term3 = simplify_gen_binary (AND, GET_MODE (src),
+                                  simplify_gen_unary (NOT, GET_MODE (src),
+                                                      XEXP (XEXP (src, 0), 0),
+                                                      GET_MODE (src)),
+                                  false_rtx);
 
       SUBST (SET_SRC (x),
-            gen_binary (IOR, GET_MODE (src),
-                        gen_binary (IOR, GET_MODE (src), term1, term2),
-                        term3));
+            simplify_gen_binary (IOR, GET_MODE (src),
+                                 simplify_gen_binary (IOR, GET_MODE (src),
+                                                      term1, term2),
+                                 term3));
 
       src = SET_SRC (x);
     }
@@ -5437,12 +5284,10 @@ simplify_set (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 (x, last)
-     rtx x;
-     int last;
+simplify_logical (rtx x)
 {
   enum machine_mode mode = GET_MODE (x);
   rtx op0 = XEXP (x, 0);
@@ -5457,29 +5302,31 @@ simplify_logical (x, last)
       if (GET_CODE (op0) == XOR
          && rtx_equal_p (XEXP (op0, 0), op1)
          && ! side_effects_p (op1))
-       x = gen_binary (AND, mode,
-                       simplify_gen_unary (NOT, mode, XEXP (op0, 1), mode),
-                       op1);
+       x = simplify_gen_binary (AND, mode,
+                                simplify_gen_unary (NOT, mode,
+                                                    XEXP (op0, 1), mode),
+                                op1);
 
       if (GET_CODE (op0) == XOR
          && rtx_equal_p (XEXP (op0, 1), op1)
          && ! side_effects_p (op1))
-       x = gen_binary (AND, mode,
-                       simplify_gen_unary (NOT, mode, XEXP (op0, 0), mode),
-                       op1);
+       x = simplify_gen_binary (AND, mode,
+                                simplify_gen_unary (NOT, mode,
+                                                    XEXP (op0, 0), mode),
+                                op1);
 
       /* Similarly for (~(A ^ B)) & A.  */
       if (GET_CODE (op0) == NOT
          && GET_CODE (XEXP (op0, 0)) == XOR
          && rtx_equal_p (XEXP (XEXP (op0, 0), 0), op1)
          && ! side_effects_p (op1))
-       x = gen_binary (AND, mode, XEXP (XEXP (op0, 0), 1), op1);
+       x = simplify_gen_binary (AND, mode, XEXP (XEXP (op0, 0), 1), op1);
 
       if (GET_CODE (op0) == NOT
          && GET_CODE (XEXP (op0, 0)) == XOR
          && rtx_equal_p (XEXP (XEXP (op0, 0), 1), op1)
          && ! side_effects_p (op1))
-       x = gen_binary (AND, mode, XEXP (XEXP (op0, 0), 0), op1);
+       x = simplify_gen_binary (AND, mode, XEXP (XEXP (op0, 0), 0), op1);
 
       /* We can call simplify_and_const_int only if we don't lose
         any (sign) bits when converting INTVAL (op1) to
@@ -5492,22 +5339,24 @@ simplify_logical (x, 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)
-           return gen_binary (IOR, mode,
-                              gen_binary (AND, mode, XEXP (op0, 0),
+             && GET_CODE (op1) == CONST_INT
+             && (INTVAL (XEXP (op0, 1)) & INTVAL (op1)) != 0)
+           return simplify_gen_binary (IOR, mode,
+                                       simplify_gen_binary
+                                         (AND, mode, XEXP (op0, 0),
                                           GEN_INT (INTVAL (XEXP (op0, 1))
                                                    & ~INTVAL (op1))), op1);
 
          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.  */
@@ -5518,54 +5367,16 @@ simplify_logical (x, last)
          && ! side_effects_p (XEXP (op0, 1)))
        return op1;
 
-      /* In the following group of tests (and those in case IOR below),
-        we start with some combination of logical operations and apply
-        the distributive law followed by the inverse distributive law.
-        Most of the time, this results in no change.  However, if some of
-        the operands are the same or inverses of each other, simplifications
-        will result.
-
-        For example, (and (ior A B) (not B)) can occur as the result of
-        expanding a bit field assignment.  When we apply the distributive
-        law to this, we get (ior (and (A (not B))) (and (B (not B)))),
-        which then simplifies to (and (A (not B))).
-
-        If we have (and (ior A B) C), apply the distributive law and then
-        the inverse distributive law to see if things simplify.  */
-
-      if (GET_CODE (op0) == IOR || GET_CODE (op0) == XOR)
+      /* If we have any of (and (ior A B) C) or (and (xor A B) C),
+        apply the distributive law and then the inverse distributive
+        law to see if things simplify.  */
+      if (GET_CODE (op0) == IOR || GET_CODE (op0) == XOR
+          || GET_CODE (op1) == IOR || GET_CODE (op1) == XOR)
        {
-         x = apply_distributive_law
-           (gen_binary (GET_CODE (op0), mode,
-                        gen_binary (AND, mode, XEXP (op0, 0), op1),
-                        gen_binary (AND, mode, XEXP (op0, 1),
-                                    copy_rtx (op1))));
-         if (GET_CODE (x) != AND)
-           return x;
+         rtx result = distribute_and_simplify_rtx (x);
+         if (result)
+           return result;
        }
-
-      if (GET_CODE (op1) == IOR || GET_CODE (op1) == XOR)
-       return apply_distributive_law
-         (gen_binary (GET_CODE (op1), mode,
-                      gen_binary (AND, mode, XEXP (op1, 0), op0),
-                      gen_binary (AND, mode, XEXP (op1, 1),
-                                  copy_rtx (op0))));
-
-      /* Similarly, taking advantage of the fact that
-        (and (not A) (xor B C)) == (xor (ior A B) (ior A C))  */
-
-      if (GET_CODE (op0) == NOT && GET_CODE (op1) == XOR)
-       return apply_distributive_law
-         (gen_binary (XOR, mode,
-                      gen_binary (IOR, mode, XEXP (op0, 0), XEXP (op1, 0)),
-                      gen_binary (IOR, mode, copy_rtx (XEXP (op0, 0)),
-                                  XEXP (op1, 1))));
-
-      else if (GET_CODE (op1) == NOT && GET_CODE (op0) == XOR)
-       return apply_distributive_law
-         (gen_binary (XOR, mode,
-                      gen_binary (IOR, mode, XEXP (op1, 0), XEXP (op0, 0)),
-                      gen_binary (IOR, mode, copy_rtx (XEXP (op1, 0)), XEXP (op0, 1))));
       break;
 
     case IOR:
@@ -5586,28 +5397,11 @@ simplify_logical (x, last)
       /* If we have (ior (and A B) C), apply the distributive law and then
         the inverse distributive law to see if things simplify.  */
 
-      if (GET_CODE (op0) == AND)
-       {
-         x = apply_distributive_law
-           (gen_binary (AND, mode,
-                        gen_binary (IOR, mode, XEXP (op0, 0), op1),
-                        gen_binary (IOR, mode, XEXP (op0, 1),
-                                    copy_rtx (op1))));
-
-         if (GET_CODE (x) != IOR)
-           return x;
-       }
-
-      if (GET_CODE (op1) == AND)
+      if (GET_CODE (op0) == AND || GET_CODE (op1) == AND)
        {
-         x = apply_distributive_law
-           (gen_binary (AND, mode,
-                        gen_binary (IOR, mode, XEXP (op1, 0), op0),
-                        gen_binary (IOR, mode, XEXP (op1, 1),
-                                    copy_rtx (op0))));
-
-         if (GET_CODE (x) != IOR)
-           return x;
+         rtx result = distribute_and_simplify_rtx (x);
+         if (result)
+           return result;
        }
 
       /* Convert (ior (ashift A CX) (lshiftrt A CY)) where CX+CY equals the
@@ -5656,7 +5450,7 @@ simplify_logical (x, last)
       if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
          && (nonzero_bits (op0, mode)
              & nonzero_bits (op1, mode)) == 0)
-       return (gen_binary (IOR, mode, op0, op1));
+       return (simplify_gen_binary (IOR, mode, op0, op1));
 
       /* Convert (XOR (NOT x) (NOT y)) to (XOR x y).
         Also convert (XOR (NOT x) y) to (NOT (XOR x y)), similarly for
@@ -5676,7 +5470,8 @@ simplify_logical (x, last)
          }
        else if (num_negated == 1)
          return
-           simplify_gen_unary (NOT, mode, gen_binary (XOR, mode, op0, op1),
+           simplify_gen_unary (NOT, mode,
+                               simplify_gen_binary (XOR, mode, op0, op1),
                                mode);
       }
 
@@ -5687,22 +5482,24 @@ simplify_logical (x, last)
       if (GET_CODE (op0) == AND
          && rtx_equal_p (XEXP (op0, 1), op1)
          && ! side_effects_p (op1))
-       return gen_binary (AND, mode,
-                          simplify_gen_unary (NOT, mode, XEXP (op0, 0), mode),
-                          op1);
+       return simplify_gen_binary (AND, mode,
+                                   simplify_gen_unary (NOT, mode,
+                                                       XEXP (op0, 0), mode),
+                                   op1);
 
       else if (GET_CODE (op0) == AND
               && rtx_equal_p (XEXP (op0, 0), op1)
               && ! side_effects_p (op1))
-       return gen_binary (AND, mode,
-                          simplify_gen_unary (NOT, mode, XEXP (op0, 1), mode),
-                          op1);
+       return simplify_gen_binary (AND, mode,
+                                   simplify_gen_unary (NOT, mode,
+                                                       XEXP (op0, 1), mode),
+                                   op1);
 
       /* (xor (comparison foo bar) (const_int 1)) can become the reversed
         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;
@@ -5724,7 +5521,7 @@ simplify_logical (x, 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;
@@ -5752,8 +5549,7 @@ simplify_logical (x, last)
    It is the inverse of this function, loosely speaking.  */
 
 static rtx
-expand_compound_operation (x)
-     rtx x;
+expand_compound_operation (rtx x)
 {
   unsigned HOST_WIDE_INT pos = 0, len;
   int unsignedp = 0;
@@ -5850,7 +5646,15 @@ expand_compound_operation (x)
               == 0)))
     {
       rtx temp = gen_rtx_ZERO_EXTEND (GET_MODE (x), XEXP (x, 0));
-      return expand_compound_operation (temp);
+      rtx temp2 = expand_compound_operation (temp);
+
+      /* Make sure this is a profitable operation.  */
+      if (rtx_cost (x, SET) > rtx_cost (temp2, SET))
+       return temp2;
+      else if (rtx_cost (x, SET) > rtx_cost (temp, SET))
+       return temp;
+      else
+       return x;
     }
 
   /* We can optimize some special cases of ZERO_EXTEND.  */
@@ -5881,7 +5685,7 @@ expand_compound_operation (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
@@ -5892,7 +5696,7 @@ expand_compound_operation (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
@@ -5953,13 +5757,12 @@ expand_compound_operation (x)
    support variable lengths.  */
 
 static rtx
-expand_field_assignment (x)
-     rtx x;
+expand_field_assignment (rtx x)
 {
   rtx inner;
   rtx pos;                     /* Always counts from low bit.  */
   int len;
-  rtx mask;
+  rtx mask, cleared, masked;
   enum machine_mode compute_mode;
 
   /* Loop until we find something we can't simplify.  */
@@ -5997,10 +5800,11 @@ expand_field_assignment (x)
                /* If position is ADJUST - X, new position is X.  */
                pos = XEXP (pos, 0);
              else
-               pos = gen_binary (MINUS, GET_MODE (pos),
-                                 GEN_INT (GET_MODE_BITSIZE (GET_MODE (inner))
-                                          - len),
-                                 pos);
+               pos = simplify_gen_binary (MINUS, GET_MODE (pos),
+                                          GEN_INT (GET_MODE_BITSIZE (
+                                                   GET_MODE (inner))
+                                                   - len),
+                                          pos);
            }
        }
 
@@ -6015,7 +5819,7 @@ expand_field_assignment (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;
@@ -6043,34 +5847,34 @@ expand_field_assignment (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.  */
-      if (len < HOST_BITS_PER_WIDE_INT)
-       mask = GEN_INT (((HOST_WIDE_INT) 1 << len) - 1);
-      else
+      if (len >= HOST_BITS_PER_WIDE_INT)
        break;
 
       /* Now compute the equivalent expression.  Make a copy of INNER
         for the SET_DEST in case it is a MEM into which we will substitute;
         we don't want shared RTL in that case.  */
-      x = gen_rtx_SET
-       (VOIDmode, copy_rtx (inner),
-        gen_binary (IOR, compute_mode,
-                    gen_binary (AND, compute_mode,
-                                simplify_gen_unary (NOT, compute_mode,
-                                                    gen_binary (ASHIFT,
-                                                                compute_mode,
-                                                                mask, pos),
-                                                    compute_mode),
-                                inner),
-                    gen_binary (ASHIFT, compute_mode,
-                                gen_binary (AND, compute_mode,
-                                            gen_lowpart_for_combine
-                                            (compute_mode, SET_SRC (x)),
-                                            mask),
-                                pos)));
+      mask = GEN_INT (((HOST_WIDE_INT) 1 << len) - 1);
+      cleared = simplify_gen_binary (AND, compute_mode,
+                                    simplify_gen_unary (NOT, compute_mode,
+                                      simplify_gen_binary (ASHIFT,
+                                                           compute_mode,
+                                                           mask, pos),
+                                      compute_mode),
+                                    inner);
+      masked = simplify_gen_binary (ASHIFT, compute_mode,
+                                   simplify_gen_binary (
+                                     AND, compute_mode,
+                                     gen_lowpart (compute_mode, SET_SRC (x)),
+                                     mask),
+                                   pos);
+
+      x = gen_rtx_SET (VOIDmode, copy_rtx (inner),
+                      simplify_gen_binary (IOR, compute_mode,
+                                           cleared, masked));
     }
 
   return x;
@@ -6104,15 +5908,9 @@ expand_field_assignment (x)
    can't handle it.  */
 
 static rtx
-make_extraction (mode, inner, pos, pos_rtx, len,
-                unsignedp, in_dest, in_compare)
-     enum machine_mode mode;
-     rtx inner;
-     HOST_WIDE_INT pos;
-     rtx pos_rtx;
-     unsigned HOST_WIDE_INT len;
-     int unsignedp;
-     int in_dest, in_compare;
+make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
+                rtx pos_rtx, unsigned HOST_WIDE_INT len, int unsignedp,
+                int in_dest, int in_compare)
 {
   /* This mode describes the size of the storage area
      to fetch the overall value from.  Within that, we
@@ -6219,30 +6017,36 @@ make_extraction (mode, inner, pos, pos_rtx, len,
        }
       else if (GET_CODE (inner) == REG)
        {
-         /* We can't call gen_lowpart_for_combine here since we always want
-            a SUBREG and it would sometimes return a new hard register.  */
          if (tmode != inner_mode)
            {
-             HOST_WIDE_INT final_word = pos / BITS_PER_WORD;
-
-             if (WORDS_BIG_ENDIAN
-                 && GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD)
-               final_word = ((GET_MODE_SIZE (inner_mode)
-                              - GET_MODE_SIZE (tmode))
-                             / UNITS_PER_WORD) - final_word;
-
-             final_word *= UNITS_PER_WORD;
-             if (BYTES_BIG_ENDIAN &&
-                 GET_MODE_SIZE (inner_mode) > GET_MODE_SIZE (tmode))
-               final_word += (GET_MODE_SIZE (inner_mode)
-                              - GET_MODE_SIZE (tmode)) % UNITS_PER_WORD;
-
-             /* Avoid creating invalid subregs, for example when
-                simplifying (x>>32)&255.  */
-             if (final_word >= GET_MODE_SIZE (inner_mode))
-               return NULL_RTX;
-
-             new = gen_rtx_SUBREG (tmode, inner, final_word);
+             /* 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)
+               {
+                 HOST_WIDE_INT final_word = pos / BITS_PER_WORD;
+
+                 if (WORDS_BIG_ENDIAN
+                     && GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD)
+                   final_word = ((GET_MODE_SIZE (inner_mode)
+                                  - GET_MODE_SIZE (tmode))
+                                 / UNITS_PER_WORD) - final_word;
+
+                 final_word *= UNITS_PER_WORD;
+                 if (BYTES_BIG_ENDIAN &&
+                     GET_MODE_SIZE (inner_mode) > GET_MODE_SIZE (tmode))
+                   final_word += (GET_MODE_SIZE (inner_mode)
+                                  - GET_MODE_SIZE (tmode)) % UNITS_PER_WORD;
+
+                 /* Avoid creating invalid subregs, for example when
+                    simplifying (x>>32)&255.  */
+                 if (final_word >= GET_MODE_SIZE (inner_mode))
+                   return NULL_RTX;
+
+                 new = gen_rtx_SUBREG (tmode, inner, final_word);
+               }
+             else
+               new = gen_lowpart (tmode, inner);
            }
          else
            new = inner;
@@ -6472,7 +6276,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
     }
   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
@@ -6487,7 +6291,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
   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;
 }
@@ -6496,9 +6300,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
    with any other operations in X.  Return X without that shift if so.  */
 
 static rtx
-extract_left_shift (x, count)
-     rtx x;
-     int count;
+extract_left_shift (rtx x, int count)
 {
   enum rtx_code code = GET_CODE (x);
   enum machine_mode mode = GET_MODE (x);
@@ -6528,8 +6330,8 @@ extract_left_shift (x, count)
       if (GET_CODE (XEXP (x, 1)) == CONST_INT
          && (INTVAL (XEXP (x, 1)) & ((((HOST_WIDE_INT) 1 << count)) - 1)) == 0
          && (tem = extract_left_shift (XEXP (x, 0), count)) != 0)
-       return gen_binary (code, mode, tem,
-                          GEN_INT (INTVAL (XEXP (x, 1)) >> count));
+       return simplify_gen_binary (code, mode, tem,
+                                   GEN_INT (INTVAL (XEXP (x, 1)) >> count));
 
       break;
 
@@ -6559,9 +6361,7 @@ extract_left_shift (x, count)
    or a COMPARE against zero, it is COMPARE.  */
 
 static rtx
-make_compound_operation (x, in_code)
-     rtx x;
-     enum rtx_code in_code;
+make_compound_operation (rtx x, enum rtx_code in_code)
 {
   enum rtx_code code = GET_CODE (x);
   enum machine_mode mode = GET_MODE (x);
@@ -6578,7 +6378,7 @@ make_compound_operation (x, 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);
 
@@ -6744,9 +6544,9 @@ make_compound_operation (x, 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)
@@ -6794,7 +6594,7 @@ make_compound_operation (x, 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;
@@ -6805,7 +6605,7 @@ make_compound_operation (x, in_code)
 
   if (new)
     {
-      x = gen_lowpart_for_combine (mode, new);
+      x = gen_lowpart (mode, new);
       code = GET_CODE (x);
     }
 
@@ -6829,23 +6629,19 @@ make_compound_operation (x, in_code)
    *PLEN is set to the length of the field.  */
 
 static int
-get_pos_from_mask (m, plen)
-     unsigned HOST_WIDE_INT m;
-     unsigned HOST_WIDE_INT *plen;
+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;
+  int len = 0;
 
-  if (pos < 0)
-    return -1;
-
-  /* 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;
@@ -6868,12 +6664,8 @@ get_pos_from_mask (m, plen)
    NOT, NEG, or XOR.  */
 
 static rtx
-force_to_mode (x, mode, mask, reg, just_select)
-     rtx x;
-     enum machine_mode mode;
-     unsigned HOST_WIDE_INT mask;
-     rtx reg;
-     int just_select;
+force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
+              rtx reg, int just_select)
 {
   enum rtx_code code = GET_CODE (x);
   int next_select = just_select || code == XOR || code == NOT || code == NEG;
@@ -6886,7 +6678,7 @@ force_to_mode (x, mode, mask, reg, just_select)
      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;
 
@@ -6908,15 +6700,13 @@ force_to_mode (x, mode, mask, reg, just_select)
     mask &= GET_MODE_MASK (op_mode);
 
   /* When we have an arithmetic operation, or a shift whose count we
-     do not know, we need to assume that all bit the up to the highest-order
+     do not know, we need to assume that all bits up to the highest-order
      bit in MASK will be needed.  This is how we form such a mask.  */
-  if (op_mode)
-    fuller_mask = (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT
-                  ? GET_MODE_MASK (op_mode)
-                  : (((unsigned HOST_WIDE_INT) 1 << (floor_log2 (mask) + 1))
-                     - 1));
+  if (mask & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)))
+    fuller_mask = ~(unsigned HOST_WIDE_INT) 0;
   else
-    fuller_mask = ~(HOST_WIDE_INT) 0;
+    fuller_mask = (((unsigned HOST_WIDE_INT) 1 << (floor_log2 (mask) + 1))
+                  - 1);
 
   /* Determine what bits of X are guaranteed to be (non)zero.  */
   nonzero = nonzero_bits (x, mode);
@@ -6942,7 +6732,7 @@ force_to_mode (x, mode, mask, reg, just_select)
      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.  */
@@ -7026,13 +6816,14 @@ force_to_mode (x, mode, mask, reg, just_select)
              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)
                cval |= (HOST_WIDE_INT) -1 << width;
 
-             y = gen_binary (AND, GET_MODE (x), XEXP (x, 0), GEN_INT (cval));
+             y = simplify_gen_binary (AND, GET_MODE (x),
+                                      XEXP (x, 0), GEN_INT (cval));
              if (rtx_cost (y, SET) < rtx_cost (x, SET))
                x = y;
            }
@@ -7124,10 +6915,10 @@ force_to_mode (x, mode, mask, reg, just_select)
        {
          temp = GEN_INT ((INTVAL (XEXP (x, 1)) & mask)
                          << INTVAL (XEXP (XEXP (x, 0), 1)));
-         temp = gen_binary (GET_CODE (x), GET_MODE (x),
-                            XEXP (XEXP (x, 0), 0), temp);
-         x = gen_binary (LSHIFTRT, GET_MODE (x), temp,
-                         XEXP (XEXP (x, 0), 1));
+         temp = simplify_gen_binary (GET_CODE (x), GET_MODE (x),
+                                     XEXP (XEXP (x, 0), 0), temp);
+         x = simplify_gen_binary (LSHIFTRT, GET_MODE (x), temp,
+                                  XEXP (XEXP (x, 0), 1));
          return force_to_mode (x, mode, mask, reg, next_select);
        }
 
@@ -7135,15 +6926,15 @@ force_to_mode (x, mode, mask, reg, just_select)
       /* 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);
+       x = simplify_gen_binary (code, op_mode, op0, op1);
       break;
 
     case ASHIFT:
@@ -7172,12 +6963,12 @@ force_to_mode (x, mode, mask, reg, just_select)
       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));
+       x = simplify_gen_binary (code, op_mode, op0, XEXP (x, 1));
       break;
 
     case LSHIFTRT:
@@ -7205,7 +6996,7 @@ force_to_mode (x, mode, mask, reg, just_select)
          inner = force_to_mode (inner, op_mode, inner_mask, reg, next_select);
 
          if (GET_MODE (x) != op_mode || inner != XEXP (x, 0))
-           x = gen_binary (LSHIFTRT, op_mode, inner, XEXP (x, 1));
+           x = simplify_gen_binary (LSHIFTRT, op_mode, inner, XEXP (x, 1));
        }
 
       /* If we have (and (lshiftrt FOO C1) C2) where the combination of the
@@ -7227,9 +7018,9 @@ force_to_mode (x, mode, mask, reg, just_select)
          /* Must be more sign bit copies than the mask needs.  */
          && ((int) num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
              >= exact_log2 (mask + 1)))
-       x = gen_binary (LSHIFTRT, GET_MODE (x), XEXP (x, 0),
-                       GEN_INT (GET_MODE_BITSIZE (GET_MODE (x))
-                                - exact_log2 (mask + 1)));
+       x = simplify_gen_binary (LSHIFTRT, GET_MODE (x), XEXP (x, 0),
+                                GEN_INT (GET_MODE_BITSIZE (GET_MODE (x))
+                                         - exact_log2 (mask + 1)));
 
       goto shiftrt;
 
@@ -7294,7 +7085,8 @@ force_to_mode (x, mode, mask, reg, just_select)
       /* If MASK is 1, convert this to an LSHIFTRT.  This can be done
         even if the shift count isn't a constant.  */
       if (mask == 1)
-       x = gen_binary (LSHIFTRT, GET_MODE (x), XEXP (x, 0), XEXP (x, 1));
+       x = simplify_gen_binary (LSHIFTRT, GET_MODE (x),
+                                XEXP (x, 0), XEXP (x, 1));
 
     shiftrt:
 
@@ -7308,8 +7100,7 @@ force_to_mode (x, mode, mask, reg, just_select)
          && (INTVAL (XEXP (x, 1))
              <= GET_MODE_BITSIZE (GET_MODE (x)) - (floor_log2 (mask) + 1))
          && GET_CODE (XEXP (x, 0)) == ASHIFT
-         && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
-         && INTVAL (XEXP (XEXP (x, 0), 1)) == INTVAL (XEXP (x, 1)))
+         && XEXP (XEXP (x, 0), 1) == XEXP (x, 1))
        return force_to_mode (XEXP (XEXP (x, 0), 0), mode, mask,
                              reg, next_select);
 
@@ -7360,8 +7151,10 @@ force_to_mode (x, mode, mask, reg, just_select)
        {
          temp = gen_int_mode (mask << INTVAL (XEXP (XEXP (x, 0), 1)),
                               GET_MODE (x));
-         temp = gen_binary (XOR, GET_MODE (x), XEXP (XEXP (x, 0), 0), temp);
-         x = gen_binary (LSHIFTRT, GET_MODE (x), temp, XEXP (XEXP (x, 0), 1));
+         temp = simplify_gen_binary (XOR, GET_MODE (x),
+                                     XEXP (XEXP (x, 0), 0), temp);
+         x = simplify_gen_binary (LSHIFTRT, GET_MODE (x),
+                                  temp, XEXP (XEXP (x, 0), 1));
 
          return force_to_mode (x, mode, mask, reg, next_select);
        }
@@ -7371,9 +7164,9 @@ force_to_mode (x, mode, mask, reg, just_select)
       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;
@@ -7395,11 +7188,11 @@ force_to_mode (x, mode, mask, reg, just_select)
         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;
@@ -7409,7 +7202,7 @@ force_to_mode (x, mode, mask, reg, just_select)
     }
 
   /* 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
@@ -7420,9 +7213,7 @@ force_to_mode (x, mode, mask, reg, just_select)
    If we return zero, we set *PTRUE and *PFALSE to X.  */
 
 static rtx
-if_then_else_cond (x, ptrue, pfalse)
-     rtx x;
-     rtx *ptrue, *pfalse;
+if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
 {
   enum machine_mode mode = GET_MODE (x);
   enum rtx_code code = GET_CODE (x);
@@ -7431,7 +7222,7 @@ if_then_else_cond (x, ptrue, pfalse)
 
   /* If we are comparing a value against zero, we are done.  */
   if ((code == NE || code == EQ)
-      && GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 0)
+      && XEXP (x, 1) == const0_rtx)
     {
       *ptrue = (code == NE) ? const_true_rtx : const0_rtx;
       *pfalse = (code == NE) ? const0_rtx : const_true_rtx;
@@ -7440,7 +7231,7 @@ if_then_else_cond (x, ptrue, 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)));
@@ -7457,8 +7248,7 @@ if_then_else_cond (x, ptrue, 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);
@@ -7474,8 +7264,19 @@ if_then_else_cond (x, ptrue, pfalse)
          else if (cond1 == 0)
            true1 = copy_rtx (true1);
 
-         *ptrue = gen_binary (code, mode, true0, true1);
-         *pfalse = gen_binary (code, mode, false0, false1);
+         if (COMPARISON_P (x))
+           {
+             *ptrue = simplify_gen_relational (code, mode, VOIDmode,
+                                               true0, true1);
+             *pfalse = simplify_gen_relational (code, mode, VOIDmode,
+                                                false0, false1);
+            }
+         else
+           {
+             *ptrue = simplify_gen_binary (code, mode, true0, true1);
+             *pfalse = simplify_gen_binary (code, mode, false0, false1);
+           }
+
          return cond0 ? cond0 : cond1;
        }
 
@@ -7494,8 +7295,8 @@ if_then_else_cond (x, ptrue, 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)))
@@ -7505,13 +7306,13 @@ if_then_else_cond (x, ptrue, pfalse)
                      && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 0))))
              && ! side_effects_p (x))
            {
-             *ptrue = gen_binary (MULT, mode, op0, const_true_rtx);
-             *pfalse = gen_binary (MULT, mode,
-                                   (code == MINUS
-                                    ? simplify_gen_unary (NEG, mode, op1,
-                                                          mode)
-                                    : op1),
-                                   const_true_rtx);
+             *ptrue = simplify_gen_binary (MULT, mode, op0, const_true_rtx);
+             *pfalse = simplify_gen_binary (MULT, mode,
+                                            (code == MINUS
+                                             ? simplify_gen_unary (NEG, mode,
+                                                                   op1, mode)
+                                             : op1),
+                                             const_true_rtx);
              return cond0;
            }
        }
@@ -7525,8 +7326,8 @@ if_then_else_cond (x, ptrue, 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)))
@@ -7565,12 +7366,16 @@ if_then_else_cond (x, ptrue, 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
@@ -7598,7 +7403,7 @@ if_then_else_cond (x, ptrue, pfalse)
     }
 
   /* Likewise for 0 or a single bit.  */
-  else if (mode != VOIDmode
+  else if (SCALAR_INT_MODE_P (mode)
           && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
           && exact_log2 (nz = nonzero_bits (x, mode)) >= 0)
     {
@@ -7620,10 +7425,7 @@ if_then_else_cond (x, ptrue, pfalse)
    arise with IF_THEN_ELSE expressions.  */
 
 static rtx
-known_cond (x, cond, reg, val)
-     rtx x;
-     enum rtx_code cond;
-     rtx reg, val;
+known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val)
 {
   enum rtx_code code = GET_CODE (x);
   rtx temp;
@@ -7663,14 +7465,14 @@ known_cond (x, cond, reg, 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;
@@ -7774,9 +7576,7 @@ known_cond (x, cond, reg, val)
    assignment as a field assignment.  */
 
 static int
-rtx_equal_for_field_assignment_p (x, y)
-     rtx x;
-     rtx y;
+rtx_equal_for_field_assignment_p (rtx x, rtx y)
 {
   if (x == y || rtx_equal_p (x, y))
     return 1;
@@ -7790,13 +7590,13 @@ rtx_equal_for_field_assignment_p (x, 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
@@ -7813,8 +7613,7 @@ rtx_equal_for_field_assignment_p (x, y)
    We only handle the most common cases.  */
 
 static rtx
-make_field_assignment (x)
-     rtx x;
+make_field_assignment (rtx x)
 {
   rtx dest = SET_DEST (x);
   rtx src = SET_SRC (x);
@@ -7848,6 +7647,7 @@ make_field_assignment (x)
           && (GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
               < GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (src, 0)))))
           && GET_CODE (SUBREG_REG (XEXP (src, 0))) == ROTATE
+          && GET_CODE (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == CONST_INT
           && INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2
           && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
     {
@@ -7930,7 +7730,7 @@ make_field_assignment (x)
       && INTVAL (XEXP (assign, 1)) < HOST_BITS_PER_WIDE_INT
       && GET_CODE (src) == AND
       && GET_CODE (XEXP (src, 1)) == CONST_INT
-      && (INTVAL (XEXP (src, 1))
+      && ((unsigned HOST_WIDE_INT) INTVAL (XEXP (src, 1))
          == ((unsigned HOST_WIDE_INT) 1 << INTVAL (XEXP (assign, 1))) - 1))
     src = XEXP (src, 0);
 
@@ -7941,18 +7741,17 @@ make_field_assignment (x)
    if so.  */
 
 static rtx
-apply_distributive_law (x)
-     rtx x;
+apply_distributive_law (rtx x)
 {
   enum rtx_code code = GET_CODE (x);
+  enum rtx_code inner_code;
   rtx lhs, rhs, other;
   rtx tem;
-  enum rtx_code inner_code;
 
-  /* Distributivity is not true for floating point.
-     It can change the value.  So don't do it.
-     -- rms and moshier@world.std.com.  */
-  if (FLOAT_MODE_P (GET_MODE (x)))
+  /* Distributivity is not true for floating point as it can change the
+     value.  So we don't do it unless -funsafe-math-optimizations.  */
+  if (FLOAT_MODE_P (GET_MODE (x))
+      && ! flag_unsafe_math_optimizations)
     return x;
 
   /* The outer operation can only be one of the following:  */
@@ -7960,12 +7759,12 @@ apply_distributive_law (x)
       && code != PLUS && code != MINUS)
     return x;
 
-  lhs = XEXP (x, 0), rhs = XEXP (x, 1);
+  lhs = XEXP (x, 0);
+  rhs = XEXP (x, 1);
 
   /* 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);
@@ -8017,9 +7816,9 @@ apply_distributive_law (x)
          || GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs))) > UNITS_PER_WORD)
        return 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);
+      tem = simplify_gen_binary (code, GET_MODE (SUBREG_REG (lhs)),
+                                SUBREG_REG (lhs), SUBREG_REG (rhs));
+      return gen_lowpart (GET_MODE (x), tem);
 
     default:
       return x;
@@ -8027,15 +7826,15 @@ apply_distributive_law (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)))
@@ -8044,10 +7843,10 @@ apply_distributive_law (x)
     return x;
 
   /* Form the new inner operation, seeing if it simplifies first.  */
-  tem = gen_binary (code, GET_MODE (x), lhs, rhs);
+  tem = simplify_gen_binary (code, GET_MODE (x), lhs, rhs);
 
   /* There is one exception to the general way of distributing:
-     (a ^ b) | (a ^ c) -> (~a) & (b ^ c)  */
+     (a | c) ^ (b | c) -> (a ^ b) & ~c  */
   if (code == XOR && inner_code == IOR)
     {
       inner_code = AND;
@@ -8057,8 +7856,95 @@ apply_distributive_law (x)
   /* We may be able to continuing distributing the result, so call
      ourselves recursively on the inner operation before forming the
      outer operation, which we return.  */
-  return gen_binary (inner_code, GET_MODE (x),
-                    apply_distributive_law (tem), other);
+  return simplify_gen_binary (inner_code, GET_MODE (x),
+                             apply_distributive_law (tem), other);
+}
+
+/* See if X is of the form (* (+ a b) c), and if so convert to
+   (+ (* a c) (* b c)) and try to simplify.
+
+   Most of the time, this results in no change.  However, if some of
+   the operands are the same or inverses of each other, simplifications
+   will result.
+
+   For example, (and (ior A B) (not B)) can occur as the result of
+   expanding a bit field assignment.  When we apply the distributive
+   law to this, we get (ior (and (A (not B))) (and (B (not B)))),
+   which then simplifies to (and (A (not B))).
+   Note that no checks happen on the validity of applying the inverse
+   distributive law.  This is pointless since we can do it in the
+   few places where this routine is called.  */
+static rtx
+distribute_and_simplify_rtx (rtx x)
+{
+  enum machine_mode mode;
+  enum rtx_code outer, inner;
+  rtx op0, op1, inner_op0, inner_op1, new_op0, new_op1;
+
+  mode = GET_MODE (x);
+  outer = GET_CODE (x);
+  op0 = XEXP (x, 0);
+  op1 = XEXP (x, 1);
+  if (ARITHMETIC_P (op0))
+    {
+      inner = GET_CODE (op0);
+      inner_op0 = XEXP (op0, 0);
+      inner_op1 = XEXP (op0, 1);
+
+      /* (and (xor B C) (not A)) == (xor (ior A B) (ior A C))  */
+      if (outer == AND && inner == XOR && GET_CODE (op1) == NOT)
+        {
+         new_op0 = simplify_gen_binary (IOR, mode, inner_op0, op1);
+          new_op1 = simplify_gen_binary (IOR, mode, inner_op1, op1);
+          x = apply_distributive_law (simplify_gen_binary (XOR, mode,
+                                                          new_op0, new_op1));
+
+         if (GET_CODE (x) != AND)
+           return x;
+       }
+      else
+       {
+          new_op0 = simplify_gen_binary (outer, mode, inner_op0, op1);
+          new_op1 = simplify_gen_binary (outer, mode, inner_op1, op1);
+          x = apply_distributive_law (simplify_gen_binary (inner, mode,
+                                                          new_op0, new_op1));
+
+         if (GET_CODE (x) != outer)
+           return x;
+       }
+    }
+
+  if (ARITHMETIC_P (op1))
+    {
+      inner = GET_CODE (op1);
+      inner_op0 = XEXP (op1, 0);
+      inner_op1 = XEXP (op1, 1);
+
+      /* (and (not A) (xor B C)) == (xor (ior A B) (ior A C))  */
+      if (outer == AND && inner == XOR && GET_CODE (op0) == NOT)
+        {
+         new_op0 = simplify_gen_binary (IOR, mode, inner_op0, op0);
+          new_op1 = simplify_gen_binary (IOR, mode, inner_op1, op0);
+          x = apply_distributive_law (simplify_gen_binary (XOR, mode,
+                                                          new_op0, new_op1));
+
+         if (GET_CODE (x) != AND)
+           return x;
+       }
+      else
+       {
+          new_op0 = simplify_gen_binary (outer, mode, op0, inner_op0);
+          new_op1 = simplify_gen_binary (outer, mode, op0, inner_op1);
+          x = apply_distributive_law (simplify_gen_binary (inner, mode,
+                                                          new_op0, new_op1));
+
+         if (GET_CODE (x) != outer)
+           return x;
+       }
+    }
+
+  return NULL_RTX;
 }
 \f
 /* We have X, a logical `and' of VAROP with the constant CONSTOP, to be done
@@ -8068,11 +7954,8 @@ apply_distributive_law (x)
    X is zero, we are to always construct the equivalent form.  */
 
 static rtx
-simplify_and_const_int (x, mode, varop, constop)
-     rtx x;
-     enum machine_mode mode;
-     rtx varop;
-     unsigned HOST_WIDE_INT constop;
+simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
+                       unsigned HOST_WIDE_INT constop)
 {
   unsigned HOST_WIDE_INT nonzero;
   int i;
@@ -8125,14 +8008,18 @@ simplify_and_const_int (x, mode, varop, constop)
 
   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),
-                     simplify_and_const_int (NULL_RTX, GET_MODE (varop),
-                                             XEXP (varop, 0), constop),
-                     simplify_and_const_int (NULL_RTX, GET_MODE (varop),
-                                             XEXP (varop, 1), constop))));
+        (simplify_gen_binary (GET_CODE (varop), GET_MODE (varop),
+                              simplify_and_const_int (NULL_RTX,
+                                                      GET_MODE (varop),
+                                                      XEXP (varop, 0),
+                                                      constop),
+                              simplify_and_const_int (NULL_RTX,
+                                                      GET_MODE (varop),
+                                                      XEXP (varop, 1),
+                                                      constop))));
 
   /* If VAROP is PLUS, and the constant is a mask of low bite, distribute
      the AND and see if one of the operands simplifies to zero.  If so, we
@@ -8158,7 +8045,7 @@ simplify_and_const_int (x, mode, varop, constop)
       && 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)
@@ -8173,7 +8060,7 @@ simplify_and_const_int (x, mode, varop, constop)
       constop = trunc_int_for_mode (constop, mode);
       /* See how much, if any, of X we can use.  */
       if (x == 0 || GET_CODE (x) != AND || GET_MODE (x) != mode)
-       x = gen_binary (AND, mode, varop, GEN_INT (constop));
+       x = simplify_gen_binary (AND, mode, varop, GEN_INT (constop));
 
       else
        {
@@ -8188,591 +8075,78 @@ simplify_and_const_int (x, mode, varop, constop)
   return x;
 }
 \f
-#define nonzero_bits_with_known(X, MODE) \
-  cached_nonzero_bits (X, MODE, known_x, known_mode, known_ret)
-
-/* The function cached_nonzero_bits is a wrapper around nonzero_bits1.
-   It avoids exponential behavior in nonzero_bits1 when X has
-   identical subexpressions on the first or the second level.  */
-
-static unsigned HOST_WIDE_INT
-cached_nonzero_bits (x, mode, known_x, known_mode, known_ret)
-     rtx x;
-     enum machine_mode mode;
-     rtx known_x;
-     enum machine_mode known_mode;
-     unsigned HOST_WIDE_INT known_ret;
-{
-  if (x == known_x && mode == known_mode)
-    return known_ret;
-
-  /* Try to find identical subexpressions.  If found call
-     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')
-    {
-      rtx x0 = XEXP (x, 0);
-      rtx x1 = XEXP (x, 1);
-
-      /* Check the first level.  */
-      if (x0 == x1)
-       return nonzero_bits1 (x, mode, x0, mode,
-                             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')
-         && (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')
-         && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
-       return nonzero_bits1 (x, mode, x0, mode,
-                        nonzero_bits_with_known (x0, mode));
-    }
-
-  return nonzero_bits1 (x, mode, known_x, known_mode, known_ret);
-}
-
-/* We let num_sign_bit_copies recur into nonzero_bits as that is useful.
-   We don't let nonzero_bits recur into num_sign_bit_copies, because that
-   is less useful.  We can't allow both, because that results in exponential
-   run time recursion.  There is a nullstone testcase that triggered
-   this.  This macro avoids accidental uses of num_sign_bit_copies.  */
-#define cached_num_sign_bit_copies()
-
-/* Given an expression, X, compute which bits in X can be nonzero.
+/* Given a REG, X, compute which bits in X can be nonzero.
    We don't care about bits outside of those defined in MODE.
 
    For most X this is simply GET_MODE_MASK (GET_MODE (MODE)), but if X is
    a shift, AND, or zero_extract, we can do better.  */
 
-static unsigned HOST_WIDE_INT
-nonzero_bits1 (x, mode, known_x, known_mode, known_ret)
-     rtx x;
-     enum machine_mode mode;
-     rtx known_x;
-     enum machine_mode known_mode;
-     unsigned HOST_WIDE_INT known_ret;
+static rtx
+reg_nonzero_bits_for_combine (rtx x, enum machine_mode mode,
+                             rtx known_x ATTRIBUTE_UNUSED,
+                             enum machine_mode known_mode ATTRIBUTE_UNUSED,
+                             unsigned HOST_WIDE_INT known_ret ATTRIBUTE_UNUSED,
+                             unsigned HOST_WIDE_INT *nonzero)
 {
-  unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode);
-  unsigned HOST_WIDE_INT inner_nz;
-  enum rtx_code code;
-  unsigned int mode_width = GET_MODE_BITSIZE (mode);
   rtx tem;
 
-  /* For floating-point values, assume all bits are needed.  */
-  if (FLOAT_MODE_P (GET_MODE (x)) || FLOAT_MODE_P (mode))
-    return nonzero;
+  /* If X is a register whose nonzero bits value is current, use it.
+     Otherwise, if X is a register whose value we can find, use that
+     value.  Otherwise, use the previously-computed global nonzero bits
+     for this register.  */
 
-  /* If X is wider than MODE, use its mode instead.  */
-  if (GET_MODE_BITSIZE (GET_MODE (x)) > mode_width)
+  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_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_stat[REGNO (x)].last_set) < subst_low_cuid)
     {
-      mode = GET_MODE (x);
-      nonzero = GET_MODE_MASK (mode);
-      mode_width = GET_MODE_BITSIZE (mode);
+      *nonzero &= reg_stat[REGNO (x)].last_set_nonzero_bits;
+      return NULL;
     }
 
-  if (mode_width > HOST_BITS_PER_WIDE_INT)
-    /* Our only callers in this case look for single bit values.  So
-       just return the mode mask.  Those tests will then be false.  */
-    return nonzero;
-
-#ifndef WORD_REGISTER_OPERATIONS
-  /* If MODE is wider than X, but both are a single word for both the host
-     and target machines, we can compute this from which bits of the
-     object might be nonzero in its own mode, taking into account the fact
-     that on many CISC machines, accessing an object in a wider mode
-     causes the high-order bits to become undefined.  So they are
-     not known to be zero.  */
-
-  if (GET_MODE (x) != VOIDmode && GET_MODE (x) != mode
-      && GET_MODE_BITSIZE (GET_MODE (x)) <= BITS_PER_WORD
-      && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
-      && GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (GET_MODE (x)))
-    {
-      nonzero &= nonzero_bits_with_known (x, GET_MODE (x));
-      nonzero |= GET_MODE_MASK (mode) & ~GET_MODE_MASK (GET_MODE (x));
-      return nonzero;
-    }
-#endif
+  tem = get_last_value (x);
 
-  code = GET_CODE (x);
-  switch (code)
+  if (tem)
     {
-    case REG:
-#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
-      /* If pointers extend unsigned and this is a pointer in Pmode, say that
-        all the bits above ptr_mode are known to be zero.  */
-      if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
-         && REG_POINTER (x))
-       nonzero &= GET_MODE_MASK (ptr_mode);
-#endif
-
-      /* Include declared information about alignment of pointers.  */
-      /* ??? We don't properly preserve REG_POINTER changes across
-        pointer-to-integer casts, so we can't trust it except for
-        things that we know must be pointers.  See execute/960116-1.c.  */
-      if ((x == stack_pointer_rtx
-          || x == frame_pointer_rtx
-          || x == arg_pointer_rtx)
-         && REGNO_POINTER_ALIGN (REGNO (x)))
-       {
-         unsigned HOST_WIDE_INT alignment
-           = REGNO_POINTER_ALIGN (REGNO (x)) / BITS_PER_UNIT;
-
-#ifdef PUSH_ROUNDING
-         /* If PUSH_ROUNDING is defined, it is possible for the
-            stack to be momentarily aligned only to that amount,
-            so we pick the least alignment.  */
-         if (x == stack_pointer_rtx && PUSH_ARGS)
-           alignment = MIN (PUSH_ROUNDING (1), alignment);
-#endif
-
-         nonzero &= ~(alignment - 1);
-       }
-
-      /* If X is a register whose nonzero bits value is current, use it.
-        Otherwise, if X is a register whose value we can find, use that
-        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
-                 && GET_MODE_CLASS (mode) == MODE_INT))
-         && (reg_last_set_label[REGNO (x)] == 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;
-
-      tem = get_last_value (x);
-
-      if (tem)
-       {
 #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
-            and this is the conservative approach.
-
-            ??? For 2.5, try to tighten up the MD files in this regard
-            instead of this kludge.  */
-
-         if (GET_MODE_BITSIZE (GET_MODE (x)) < mode_width
-             && GET_CODE (tem) == CONST_INT
-             && INTVAL (tem) > 0
-             && 0 != (INTVAL (tem)
-                      & ((HOST_WIDE_INT) 1
-                         << (GET_MODE_BITSIZE (GET_MODE (x)) - 1))))
-           tem = GEN_INT (INTVAL (tem)
-                          | ((HOST_WIDE_INT) (-1)
-                             << GET_MODE_BITSIZE (GET_MODE (x))));
-#endif
-         return nonzero_bits_with_known (tem, mode) & nonzero;
-       }
-      else if (nonzero_sign_valid && reg_nonzero_bits[REGNO (x)])
-       {
-         unsigned HOST_WIDE_INT mask = reg_nonzero_bits[REGNO (x)];
-
-         if (GET_MODE_BITSIZE (GET_MODE (x)) < mode_width)
-           /* We don't know anything about the upper bits.  */
-           mask |= GET_MODE_MASK (mode) ^ GET_MODE_MASK (GET_MODE (x));
-         return nonzero & mask;
-       }
-      else
-       return nonzero;
-
-    case CONST_INT:
-#ifdef SHORT_IMMEDIATES_SIGN_EXTEND
-      /* If X is negative in MODE, sign-extend the value.  */
-      if (INTVAL (x) > 0 && mode_width < BITS_PER_WORD
-         && 0 != (INTVAL (x) & ((HOST_WIDE_INT) 1 << (mode_width - 1))))
-       return (INTVAL (x) | ((HOST_WIDE_INT) (-1) << mode_width));
-#endif
-
-      return INTVAL (x);
-
-    case MEM:
-#ifdef LOAD_EXTEND_OP
-      /* In many, if not most, RISC machines, reading a byte from memory
-        zeros the rest of the register.  Noticing that fact saves a lot
-        of extra zero-extends.  */
-      if (LOAD_EXTEND_OP (GET_MODE (x)) == ZERO_EXTEND)
-       nonzero &= GET_MODE_MASK (GET_MODE (x));
-#endif
-      break;
-
-    case EQ:  case NE:
-    case UNEQ:  case LTGT:
-    case GT:  case GTU:  case UNGT:
-    case LT:  case LTU:  case UNLT:
-    case GE:  case GEU:  case UNGE:
-    case LE:  case LEU:  case UNLE:
-    case UNORDERED: case ORDERED:
-
-      /* If this produces an integer result, we know which bits are set.
-        Code here used to clear bits outside the mode of X, but that is
-        now done above.  */
-
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && mode_width <= HOST_BITS_PER_WIDE_INT)
-       nonzero = STORE_FLAG_VALUE;
-      break;
-
-    case NEG:
-#if 0
-      /* Disabled to avoid exponential mutual recursion between nonzero_bits
-        and num_sign_bit_copies.  */
-      if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
-         == GET_MODE_BITSIZE (GET_MODE (x)))
-       nonzero = 1;
-#endif
-
-      if (GET_MODE_SIZE (GET_MODE (x)) < mode_width)
-       nonzero |= (GET_MODE_MASK (mode) & ~GET_MODE_MASK (GET_MODE (x)));
-      break;
-
-    case ABS:
-#if 0
-      /* Disabled to avoid exponential mutual recursion between nonzero_bits
-        and num_sign_bit_copies.  */
-      if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
-         == GET_MODE_BITSIZE (GET_MODE (x)))
-       nonzero = 1;
-#endif
-      break;
-
-    case TRUNCATE:
-      nonzero &= (nonzero_bits_with_known (XEXP (x, 0), mode)
-                 & GET_MODE_MASK (mode));
-      break;
-
-    case ZERO_EXTEND:
-      nonzero &= nonzero_bits_with_known (XEXP (x, 0), mode);
-      if (GET_MODE (XEXP (x, 0)) != VOIDmode)
-       nonzero &= GET_MODE_MASK (GET_MODE (XEXP (x, 0)));
-      break;
-
-    case SIGN_EXTEND:
-      /* If the sign bit is known clear, this is the same as ZERO_EXTEND.
-        Otherwise, show all the bits in the outer mode but not the inner
-        may be nonzero.  */
-      inner_nz = nonzero_bits_with_known (XEXP (x, 0), mode);
-      if (GET_MODE (XEXP (x, 0)) != VOIDmode)
-       {
-         inner_nz &= GET_MODE_MASK (GET_MODE (XEXP (x, 0)));
-         if (inner_nz
-             & (((HOST_WIDE_INT) 1
-                 << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1))))
-           inner_nz |= (GET_MODE_MASK (mode)
-                        & ~GET_MODE_MASK (GET_MODE (XEXP (x, 0))));
-       }
-
-      nonzero &= inner_nz;
-      break;
-
-    case AND:
-      nonzero &= (nonzero_bits_with_known (XEXP (x, 0), mode)
-                 & nonzero_bits_with_known (XEXP (x, 1), mode));
-      break;
-
-    case XOR:   case IOR:
-    case UMIN:  case UMAX:  case SMIN:  case SMAX:
-      {
-       unsigned HOST_WIDE_INT nonzero0 =
-         nonzero_bits_with_known (XEXP (x, 0), mode);
-
-       /* Don't call nonzero_bits for the second time if it cannot change
-          anything.  */
-       if ((nonzero & nonzero0) != nonzero)
-         nonzero &= (nonzero0
-                     | nonzero_bits_with_known (XEXP (x, 1), mode));
-      }
-      break;
-
-    case PLUS:  case MINUS:
-    case MULT:
-    case DIV:   case UDIV:
-    case MOD:   case UMOD:
-      /* We can apply the rules of arithmetic to compute the number of
-        high- and low-order zero bits of these operations.  We start by
-        computing the width (position of the highest-order nonzero bit)
-        and the number of low-order zero bits for each value.  */
-      {
-       unsigned HOST_WIDE_INT nz0 =
-         nonzero_bits_with_known (XEXP (x, 0), mode);
-       unsigned HOST_WIDE_INT nz1 =
-         nonzero_bits_with_known (XEXP (x, 1), mode);
-       int sign_index = GET_MODE_BITSIZE (GET_MODE (x)) - 1;
-       int width0 = floor_log2 (nz0) + 1;
-       int width1 = floor_log2 (nz1) + 1;
-       int low0 = floor_log2 (nz0 & -nz0);
-       int low1 = floor_log2 (nz1 & -nz1);
-       HOST_WIDE_INT op0_maybe_minusp
-         = (nz0 & ((HOST_WIDE_INT) 1 << sign_index));
-       HOST_WIDE_INT op1_maybe_minusp
-         = (nz1 & ((HOST_WIDE_INT) 1 << sign_index));
-       unsigned int result_width = mode_width;
-       int result_low = 0;
-
-       switch (code)
-         {
-         case PLUS:
-           result_width = MAX (width0, width1) + 1;
-           result_low = MIN (low0, low1);
-           break;
-         case MINUS:
-           result_low = MIN (low0, low1);
-           break;
-         case MULT:
-           result_width = width0 + width1;
-           result_low = low0 + low1;
-           break;
-         case DIV:
-           if (width1 == 0)
-             break;
-           if (! op0_maybe_minusp && ! op1_maybe_minusp)
-             result_width = width0;
-           break;
-         case UDIV:
-           if (width1 == 0)
-             break;
-           result_width = width0;
-           break;
-         case MOD:
-           if (width1 == 0)
-             break;
-           if (! op0_maybe_minusp && ! op1_maybe_minusp)
-             result_width = MIN (width0, width1);
-           result_low = MIN (low0, low1);
-           break;
-         case UMOD:
-           if (width1 == 0)
-             break;
-           result_width = MIN (width0, width1);
-           result_low = MIN (low0, low1);
-           break;
-         default:
-           abort ();
-         }
-
-       if (result_width < mode_width)
-         nonzero &= ((HOST_WIDE_INT) 1 << result_width) - 1;
-
-       if (result_low > 0)
-         nonzero &= ~(((HOST_WIDE_INT) 1 << result_low) - 1);
-
-#ifdef POINTERS_EXTEND_UNSIGNED
-       /* If pointers extend unsigned and this is an addition or subtraction
-          to a pointer in Pmode, all the bits above ptr_mode are known to be
-          zero.  */
-       if (POINTERS_EXTEND_UNSIGNED > 0 && GET_MODE (x) == Pmode
-           && (code == PLUS || code == MINUS)
-           && GET_CODE (XEXP (x, 0)) == REG && REG_POINTER (XEXP (x, 0)))
-         nonzero &= GET_MODE_MASK (ptr_mode);
-#endif
-      }
-      break;
-
-    case ZERO_EXTRACT:
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
-       nonzero &= ((HOST_WIDE_INT) 1 << INTVAL (XEXP (x, 1))) - 1;
-      break;
-
-    case SUBREG:
-      /* If this is a SUBREG formed for a promoted variable that has
-        been zero-extended, we know that at least the high-order bits
-        are zero, though others might be too.  */
-
-      if (SUBREG_PROMOTED_VAR_P (x) && SUBREG_PROMOTED_UNSIGNED_P (x) > 0)
-       nonzero = (GET_MODE_MASK (GET_MODE (x))
-                  & nonzero_bits_with_known (SUBREG_REG (x), GET_MODE (x)));
-
-      /* If the inner mode is a single word for both the host and target
-        machines, we can compute this from which bits of the inner
-        object might be nonzero.  */
-      if (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) <= BITS_PER_WORD
-         && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
-             <= HOST_BITS_PER_WIDE_INT))
-       {
-         nonzero &= nonzero_bits_with_known (SUBREG_REG (x), mode);
-
-#if defined (WORD_REGISTER_OPERATIONS) && defined (LOAD_EXTEND_OP)
-         /* If this is a typical RISC machine, we only have to worry
-            about the way loads are extended.  */
-         if ((LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND
-              ? (((nonzero
-                   & (((unsigned HOST_WIDE_INT) 1
-                       << (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - 1))))
-                  != 0))
-              : LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) != ZERO_EXTEND)
-             || GET_CODE (SUBREG_REG (x)) != MEM)
+      /* 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
+         and this is the conservative approach.
+
+         ??? For 2.5, try to tighten up the MD files in this regard
+         instead of this kludge.  */
+
+      if (GET_MODE_BITSIZE (GET_MODE (x)) < GET_MODE_BITSIZE (mode)
+         && GET_CODE (tem) == CONST_INT
+         && INTVAL (tem) > 0
+         && 0 != (INTVAL (tem)
+                  & ((HOST_WIDE_INT) 1
+                     << (GET_MODE_BITSIZE (GET_MODE (x)) - 1))))
+       tem = GEN_INT (INTVAL (tem)
+                      | ((HOST_WIDE_INT) (-1)
+                         << GET_MODE_BITSIZE (GET_MODE (x))));
 #endif
-           {
-             /* On many CISC machines, accessing an object in a wider mode
-                causes the high-order bits to become undefined.  So they are
-                not known to be zero.  */
-             if (GET_MODE_SIZE (GET_MODE (x))
-                 > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
-               nonzero |= (GET_MODE_MASK (GET_MODE (x))
-                           & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (x))));
-           }
-       }
-      break;
-
-    case ASHIFTRT:
-    case LSHIFTRT:
-    case ASHIFT:
-    case ROTATE:
-      /* The nonzero bits are in two classes: any bits within MODE
-        that aren't in GET_MODE (x) are always significant.  The rest of the
-        nonzero bits are those that are significant in the operand of
-        the shift when shifted the appropriate number of bits.  This
-        shows that high-order bits are cleared by the right shift and
-        low-order bits by left shifts.  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && INTVAL (XEXP (x, 1)) >= 0
-         && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
-       {
-         enum machine_mode inner_mode = GET_MODE (x);
-         unsigned int width = GET_MODE_BITSIZE (inner_mode);
-         int count = INTVAL (XEXP (x, 1));
-         unsigned HOST_WIDE_INT mode_mask = GET_MODE_MASK (inner_mode);
-         unsigned HOST_WIDE_INT op_nonzero =
-           nonzero_bits_with_known (XEXP (x, 0), mode);
-         unsigned HOST_WIDE_INT inner = op_nonzero & mode_mask;
-         unsigned HOST_WIDE_INT outer = 0;
-
-         if (mode_width > width)
-           outer = (op_nonzero & nonzero & ~mode_mask);
-
-         if (code == LSHIFTRT)
-           inner >>= count;
-         else if (code == ASHIFTRT)
-           {
-             inner >>= count;
-
-             /* If the sign bit may have been nonzero before the shift, we
-                need to mark all the places it could have been copied to
-                by the shift as possibly nonzero.  */
-             if (inner & ((HOST_WIDE_INT) 1 << (width - 1 - count)))
-               inner |= (((HOST_WIDE_INT) 1 << count) - 1) << (width - count);
-           }
-         else if (code == ASHIFT)
-           inner <<= count;
-         else
-           inner = ((inner << (count % width)
-                     | (inner >> (width - (count % width)))) & mode_mask);
-
-         nonzero &= (outer | inner);
-       }
-      break;
-
-    case FFS:
-    case POPCOUNT:
-      /* This is at most the number of bits in the mode.  */
-      nonzero = ((HOST_WIDE_INT) 2 << (floor_log2 (mode_width))) - 1;
-      break;
-
-    case CLZ:
-      /* If CLZ has a known value at zero, then the nonzero bits are
-        that value, plus the number of bits in the mode minus one.  */
-      if (CLZ_DEFINED_VALUE_AT_ZERO (mode, nonzero))
-       nonzero |= ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width))) - 1;
-      else
-       nonzero = -1;
-      break;
-
-    case CTZ:
-      /* If CTZ has a known value at zero, then the nonzero bits are
-        that value, plus the number of bits in the mode minus one.  */
-      if (CTZ_DEFINED_VALUE_AT_ZERO (mode, nonzero))
-       nonzero |= ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width))) - 1;
-      else
-       nonzero = -1;
-      break;
-
-    case PARITY:
-      nonzero = 1;
-      break;
-
-    case IF_THEN_ELSE:
-      nonzero &= (nonzero_bits_with_known (XEXP (x, 1), mode)
-                 | nonzero_bits_with_known (XEXP (x, 2), mode));
-      break;
-
-    default:
-      break;
+      return tem;
     }
-
-  return nonzero;
-}
-
-/* See the macro definition above.  */
-#undef cached_num_sign_bit_copies
-\f
-#define num_sign_bit_copies_with_known(X, M) \
-  cached_num_sign_bit_copies (X, M, known_x, known_mode, known_ret)
-
-/* The function cached_num_sign_bit_copies is a wrapper around
-   num_sign_bit_copies1.  It avoids exponential behavior in
-   num_sign_bit_copies1 when X has identical subexpressions on the
-   first or the second level.  */
-
-static unsigned int
-cached_num_sign_bit_copies (x, mode, known_x, known_mode, known_ret)
-     rtx x;
-     enum machine_mode mode;
-     rtx known_x;
-     enum machine_mode known_mode;
-     unsigned int known_ret;
-{
-  if (x == known_x && mode == known_mode)
-    return known_ret;
-
-  /* Try to find identical subexpressions.  If found call
-     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')
+  else if (nonzero_sign_valid && reg_stat[REGNO (x)].nonzero_bits)
     {
-      rtx x0 = XEXP (x, 0);
-      rtx x1 = XEXP (x, 1);
+      unsigned HOST_WIDE_INT mask = reg_stat[REGNO (x)].nonzero_bits;
 
-      /* Check the first level.  */
-      if (x0 == x1)
-       return
-         num_sign_bit_copies1 (x, mode, x0, mode,
-                               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')
-         && (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')
-         && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
-       return
-         num_sign_bit_copies1 (x, mode, x0, mode,
-                               num_sign_bit_copies_with_known (x0, mode));
+      if (GET_MODE_BITSIZE (GET_MODE (x)) < GET_MODE_BITSIZE (mode))
+        /* We don't know anything about the upper bits.  */
+        mask |= GET_MODE_MASK (mode) ^ GET_MODE_MASK (GET_MODE (x));
+      *nonzero &= mask;
     }
 
-  return num_sign_bit_copies1 (x, mode, known_x, known_mode, known_ret);
+  return NULL;
 }
 
 /* Return the number of bits at the high-order end of X that are known to
@@ -8780,357 +8154,38 @@ cached_num_sign_bit_copies (x, mode, known_x, known_mode, known_ret)
    VOIDmode, X will be used in its own mode.  The returned value  will always
    be between 1 and the number of bits in MODE.  */
 
-static unsigned int
-num_sign_bit_copies1 (x, mode, known_x, known_mode, known_ret)
-     rtx x;
-     enum machine_mode mode;
-     rtx known_x;
-     enum machine_mode known_mode;
-     unsigned int known_ret;
+static rtx
+reg_num_sign_bit_copies_for_combine (rtx x, enum machine_mode mode,
+                                    rtx known_x ATTRIBUTE_UNUSED,
+                                    enum machine_mode known_mode
+                                    ATTRIBUTE_UNUSED,
+                                    unsigned int known_ret ATTRIBUTE_UNUSED,
+                                    unsigned int *result)
 {
-  enum rtx_code code = GET_CODE (x);
-  unsigned int bitwidth;
-  int num0, num1, result;
-  unsigned HOST_WIDE_INT nonzero;
   rtx tem;
 
-  /* If we weren't given a mode, use the mode of X.  If the mode is still
-     VOIDmode, we don't know anything.  Likewise if one of the modes is
-     floating-point.  */
-
-  if (mode == VOIDmode)
-    mode = GET_MODE (x);
-
-  if (mode == VOIDmode || FLOAT_MODE_P (mode) || FLOAT_MODE_P (GET_MODE (x)))
-    return 1;
-
-  bitwidth = GET_MODE_BITSIZE (mode);
-
-  /* For a smaller object, just ignore the high bits.  */
-  if (bitwidth < GET_MODE_BITSIZE (GET_MODE (x)))
+  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_stat[REGNO (x)].last_set) < subst_low_cuid)
     {
-      num0 = num_sign_bit_copies_with_known (x, GET_MODE (x));
-      return MAX (1,
-                 num0 - (int) (GET_MODE_BITSIZE (GET_MODE (x)) - bitwidth));
-    }
-
-  if (GET_MODE (x) != VOIDmode && bitwidth > GET_MODE_BITSIZE (GET_MODE (x)))
-    {
-#ifndef WORD_REGISTER_OPERATIONS
-  /* If this machine does not do all register operations on the entire
-     register and MODE is wider than the mode of X, we can say nothing
-     at all about the high-order bits.  */
-      return 1;
-#else
-      /* Likewise on machines that do, if the mode of the object is smaller
-        than a word and loads of that size don't sign extend, we can say
-        nothing about the high order bits.  */
-      if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD
-#ifdef LOAD_EXTEND_OP
-         && LOAD_EXTEND_OP (GET_MODE (x)) != SIGN_EXTEND
-#endif
-         )
-       return 1;
-#endif
-    }
-
-  switch (code)
-    {
-    case REG:
-
-#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
-      /* If pointers extend signed and this is a pointer in Pmode, say that
-        all the bits above ptr_mode are known to be sign bit copies.  */
-      if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode && mode == Pmode
-         && REG_POINTER (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
-             || (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)];
-
-      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
-         && GET_MODE_BITSIZE (GET_MODE (x)) == bitwidth)
-       return reg_sign_bit_copies[REGNO (x)];
-      break;
-
-    case MEM:
-#ifdef LOAD_EXTEND_OP
-      /* Some RISC machines sign-extend all loads of smaller than a word.  */
-      if (LOAD_EXTEND_OP (GET_MODE (x)) == SIGN_EXTEND)
-       return MAX (1, ((int) bitwidth
-                       - (int) GET_MODE_BITSIZE (GET_MODE (x)) + 1));
-#endif
-      break;
-
-    case CONST_INT:
-      /* If the constant is negative, take its 1's complement and remask.
-        Then see how many zero bits we have.  */
-      nonzero = INTVAL (x) & GET_MODE_MASK (mode);
-      if (bitwidth <= HOST_BITS_PER_WIDE_INT
-         && (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
-       nonzero = (~nonzero) & GET_MODE_MASK (mode);
-
-      return (nonzero == 0 ? bitwidth : bitwidth - floor_log2 (nonzero) - 1);
-
-    case SUBREG:
-      /* If this is a SUBREG for a promoted object that is sign-extended
-        and we are looking at it in a wider mode, we know that at least the
-        high-order bits are known to be sign bit copies.  */
-
-      if (SUBREG_PROMOTED_VAR_P (x) && ! SUBREG_PROMOTED_UNSIGNED_P (x))
-       {
-         num0 = num_sign_bit_copies_with_known (SUBREG_REG (x), mode);
-         return MAX ((int) bitwidth
-                     - (int) GET_MODE_BITSIZE (GET_MODE (x)) + 1,
-                     num0);
-       }
-
-      /* For a smaller object, just ignore the high bits.  */
-      if (bitwidth <= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))))
-       {
-         num0 = num_sign_bit_copies_with_known (SUBREG_REG (x), VOIDmode);
-         return MAX (1, (num0
-                         - (int) (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
-                                  - bitwidth)));
-       }
-
-#ifdef WORD_REGISTER_OPERATIONS
-#ifdef LOAD_EXTEND_OP
-      /* For paradoxical SUBREGs on machines where all register operations
-        affect the entire register, just look inside.  Note that we are
-        passing MODE to the recursive call, so the number of sign bit copies
-        will remain relative to that mode, not the inner mode.  */
-
-      /* This works only if loads sign extend.  Otherwise, if we get a
-        reload for the inner part, it may be loaded from the stack, and
-        then we lose all sign bit copies that existed before the store
-        to the stack.  */
-
-      if ((GET_MODE_SIZE (GET_MODE (x))
-          > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
-         && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND
-         && GET_CODE (SUBREG_REG (x)) == MEM)
-       return num_sign_bit_copies_with_known (SUBREG_REG (x), mode);
-#endif
-#endif
-      break;
-
-    case SIGN_EXTRACT:
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
-       return MAX (1, (int) bitwidth - INTVAL (XEXP (x, 1)));
-      break;
-
-    case SIGN_EXTEND:
-      return (bitwidth - GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
-             + num_sign_bit_copies_with_known (XEXP (x, 0), VOIDmode));
-
-    case TRUNCATE:
-      /* For a smaller object, just ignore the high bits.  */
-      num0 = num_sign_bit_copies_with_known (XEXP (x, 0), VOIDmode);
-      return MAX (1, (num0 - (int) (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
-                                   - bitwidth)));
-
-    case NOT:
-      return num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-
-    case ROTATE:       case ROTATERT:
-      /* If we are rotating left by a number of bits less than the number
-        of sign bit copies, we can just subtract that amount from the
-        number.  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && INTVAL (XEXP (x, 1)) >= 0
-         && INTVAL (XEXP (x, 1)) < (int) bitwidth)
-       {
-         num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-         return MAX (1, num0 - (code == ROTATE ? INTVAL (XEXP (x, 1))
-                                : (int) bitwidth - INTVAL (XEXP (x, 1))));
-       }
-      break;
-
-    case NEG:
-      /* In general, this subtracts one sign bit copy.  But if the value
-        is known to be positive, the number of sign bit copies is the
-        same as that of the input.  Finally, if the input has just one bit
-        that might be nonzero, all the bits are copies of the sign bit.  */
-      num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-      if (bitwidth > HOST_BITS_PER_WIDE_INT)
-       return num0 > 1 ? num0 - 1 : 1;
-
-      nonzero = nonzero_bits (XEXP (x, 0), mode);
-      if (nonzero == 1)
-       return bitwidth;
-
-      if (num0 > 1
-         && (((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero))
-       num0--;
-
-      return num0;
-
-    case IOR:   case AND:   case XOR:
-    case SMIN:  case SMAX:  case UMIN:  case UMAX:
-      /* Logical operations will preserve the number of sign-bit copies.
-        MIN and MAX operations always return one of the operands.  */
-      num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-      num1 = num_sign_bit_copies_with_known (XEXP (x, 1), mode);
-      return MIN (num0, num1);
-
-    case PLUS:  case MINUS:
-      /* For addition and subtraction, we can have a 1-bit carry.  However,
-        if we are subtracting 1 from a positive number, there will not
-        be such a carry.  Furthermore, if the positive number is known to
-        be 0 or 1, we know the result is either -1 or 0.  */
-
-      if (code == PLUS && XEXP (x, 1) == constm1_rtx
-         && bitwidth <= HOST_BITS_PER_WIDE_INT)
-       {
-         nonzero = nonzero_bits (XEXP (x, 0), mode);
-         if ((((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero) == 0)
-           return (nonzero == 1 || nonzero == 0 ? bitwidth
-                   : bitwidth - floor_log2 (nonzero) - 1);
-       }
-
-      num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-      num1 = num_sign_bit_copies_with_known (XEXP (x, 1), mode);
-      result = MAX (1, MIN (num0, num1) - 1);
-
-#ifdef POINTERS_EXTEND_UNSIGNED
-      /* If pointers extend signed and this is an addition or subtraction
-        to a pointer in Pmode, all the bits above ptr_mode are known to be
-        sign bit copies.  */
-      if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
-         && (code == PLUS || code == MINUS)
-         && GET_CODE (XEXP (x, 0)) == REG && REG_POINTER (XEXP (x, 0)))
-       result = MAX ((int) (GET_MODE_BITSIZE (Pmode)
-                            - GET_MODE_BITSIZE (ptr_mode) + 1),
-                     result);
-#endif
-      return result;
-
-    case MULT:
-      /* The number of bits of the product is the sum of the number of
-        bits of both terms.  However, unless one of the terms if known
-        to be positive, we must allow for an additional bit since negating
-        a negative number can remove one sign bit copy.  */
-
-      num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-      num1 = num_sign_bit_copies_with_known (XEXP (x, 1), mode);
-
-      result = bitwidth - (bitwidth - num0) - (bitwidth - num1);
-      if (result > 0
-         && (bitwidth > HOST_BITS_PER_WIDE_INT
-             || (((nonzero_bits (XEXP (x, 0), mode)
-                   & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
-                 && ((nonzero_bits (XEXP (x, 1), mode)
-                      & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))))
-       result--;
-
-      return MAX (1, result);
-
-    case UDIV:
-      /* The result must be <= the first operand.  If the first operand
-         has the high bit set, we know nothing about the number of sign
-         bit copies.  */
-      if (bitwidth > HOST_BITS_PER_WIDE_INT)
-       return 1;
-      else if ((nonzero_bits (XEXP (x, 0), mode)
-               & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
-       return 1;
-      else
-       return num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-
-    case UMOD:
-      /* The result must be <= the second operand.  */
-      return num_sign_bit_copies_with_known (XEXP (x, 1), mode);
-
-    case DIV:
-      /* Similar to unsigned division, except that we have to worry about
-        the case where the divisor is negative, in which case we have
-        to add 1.  */
-      result = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-      if (result > 1
-         && (bitwidth > HOST_BITS_PER_WIDE_INT
-             || (nonzero_bits (XEXP (x, 1), mode)
-                 & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))
-       result--;
-
-      return result;
-
-    case MOD:
-      result = num_sign_bit_copies_with_known (XEXP (x, 1), mode);
-      if (result > 1
-         && (bitwidth > HOST_BITS_PER_WIDE_INT
-             || (nonzero_bits (XEXP (x, 1), mode)
-                 & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))
-       result--;
-
-      return result;
-
-    case ASHIFTRT:
-      /* Shifts by a constant add to the number of bits equal to the
-        sign bit.  */
-      num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && INTVAL (XEXP (x, 1)) > 0)
-       num0 = MIN ((int) bitwidth, num0 + INTVAL (XEXP (x, 1)));
-
-      return num0;
-
-    case ASHIFT:
-      /* Left shifts destroy copies.  */
-      if (GET_CODE (XEXP (x, 1)) != CONST_INT
-         || INTVAL (XEXP (x, 1)) < 0
-         || INTVAL (XEXP (x, 1)) >= (int) bitwidth)
-       return 1;
-
-      num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-      return MAX (1, num0 - INTVAL (XEXP (x, 1)));
-
-    case IF_THEN_ELSE:
-      num0 = num_sign_bit_copies_with_known (XEXP (x, 1), mode);
-      num1 = num_sign_bit_copies_with_known (XEXP (x, 2), mode);
-      return MIN (num0, num1);
-
-    case EQ:  case NE:  case GE:  case GT:  case LE:  case LT:
-    case UNEQ:  case LTGT:  case UNGE:  case UNGT:  case UNLE:  case UNLT:
-    case GEU: case GTU: case LEU: case LTU:
-    case UNORDERED: case ORDERED:
-      /* If the constant is negative, take its 1's complement and remask.
-        Then see how many zero bits we have.  */
-      nonzero = STORE_FLAG_VALUE;
-      if (bitwidth <= HOST_BITS_PER_WIDE_INT
-         && (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
-       nonzero = (~nonzero) & GET_MODE_MASK (mode);
-
-      return (nonzero == 0 ? bitwidth : bitwidth - floor_log2 (nonzero) - 1);
-      break;
-
-    default:
-      break;
+      *result = reg_stat[REGNO (x)].last_set_sign_bit_copies;
+      return NULL;
     }
 
-  /* If we haven't been able to figure it out by one of the above rules,
-     see if some of the high-order bits are known to be zero.  If so,
-     count those bits and return one less than that amount.  If we can't
-     safely compute the mask for this mode, always return BITWIDTH.  */
+  tem = get_last_value (x);
+  if (tem != 0)
+    return tem;
 
-  if (bitwidth > HOST_BITS_PER_WIDE_INT)
-    return 1;
-
-  nonzero = nonzero_bits (x, mode);
-  return (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))
-         ? 1 : bitwidth - floor_log2 (nonzero) - 1);
+  if (nonzero_sign_valid && reg_stat[REGNO (x)].sign_bit_copies != 0
+      && GET_MODE_BITSIZE (GET_MODE (x)) == GET_MODE_BITSIZE (mode))
+    *result = reg_stat[REGNO (x)].sign_bit_copies;
+      
+  return NULL;
 }
 \f
 /* Return the number of "extended" bits there are in X, when interpreted
@@ -9145,10 +8200,7 @@ num_sign_bit_copies1 (x, mode, known_x, known_mode, known_ret)
    implies that it must be called from a define_split.  */
 
 unsigned int
-extended_count (x, mode, unsignedp)
-     rtx x;
-     enum machine_mode mode;
-     int unsignedp;
+extended_count (rtx x, enum machine_mode mode, int unsignedp)
 {
   if (nonzero_sign_valid == 0)
     return 0;
@@ -9183,13 +8235,7 @@ extended_count (x, mode, unsignedp)
    return 0 and do not change *POP0, *PCONST0, and *PCOMP_P.  */
 
 static int
-merge_outer_ops (pop0, pconst0, op1, const1, mode, pcomp_p)
-     enum rtx_code *pop0;
-     HOST_WIDE_INT *pconst0;
-     enum rtx_code op1;
-     HOST_WIDE_INT const1;
-     enum machine_mode mode;
-     int *pcomp_p;
+merge_outer_ops (enum rtx_code *pop0, HOST_WIDE_INT *pconst0, enum rtx_code op1, HOST_WIDE_INT const1, enum machine_mode mode, int *pcomp_p)
 {
   enum rtx_code op0 = *pop0;
   HOST_WIDE_INT const0 = *pconst0;
@@ -9261,7 +8307,7 @@ merge_outer_ops (pop0, pconst0, op1, const1, mode, pcomp_p)
          op0 = AND, *pcomp_p = 1;
        else /* op1 == IOR */
          /* (a | b) ^ b == a & ~b */
-         op0 = AND, *pconst0 = ~const0;
+         op0 = AND, const0 = ~const0;
        break;
 
       case AND:
@@ -9307,12 +8353,9 @@ merge_outer_ops (pop0, pconst0, op1, const1, mode, pcomp_p)
    are ASHIFTRT and ROTATE, which are always done in their original mode,  */
 
 static rtx
-simplify_shift_const (x, code, result_mode, varop, orig_count)
-     rtx x;
-     enum rtx_code code;
-     enum machine_mode result_mode;
-     rtx varop;
-     int orig_count;
+simplify_shift_const (rtx x, enum rtx_code code,
+                     enum machine_mode result_mode, rtx varop,
+                     int orig_count)
 {
   enum rtx_code orig_code = code;
   unsigned int count;
@@ -9331,10 +8374,8 @@ simplify_shift_const (x, code, result_mode, varop, orig_count)
   /* 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.  */
@@ -9538,8 +8579,10 @@ simplify_shift_const (x, code, result_mode, varop, orig_count)
              && exact_log2 (INTVAL (XEXP (varop, 1))) >= 0)
            {
              varop
-               = gen_binary (ASHIFT, GET_MODE (varop), XEXP (varop, 0),
-                             GEN_INT (exact_log2 (INTVAL (XEXP (varop, 1)))));
+               = simplify_gen_binary (ASHIFT, GET_MODE (varop),
+                                      XEXP (varop, 0),
+                                      GEN_INT (exact_log2 (
+                                               INTVAL (XEXP (varop, 1)))));
              continue;
            }
          break;
@@ -9550,8 +8593,10 @@ simplify_shift_const (x, code, result_mode, varop, orig_count)
              && exact_log2 (INTVAL (XEXP (varop, 1))) >= 0)
            {
              varop
-               = gen_binary (LSHIFTRT, GET_MODE (varop), XEXP (varop, 0),
-                             GEN_INT (exact_log2 (INTVAL (XEXP (varop, 1)))));
+               = simplify_gen_binary (LSHIFTRT, GET_MODE (varop),
+                                      XEXP (varop, 0),
+                                      GEN_INT (exact_log2 (
+                                               INTVAL (XEXP (varop, 1)))));
              continue;
            }
          break;
@@ -9776,6 +8821,11 @@ simplify_shift_const (x, code, result_mode, varop, orig_count)
             (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
@@ -9789,22 +8839,27 @@ simplify_shift_const (x, code, result_mode, varop, orig_count)
 
          /* 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 = simplify_gen_binary (GET_CODE (varop), shift_mode,
+                                          lhs, rhs);
+             varop = apply_distributive_law (varop);
 
-           count = 0;
-         }
+             count = 0;
+           }
          break;
 
        case EQ:
-         /* convert (lshiftrt (eq FOO 0) C) to (xor FOO 1) if STORE_FLAG_VALUE
+         /* Convert (lshiftrt (eq FOO 0) C) to (xor FOO 1) if STORE_FLAG_VALUE
             says that the sign bit can be tested, FOO has mode MODE, C is
             GET_MODE_BITSIZE (MODE) - 1, and FOO has only its low-order bit
             that may be nonzero.  */
@@ -9988,7 +9043,7 @@ simplify_shift_const (x, code, result_mode, varop, orig_count)
      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);
@@ -10000,7 +9055,7 @@ simplify_shift_const (x, code, result_mode, varop, orig_count)
       && 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)
@@ -10029,7 +9084,7 @@ simplify_shift_const (x, code, result_mode, varop, orig_count)
                                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.  */
@@ -10047,10 +9102,11 @@ simplify_shift_const (x, code, result_mode, varop, orig_count)
        /* 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));
+       x = simplify_gen_binary (outer_op, result_mode, x,
+                                GEN_INT (outer_const));
     }
 
   return x;
@@ -10070,17 +9126,14 @@ simplify_shift_const (x, code, result_mode, varop, orig_count)
    or -1.  */
 
 static int
-recog_for_combine (pnewpat, insn, pnotes)
-     rtx *pnewpat;
-     rtx insn;
-     rtx *pnotes;
+recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
 {
   rtx pat = *pnewpat;
   int insn_code_number;
   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
@@ -10091,13 +9144,12 @@ recog_for_combine (pnewpat, insn, 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
@@ -10122,9 +9174,11 @@ recog_for_combine (pnewpat, insn, 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))
@@ -10166,27 +9220,32 @@ recog_for_combine (pnewpat, insn, 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 (mode, x)
-     enum machine_mode mode;
-     rtx x;
+gen_lowpart_for_combine (enum machine_mode mode, rtx x)
 {
   rtx result;
 
   if (GET_MODE (x) == mode)
     return x;
 
+  /* Return identity if this is a CONST or symbolic
+     reference.  */
+  if (mode == Pmode
+      && (GET_CODE (x) == CONST
+         || GET_CODE (x) == SYMBOL_REF
+         || GET_CODE (x) == LABEL_REF))
+    return x;
+
   /* We can only support MODE being wider than a word if X is a
      constant integer or has a mode the same size.  */
 
@@ -10231,7 +9290,7 @@ gen_lowpart_for_combine (mode, 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);
@@ -10253,7 +9312,7 @@ gen_lowpart_for_combine (mode, 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
@@ -10270,6 +9329,8 @@ gen_lowpart_for_combine (mode, x)
        {
          sub_mode = int_mode_for_mode (mode);
          x = gen_lowpart_common (sub_mode, x);
+         if (x == 0)
+           return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
        }
       res = simplify_gen_subreg (mode, x, sub_mode, offset);
       if (res)
@@ -10278,60 +9339,6 @@ gen_lowpart_for_combine (mode, x)
     }
 }
 \f
-/* These routines make binary and unary operations by first seeing if they
-   fold; if not, a new expression is allocated.  */
-
-static rtx
-gen_binary (code, mode, op0, op1)
-     enum rtx_code code;
-     enum machine_mode mode;
-     rtx op0, op1;
-{
-  rtx result;
-  rtx tem;
-
-  if (GET_RTX_CLASS (code) == 'c'
-      && swap_commutative_operands_p (op0, op1))
-    tem = op0, op0 = op1, op1 = tem;
-
-  if (GET_RTX_CLASS (code) == '<')
-    {
-      enum machine_mode op_mode = GET_MODE (op0);
-
-      /* Strip the COMPARE from (REL_OP (compare X Y) 0) to get
-        just (REL_OP X Y).  */
-      if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
-       {
-         op1 = XEXP (op0, 1);
-         op0 = XEXP (op0, 0);
-         op_mode = GET_MODE (op0);
-       }
-
-      if (op_mode == VOIDmode)
-       op_mode = GET_MODE (op1);
-      result = simplify_relational_operation (code, op_mode, op0, op1);
-    }
-  else
-    result = simplify_binary_operation (code, mode, op0, op1);
-
-  if (result)
-    return result;
-
-  /* Put complex operands first and constants second.  */
-  if (GET_RTX_CLASS (code) == 'c'
-      && swap_commutative_operands_p (op0, op1))
-    return gen_rtx_fmt_ee (code, mode, op1, op0);
-
-  /* If we are turning off bits already known off in OP0, we need not do
-     an AND.  */
-  else if (code == AND && GET_CODE (op1) == CONST_INT
-          && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-          && (nonzero_bits (op0, mode) & ~INTVAL (op1)) == 0)
-    return op0;
-
-  return gen_rtx_fmt_ee (code, mode, op0, op1);
-}
-\f
 /* Simplify a comparison between *POP0 and *POP1 where CODE is the
    comparison code that will be tested.
 
@@ -10344,10 +9351,7 @@ gen_binary (code, mode, op0, op1)
    should have been detected earlier.  Hence we ignore all such cases.  */
 
 static enum rtx_code
-simplify_comparison (code, pop0, pop1)
-     enum rtx_code code;
-     rtx *pop0;
-     rtx *pop1;
+simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
 {
   rtx op0 = *pop0;
   rtx op1 = *pop1;
@@ -10370,12 +9374,9 @@ simplify_comparison (code, pop0, pop1)
          && (GET_MODE (SUBREG_REG (XEXP (XEXP (op0, 0), 0)))
              == GET_MODE (SUBREG_REG (XEXP (XEXP (op1, 0), 0))))
          && GET_CODE (XEXP (op0, 1)) == CONST_INT
-         && GET_CODE (XEXP (op1, 1)) == CONST_INT
-         && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
-         && GET_CODE (XEXP (XEXP (op1, 0), 1)) == CONST_INT
-         && INTVAL (XEXP (op0, 1)) == INTVAL (XEXP (op1, 1))
-         && INTVAL (XEXP (op0, 1)) == INTVAL (XEXP (XEXP (op0, 0), 1))
-         && INTVAL (XEXP (op0, 1)) == INTVAL (XEXP (XEXP (op1, 0), 1))
+         && XEXP (op0, 1) == XEXP (op1, 1)
+         && XEXP (op0, 1) == XEXP (XEXP (op0, 0), 1)
+         && XEXP (op0, 1) == XEXP (XEXP (op1, 0), 1)
          && (INTVAL (XEXP (op0, 1))
              == (GET_MODE_BITSIZE (GET_MODE (op0))
                  - (GET_MODE_BITSIZE
@@ -10470,8 +9471,8 @@ simplify_comparison (code, pop0, 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;
@@ -10524,8 +9525,7 @@ simplify_comparison (code, pop0, 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
@@ -10729,8 +9729,10 @@ simplify_comparison (code, pop0, 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)
@@ -11098,9 +10100,9 @@ simplify_comparison (code, pop0, 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;
@@ -11134,70 +10136,88 @@ simplify_comparison (code, pop0, 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;
            }
 
-         /* If this is (and:M1 (subreg:M2 X 0) (const_int C1)) where C1 fits
-            in both M1 and M2 and the SUBREG is either paradoxical or
-            represents the low part, permute the SUBREG and the AND and
-            try again.  */
-         if (GET_CODE (XEXP (op0, 0)) == SUBREG
+         /* If this is (and:M1 (subreg:M2 X 0) (const_int C1)) where C1
+            fits in both M1 and M2 and the SUBREG is either paradoxical
+            or represents the low part, permute the SUBREG and the AND
+            and try again.  */
+         if (GET_CODE (XEXP (op0, 0)) == SUBREG)
+           {
+             unsigned HOST_WIDE_INT c1;
+             tmode = GET_MODE (SUBREG_REG (XEXP (op0, 0)));
              /* Require an integral mode, to avoid creating something like
                 (AND:SF ...).  */
-             && SCALAR_INT_MODE_P (GET_MODE (SUBREG_REG (XEXP (op0, 0))))
-             /* It is unsafe to commute the AND into the SUBREG if the SUBREG
-                is paradoxical and WORD_REGISTER_OPERATIONS is not defined.
-                As originally written the upper bits have a defined value
-                due to the AND operation.  However, if we commute the AND
-                inside the SUBREG then they no longer have defined values
-                and the meaning of the code has been changed.  */
-             && (0
+             if (SCALAR_INT_MODE_P (tmode)
+                 /* It is unsafe to commute the AND into the SUBREG if the
+                    SUBREG is paradoxical and WORD_REGISTER_OPERATIONS is
+                    not defined.  As originally written the upper bits
+                    have a defined value due to the AND operation.
+                    However, if we commute the AND inside the SUBREG then
+                    they no longer have defined values and the meaning of
+                    the code has been changed.  */
+                 && (0
 #ifdef WORD_REGISTER_OPERATIONS
-                 || ((mode_width
-                      > (GET_MODE_BITSIZE
-                          (GET_MODE (SUBREG_REG (XEXP (op0, 0))))))
-                     && mode_width <= BITS_PER_WORD)
+                     || (mode_width > GET_MODE_BITSIZE (tmode)
+                         && mode_width <= BITS_PER_WORD)
 #endif
-                 || ((mode_width
-                      <= (GET_MODE_BITSIZE
-                          (GET_MODE (SUBREG_REG (XEXP (op0, 0))))))
-                     && subreg_lowpart_p (XEXP (op0, 0))))
-             && GET_CODE (XEXP (op0, 1)) == CONST_INT
-             && mode_width <= HOST_BITS_PER_WIDE_INT
-             && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0))))
-                 <= HOST_BITS_PER_WIDE_INT)
-             && (INTVAL (XEXP (op0, 1)) & ~mask) == 0
-             && 0 == (~GET_MODE_MASK (GET_MODE (SUBREG_REG (XEXP (op0, 0))))
-                      & INTVAL (XEXP (op0, 1)))
-             && (unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1)) != mask
-             && ((unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1))
-                 != GET_MODE_MASK (GET_MODE (SUBREG_REG (XEXP (op0, 0))))))
-
-           {
-             op0
-               = gen_lowpart_for_combine
-                 (mode,
-                  gen_binary (AND, GET_MODE (SUBREG_REG (XEXP (op0, 0))),
-                              SUBREG_REG (XEXP (op0, 0)), XEXP (op0, 1)));
-             continue;
+                     || (mode_width <= GET_MODE_BITSIZE (tmode)
+                         && subreg_lowpart_p (XEXP (op0, 0))))
+                 && GET_CODE (XEXP (op0, 1)) == CONST_INT
+                 && mode_width <= HOST_BITS_PER_WIDE_INT
+                 && GET_MODE_BITSIZE (tmode) <= HOST_BITS_PER_WIDE_INT
+                 && ((c1 = INTVAL (XEXP (op0, 1))) & ~mask) == 0
+                 && (c1 & ~GET_MODE_MASK (tmode)) == 0
+                 && c1 != mask
+                 && c1 != GET_MODE_MASK (tmode))
+               {
+                 op0 = simplify_gen_binary (AND, tmode,
+                                            SUBREG_REG (XEXP (op0, 0)),
+                                            gen_int_mode (c1, tmode));
+                 op0 = gen_lowpart (mode, op0);
+                 continue;
+               }
            }
 
-         /* Convert (ne (and (lshiftrt (not X)) 1) 0) to
-            (eq (and (lshiftrt X) 1) 0).  */
+         /* Convert (ne (and (not X) 1) 0) to (eq (and X 1) 0).  */
          if (const_op == 0 && equality_comparison_p
              && XEXP (op0, 1) == const1_rtx
-             && GET_CODE (XEXP (op0, 0)) == LSHIFTRT
-             && GET_CODE (XEXP (XEXP (op0, 0), 0)) == NOT)
+             && GET_CODE (XEXP (op0, 0)) == NOT)
            {
              op0 = simplify_and_const_int
-               (op0, mode,
-                gen_rtx_LSHIFTRT (mode, XEXP (XEXP (XEXP (op0, 0), 0), 0),
-                                  XEXP (XEXP (op0, 0), 1)),
-                (HOST_WIDE_INT) 1);
+               (NULL_RTX, mode, XEXP (XEXP (op0, 0), 0), (HOST_WIDE_INT) 1);
              code = (code == NE ? EQ : NE);
              continue;
            }
+
+         /* Convert (ne (and (lshiftrt (not X)) 1) 0) to
+            (eq (and (lshiftrt X) 1) 0).
+            Also handle the case where (not X) is expressed using xor.  */
+         if (const_op == 0 && equality_comparison_p
+             && XEXP (op0, 1) == const1_rtx
+             && GET_CODE (XEXP (op0, 0)) == LSHIFTRT)
+           {
+             rtx shift_op = XEXP (XEXP (op0, 0), 0);
+             rtx shift_count = XEXP (XEXP (op0, 0), 1);
+
+             if (GET_CODE (shift_op) == NOT
+                 || (GET_CODE (shift_op) == XOR
+                     && GET_CODE (XEXP (shift_op, 1)) == CONST_INT
+                     && GET_CODE (shift_count) == CONST_INT
+                     && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+                     && (INTVAL (XEXP (shift_op, 1))
+                         == (HOST_WIDE_INT) 1 << INTVAL (shift_count))))
+               {
+                 op0 = simplify_and_const_int
+                   (NULL_RTX, mode,
+                    gen_rtx_LSHIFTRT (mode, XEXP (shift_op, 0), shift_count),
+                    (HOST_WIDE_INT) 1);
+                 code = (code == NE ? EQ : NE);
+                 continue;
+               }
+           }
          break;
 
        case ASHIFT:
@@ -11278,7 +10298,7 @@ simplify_comparison (code, pop0, 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;
            }
 
@@ -11299,12 +10319,12 @@ simplify_comparison (code, pop0, pop1)
            {
              rtx inner = XEXP (XEXP (XEXP (op0, 0), 0), 0);
              rtx add_const = XEXP (XEXP (op0, 0), 1);
-             rtx new_const = gen_binary (ASHIFTRT, GET_MODE (op0), add_const,
-                                         XEXP (op0, 1));
+             rtx new_const = simplify_gen_binary (ASHIFTRT, GET_MODE (op0),
+                                                  add_const, XEXP (op0, 1));
 
-             op0 = gen_binary (PLUS, tmode,
-                               gen_lowpart_for_combine (tmode, inner),
-                               new_const);
+             op0 = simplify_gen_binary (PLUS, tmode,
+                                        gen_lowpart (tmode, inner),
+                                        new_const);
              continue;
            }
 
@@ -11385,9 +10405,6 @@ simplify_comparison (code, pop0, pop1)
   op1 = make_compound_operation (op1, SET);
 
   if (GET_CODE (op0) == SUBREG && subreg_lowpart_p (op0)
-      /* Case 3 above, to sometimes allow (subreg (mem x)), isn't
-        implemented.  */
-      && GET_CODE (SUBREG_REG (op0)) == REG
       && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
       && GET_MODE_CLASS (GET_MODE (SUBREG_REG (op0))) == MODE_INT
       && (code == NE || code == EQ))
@@ -11395,8 +10412,13 @@ simplify_comparison (code, pop0, pop1)
       if (GET_MODE_SIZE (GET_MODE (op0))
          > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))
        {
-         op0 = SUBREG_REG (op0);
-         op1 = gen_lowpart_for_combine (GET_MODE (op0), op1);
+         /* For paradoxical subregs, allow case 1 as above.  Case 3 isn't
+            implemented.  */
+          if (GET_CODE (SUBREG_REG (op0)) == REG)
+           {
+             op0 = SUBREG_REG (op0);
+             op1 = gen_lowpart (GET_MODE (op0), op1);
+           }
        }
       else if ((GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
                <= HOST_BITS_PER_WIDE_INT)
@@ -11404,7 +10426,7 @@ simplify_comparison (code, pop0, 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)
@@ -11455,16 +10477,16 @@ simplify_comparison (code, pop0, pop1)
                 make a new AND in the proper mode.  */
              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)));
+               op0 = simplify_gen_binary (AND, tmode,
+                                          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;
            }
 
@@ -11474,10 +10496,11 @@ simplify_comparison (code, pop0, pop1)
          if (op1 == const0_rtx && (code == LT || code == GE)
              && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
            {
-             op0 = gen_binary (AND, tmode,
-                               gen_lowpart_for_combine (tmode, op0),
-                               GEN_INT ((HOST_WIDE_INT) 1
-                                        << (GET_MODE_BITSIZE (mode) - 1)));
+             op0 = simplify_gen_binary (AND, tmode,
+                                        gen_lowpart (tmode, op0),
+                                        GEN_INT ((HOST_WIDE_INT) 1
+                                                 << (GET_MODE_BITSIZE (mode)
+                                                     - 1)));
              code = (code == LT) ? NE : EQ;
              break;
            }
@@ -11498,8 +10521,7 @@ simplify_comparison (code, pop0, pop1)
 /* Like jump.c' reversed_comparison_code, but use combine infrastructure for
    searching backward.  */
 static enum rtx_code
-combine_reversed_comparison_code (exp)
-     rtx exp;
+combine_reversed_comparison_code (rtx exp)
 {
   enum rtx_code code1 = reversed_comparison_code (exp, NULL);
   rtx x;
@@ -11519,24 +10541,21 @@ combine_reversed_comparison_code (exp)
 /* Return comparison with reversed code of EXP and operands OP0 and OP1.
    Return NULL_RTX in case we fail to do the reversal.  */
 static rtx
-reversed_comparison (exp, mode, op0, op1)
-     rtx exp, op0, op1;
-     enum machine_mode mode;
+reversed_comparison (rtx exp, enum machine_mode mode, rtx op0, rtx op1)
 {
   enum rtx_code reversed_code = combine_reversed_comparison_code (exp);
   if (reversed_code == UNKNOWN)
     return NULL_RTX;
   else
-    return gen_binary (reversed_code, mode, op0, op1);
+    return simplify_gen_relational (reversed_code, mode, VOIDmode, op0, 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
-update_table_tick (x)
-     rtx x;
+update_table_tick (rtx x)
 {
   enum rtx_code code = GET_CODE (x);
   const char *fmt = GET_RTX_FORMAT (code);
@@ -11547,11 +10566,11 @@ update_table_tick (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;
     }
@@ -11564,9 +10583,7 @@ update_table_tick (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.  */
@@ -11581,41 +10598,37 @@ update_table_tick (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));
                break;
              }
          }
-         
+
        update_table_tick (XEXP (x, i));
       }
 }
 
 /* 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 (reg, insn, value)
-     rtx reg;
-     rtx insn;
-     rtx value;
+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
@@ -11635,8 +10648,7 @@ record_value_for_reg (reg, insn, 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);
@@ -11652,13 +10664,13 @@ record_value_for_reg (reg, insn, 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.  */
@@ -11674,40 +10686,40 @@ record_value_for_reg (reg, insn, 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));
     }
 }
@@ -11717,9 +10729,7 @@ record_value_for_reg (reg, insn, value)
    set is occurring.  */
 
 static void
-record_dead_and_set_regs_1 (dest, setter, data)
-     rtx dest, setter;
-     void *data;
+record_dead_and_set_regs_1 (rtx dest, rtx setter, void *data)
 {
   rtx record_dead_insn = (rtx) data;
 
@@ -11739,7 +10749,7 @@ record_dead_and_set_regs_1 (dest, setter, 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);
@@ -11754,15 +10764,14 @@ record_dead_and_set_regs_1 (dest, setter, 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 (insn)
-     rtx insn;
+record_dead_and_set_regs (rtx insn)
 {
   rtx link;
   unsigned int i;
@@ -11775,11 +10784,11 @@ record_dead_and_set_regs (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);
@@ -11790,11 +10799,11 @@ record_dead_and_set_regs (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);
@@ -11820,9 +10829,7 @@ record_dead_and_set_regs (insn)
    missed because of that.  */
 
 static void
-record_promoted_value (insn, subreg)
-     rtx insn;
-     rtx subreg;
+record_promoted_value (rtx insn, rtx subreg)
 {
   rtx links, set;
   unsigned int regno = REGNO (SUBREG_REG (subreg));
@@ -11844,10 +10851,10 @@ record_promoted_value (insn, 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)
@@ -11864,9 +10871,7 @@ record_promoted_value (insn, subreg)
    note what it implies to the registers used in it.  */
 
 static void
-check_promoted_subreg (insn, x)
-     rtx insn;
-     rtx x;
+check_promoted_subreg (rtx insn, rtx x)
 {
   if (GET_CODE (x) == SUBREG && SUBREG_PROMOTED_VAR_P (x)
       && GET_CODE (SUBREG_REG (x)) == REG)
@@ -11903,11 +10908,7 @@ check_promoted_subreg (insn, x)
    we don't know exactly what registers it was produced from.  */
 
 static int
-get_last_value_validate (loc, insn, tick, replace)
-     rtx *loc;
-     rtx insn;
-     int tick;
-     int replace;
+get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
 {
   rtx x = *loc;
   const char *fmt = GET_RTX_FORMAT (GET_CODE (x));
@@ -11919,18 +10920,18 @@ get_last_value_validate (loc, insn, tick, 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);
@@ -11957,9 +10958,7 @@ get_last_value_validate (loc, insn, tick, 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.  */
@@ -11973,15 +10972,13 @@ get_last_value_validate (loc, insn, tick, 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,
@@ -12007,8 +11004,7 @@ get_last_value_validate (loc, insn, tick, replace)
    is known longer known reliably.  */
 
 static rtx
-get_last_value (x)
-     rtx x;
+get_last_value (rtx x)
 {
   unsigned int regno;
   rtx value;
@@ -12021,13 +11017,13 @@ get_last_value (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
@@ -12040,7 +11036,7 @@ get_last_value (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
@@ -12049,20 +11045,20 @@ get_last_value (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;
@@ -12072,9 +11068,7 @@ get_last_value (x)
    that is set in an instruction more recent than FROM_CUID.  */
 
 static int
-use_crosses_set_p (x, from_cuid)
-     rtx x;
-     int from_cuid;
+use_crosses_set_p (rtx x, int from_cuid)
 {
   const char *fmt;
   int i;
@@ -12084,7 +11078,7 @@ use_crosses_set_p (x, 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,
@@ -12093,8 +11087,8 @@ use_crosses_set_p (x, 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;
     }
@@ -12132,10 +11126,7 @@ static int reg_dead_flag;
    reg_dead_flag to 1 if X is a CLOBBER and to -1 it is a SET.  */
 
 static void
-reg_dead_at_p_1 (dest, x, data)
-     rtx dest;
-     rtx x;
-     void *data ATTRIBUTE_UNUSED;
+reg_dead_at_p_1 (rtx dest, rtx x, void *data ATTRIBUTE_UNUSED)
 {
   unsigned int regno, endregno;
 
@@ -12144,7 +11135,7 @@ reg_dead_at_p_1 (dest, x, data)
 
   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;
@@ -12159,9 +11150,7 @@ reg_dead_at_p_1 (dest, x, data)
    must be assumed to be always live.  */
 
 static int
-reg_dead_at_p (reg, insn)
-     rtx reg;
-     rtx insn;
+reg_dead_at_p (rtx reg, rtx insn)
 {
   basic_block block;
   unsigned int i;
@@ -12169,8 +11158,8 @@ reg_dead_at_p (reg, 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;
@@ -12202,7 +11191,7 @@ reg_dead_at_p (reg, insn)
   else
     {
       FOR_EACH_BB (block)
-       if (insn == block->head)
+       if (insn == BB_HEAD (block))
          break;
 
       if (block == EXIT_BLOCK_PTR)
@@ -12220,8 +11209,7 @@ reg_dead_at_p (reg, insn)
    that in flow.c, but much simpler since we don't care about pseudos.  */
 
 static void
-mark_used_regs_combine (x)
-     rtx x;
+mark_used_regs_combine (rtx x)
 {
   RTX_CODE code = GET_CODE (x);
   unsigned int regno;
@@ -12272,7 +11260,7 @@ mark_used_regs_combine (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);
        }
@@ -12326,9 +11314,7 @@ mark_used_regs_combine (x)
    Return the note used to record the death, if there was one.  */
 
 rtx
-remove_death (regno, insn)
-     unsigned int regno;
-     rtx insn;
+remove_death (unsigned int regno, rtx insn)
 {
   rtx note = find_regno_note (insn, REG_DEAD, regno);
 
@@ -12352,12 +11338,8 @@ remove_death (regno, insn)
    notes will then be distributed as needed.  */
 
 static void
-move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
-     rtx x;
-     rtx maybe_kill_insn;
-     int from_cuid;
-     rtx to_insn;
-     rtx *pnotes;
+move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
+            rtx *pnotes)
 {
   const char *fmt;
   int len, i;
@@ -12366,7 +11348,7 @@ move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
   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.  */
@@ -12393,7 +11375,7 @@ move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
          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
@@ -12407,10 +11389,10 @@ move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
            {
              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++)
@@ -12431,15 +11413,15 @@ move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
                        && (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;
 
@@ -12525,9 +11507,7 @@ move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
    pattern of an insn.  X must be a REG.  */
 
 static int
-reg_bitfield_target_p (x, body)
-     rtx x;
-     rtx body;
+reg_bitfield_target_p (rtx x, rtx body)
 {
   int i;
 
@@ -12554,8 +11534,8 @@ reg_bitfield_target_p (x, 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;
     }
@@ -12572,19 +11552,11 @@ reg_bitfield_target_p (x, body)
    as appropriate.  I3 and I2 are the insns resulting from the combination
    insns including FROM (I2 may be zero).
 
-   ELIM_I2 and ELIM_I1 are either zero or registers that we know will
-   not need REG_DEAD notes because they are being substituted for.  This
-   saves searching in the most common cases.
-
    Each note in the list is either ignored or placed on some insns, depending
    on the type of note.  */
 
 static void
-distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
-     rtx notes;
-     rtx from_insn;
-     rtx i3, i2;
-     rtx elim_i2, elim_i1;
+distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
 {
   rtx note, next_note;
   rtx tem;
@@ -12610,6 +11582,10 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
          place = i3;
          break;
 
+       case REG_VALUE_PROFILE:
+         /* Just get rid of this note, as it is unused later anyway.  */
+         break;
+
        case REG_VTABLE_REF:
          /* ??? Should remain with *a particular* memory load.  Given the
             nature of vtable data, the last insn seems relatively safe.  */
@@ -12645,6 +11621,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
            abort ();
          break;
 
+       case REG_ALWAYS_RETURN:
        case REG_NORETURN:
        case REG_SETJMP:
          /* These notes must remain with the call.  It should not be
@@ -12778,8 +11755,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
          break;
 
        case REG_NONNEG:
-       case REG_WAS_0:
-         /* These notes say something about the value of a register prior
+         /* This note says something about the value of a register prior
             to the execution of an insn.  It is too much trouble to see
             if the note is still correct in all situations.  It is better
             to simply delete it.  */
@@ -12801,6 +11777,9 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                 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;
 
@@ -12818,6 +11797,9 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                 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;
 
@@ -12846,10 +11828,6 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                   && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
            place = i2;
 
-         if (rtx_equal_p (XEXP (note, 0), elim_i2)
-             || rtx_equal_p (XEXP (note, 0), elim_i1))
-           break;
-
          if (place == 0)
            {
              basic_block bb = this_basic_block;
@@ -12858,7 +11836,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                {
                  if (! INSN_P (tem))
                    {
-                     if (tem == bb->head)
+                     if (tem == BB_HEAD (bb))
                        break;
                      continue;
                    }
@@ -12903,11 +11881,12 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                             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, NULL_RTX, NULL_RTX);
+                         distribute_notes (old_notes, tem, tem, NULL_RTX);
                          distribute_links (LOG_LINKS (tem));
 
                          PUT_CODE (tem, NOTE);
@@ -12919,10 +11898,11 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                          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, NULL_RTX, NULL_RTX);
+                             distribute_notes (old_notes, cc0_setter,
+                                               cc0_setter, NULL_RTX);
                              distribute_links (LOG_LINKS (cc0_setter));
 
                              PUT_CODE (cc0_setter, NOTE);
@@ -12932,26 +11912,16 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                            }
 #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;
@@ -12983,7 +11953,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                      break;
                    }
 
-                 if (tem == bb->head)
+                 if (tem == BB_HEAD (bb))
                    break;
                }
 
@@ -13018,14 +11988,14 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                  || 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
@@ -13037,11 +12007,11 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                 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;
 
@@ -13057,7 +12027,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                         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;
@@ -13070,7 +12040,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                                = gen_rtx_EXPR_LIST (REG_DEAD, piece, NULL_RTX);
 
                              distribute_notes (new_note, place, place,
-                                               NULL_RTX, NULL_RTX, NULL_RTX);
+                                               NULL_RTX);
                            }
                          else if (! refers_to_regno_p (i, i + 1,
                                                        PATTERN (place), 0)
@@ -13080,7 +12050,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                              {
                                if (! INSN_P (tem))
                                  {
-                                   if (tem == bb->head)
+                                   if (tem == BB_HEAD (bb))
                                      {
                                        SET_BIT (refresh_blocks,
                                                 this_basic_block->index);
@@ -13139,12 +12109,11 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
 }
 \f
 /* Similarly to above, distribute the LOG_LINKS that used to be present on
-   I3, I2, and I1 to new locations.  This is also called in one case to
-   add a link pointing at I3 when I3's destination is changed.  */
+   I3, I2, and I1 to new locations.  This is also called to add a link
+   pointing at I3 when I3's destination is changed.  */
 
 static void
-distribute_links (links)
-     rtx links;
+distribute_links (rtx links)
 {
   rtx link, next_link;
 
@@ -13188,7 +12157,7 @@ distribute_links (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)))
          {
@@ -13202,6 +12171,8 @@ distribute_links (links)
            place = insn;
            break;
          }
+       else if (INSN_P (insn) && reg_set_p (reg, insn))
+         break;
 
       /* If we found a place to put the link, place it there unless there
         is already a link to the same insn as LINK at that point.  */
@@ -13229,11 +12200,37 @@ distribute_links (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
-insn_cuid (insn)
-     rtx insn;
+insn_cuid (rtx insn)
 {
   while (insn != 0 && INSN_UID (insn) > max_uid_cuid
         && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == USE)
@@ -13246,8 +12243,7 @@ insn_cuid (insn)
 }
 \f
 void
-dump_combine_stats (file)
-     FILE *file;
+dump_combine_stats (FILE *file)
 {
   fnotice
     (file,
@@ -13256,8 +12252,7 @@ dump_combine_stats (file)
 }
 
 void
-dump_combine_total_stats (file)
-     FILE *file;
+dump_combine_total_stats (FILE *file)
 {
   fnotice
     (file,