OSDN Git Service

* check.c (same_type_check): Typo fix in comment.
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index eb07dbb..e85e9d1 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, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -16,8 +16,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 /* This module is essentially the "combiner" phase of the U. of Arizona
    Portable Optimizer, but redone to work on our list-structured
@@ -53,6 +53,10 @@ 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_notes) 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
@@ -90,7 +94,14 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "real.h"
 #include "toplev.h"
 #include "target.h"
+#include "optabs.h"
+#include "insn-codes.h"
 #include "rtlhooks-def.h"
+/* Include output.h for dump_file.  */
+#include "output.h"
+#include "params.h"
+#include "timevar.h"
+#include "tree-pass.h"
 
 /* Number of attempts to combine instructions in this function.  */
 
@@ -112,6 +123,16 @@ static int combine_successes;
 
 static int total_attempts, total_merges, total_extras, total_successes;
 
+/* Sometimes combine tries to replace the right hand side of an insn
+   with the value of a REG_EQUAL note.  This is the insn that has been
+   so modified, or null if none.  */
+
+static rtx replaced_rhs_insn;
+
+/* When REPLACED_RHS_INSN is nonnull, this is a copy of the new right
+   hand side.  */
+
+static rtx replaced_rhs_value;
 \f
 /* Vector mapping INSN_UIDs to cuids.
    The cuids are like uids but increase monotonically always.
@@ -128,12 +149,6 @@ static int max_uid_cuid;
 #define INSN_CUID(INSN) \
 (INSN_UID (INSN) > max_uid_cuid ? insn_cuid (INSN) : uid_cuid[INSN_UID (INSN)])
 
-/* In case BITS_PER_WORD == HOST_BITS_PER_WIDE_INT, shifting by
-   BITS_PER_WORD would invoke undefined behavior.  Work around it.  */
-
-#define UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD(val) \
-  (((unsigned HOST_WIDE_INT) (val) << (BITS_PER_WORD - 1)) << 1)
-
 /* Maximum register number, which is the size of the tables below.  */
 
 static unsigned int combine_max_regno;
@@ -156,7 +171,7 @@ struct reg_stat {
 
      (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.
+        to a register.  Often just its form is helpful.
 
      Therefore, we maintain the following fields:
 
@@ -203,13 +218,13 @@ struct reg_stat {
   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
+     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.  */
 
   unsigned HOST_WIDE_INT       last_set_nonzero_bits;
   char                         last_set_sign_bit_copies;
-  ENUM_BITFIELD(machine_mode)  last_set_mode : 8; 
+  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
@@ -232,6 +247,19 @@ struct reg_stat {
   unsigned char                        sign_bit_copies;
 
   unsigned HOST_WIDE_INT       nonzero_bits;
+
+  /* Record the value of the label_tick when the last truncation
+     happened.  The field truncated_to_mode is only valid if
+     truncation_label == label_tick.  */
+
+  int                          truncation_label;
+
+  /* Record the last truncation seen for this register.  If truncation
+     is not a nop to this mode we might be able to save an explicit
+     truncation if we know that value already contains a truncated
+     value.  */
+
+  ENUM_BITFIELD(machine_mode)  truncated_to_mode : 8;
 };
 
 static struct reg_stat *reg_stat;
@@ -282,6 +310,15 @@ static basic_block this_basic_block;
    those blocks as starting points.  */
 static sbitmap refresh_blocks;
 \f
+/* The following array records the insn_rtx_cost for every insn
+   in the instruction stream.  */
+
+static int *uid_insn_cost;
+
+/* Length of the currently allocated uid_insn_cost array.  */
+
+static int last_insn_cost;
+
 /* Incremented for each label.  */
 
 static int label_tick;
@@ -301,15 +338,14 @@ static int nonzero_sign_valid;
 
 \f
 /* Record one modification to rtl structure
-   to be undone by storing old_contents into *where.
-   is_int is 1 if the contents are an int.  */
+   to be undone by storing old_contents into *where.  */
 
 struct undo
 {
   struct undo *next;
-  int is_int;
-  union {rtx r; int i;} old_contents;
-  union {rtx *r; int *i;} where;
+  enum { UNDO_RTX, UNDO_INT, UNDO_MODE } kind;
+  union { rtx r; int i; enum machine_mode m; } old_contents;
+  union { rtx *r; int *i; } where;
 };
 
 /* Record a bunch of changes to be undone, up to MAX_UNDO of them.
@@ -365,26 +401,30 @@ 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 canon_reg_for_combine (rtx, rtx);
 static rtx force_to_mode (rtx, enum machine_mode,
-                         unsigned HOST_WIDE_INT, rtx, int);
+                         unsigned HOST_WIDE_INT, 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 distribute_and_simplify_rtx (rtx, int);
+static rtx simplify_and_const_int_1 (enum machine_mode, rtx,
+                                    unsigned HOST_WIDE_INT);
 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,
+static rtx simplify_shift_const_1 (enum rtx_code, enum machine_mode, rtx, 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 check_conversions (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);
@@ -394,15 +434,16 @@ 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_notes (rtx, rtx, 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);
+static void record_truncated_value (rtx);
+static bool reg_truncated_to_mode (enum machine_mode, rtx);
+static rtx gen_lowpart_or_truncate (enum machine_mode, rtx);
 \f
 
 /* It is not safe to use ordinary gen_lowpart in combine.
@@ -410,12 +451,19 @@ static bool unmentioned_reg_p (rtx, rtx);
 #undef RTL_HOOKS_GEN_LOWPART
 #define RTL_HOOKS_GEN_LOWPART              gen_lowpart_for_combine
 
+/* Our implementation of gen_lowpart never emits a new pseudo.  */
+#undef RTL_HOOKS_GEN_LOWPART_NO_EMIT
+#define RTL_HOOKS_GEN_LOWPART_NO_EMIT      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
 
+#undef RTL_HOOKS_REG_TRUNCATED_TO_MODE
+#define RTL_HOOKS_REG_TRUNCATED_TO_MODE    reg_truncated_to_mode
+
 static const struct rtl_hooks combine_rtl_hooks = RTL_HOOKS_INITIALIZER;
 
 \f
@@ -444,9 +492,8 @@ do_SUBST (rtx *into, rtx newval)
     {
       /* Sanity check that we're replacing oldval with a CONST_INT
         that is a valid sign-extension for the original mode.  */
-      if (INTVAL (newval) != trunc_int_for_mode (INTVAL (newval),
-                                                GET_MODE (oldval)))
-       abort ();
+      gcc_assert (INTVAL (newval)
+                 == trunc_int_for_mode (INTVAL (newval), GET_MODE (oldval)));
 
       /* Replacing the operand of a SUBREG or a ZERO_EXTEND with a
         CONST_INT is not valid, because after the replacement, the
@@ -454,19 +501,18 @@ do_SUBST (rtx *into, rtx newval)
         when do_SUBST is called to replace the operand thereof, so we
         perform this test on oldval instead, checking whether an
         invalid replacement took place before we got here.  */
-      if ((GET_CODE (oldval) == SUBREG
-          && GET_CODE (SUBREG_REG (oldval)) == CONST_INT)
-         || (GET_CODE (oldval) == ZERO_EXTEND
-             && GET_CODE (XEXP (oldval, 0)) == CONST_INT))
-       abort ();
+      gcc_assert (!(GET_CODE (oldval) == SUBREG
+                   && GET_CODE (SUBREG_REG (oldval)) == CONST_INT));
+      gcc_assert (!(GET_CODE (oldval) == ZERO_EXTEND
+                   && GET_CODE (XEXP (oldval, 0)) == CONST_INT));
     }
 
   if (undobuf.frees)
     buf = undobuf.frees, undobuf.frees = buf->next;
   else
-    buf = xmalloc (sizeof (struct undo));
+    buf = XNEW (struct undo);
 
-  buf->is_int = 0;
+  buf->kind = UNDO_RTX;
   buf->where.r = into;
   buf->old_contents.r = oldval;
   *into = newval;
@@ -492,9 +538,9 @@ do_SUBST_INT (int *into, int newval)
   if (undobuf.frees)
     buf = undobuf.frees, undobuf.frees = buf->next;
   else
-    buf = xmalloc (sizeof (struct undo));
+    buf = XNEW (struct undo);
 
-  buf->is_int = 1;
+  buf->kind = UNDO_INT;
   buf->where.i = into;
   buf->old_contents.i = oldval;
   *into = newval;
@@ -503,13 +549,150 @@ do_SUBST_INT (int *into, int newval)
 }
 
 #define SUBST_INT(INTO, NEWVAL)  do_SUBST_INT(&(INTO), (NEWVAL))
+
+/* Similar to SUBST, but just substitute the mode.  This is used when
+   changing the mode of a pseudo-register, so that any other
+   references to the entry in the regno_reg_rtx array will change as
+   well.  */
+
+static void
+do_SUBST_MODE (rtx *into, enum machine_mode newval)
+{
+  struct undo *buf;
+  enum machine_mode oldval = GET_MODE (*into);
+
+  if (oldval == newval)
+    return;
+
+  if (undobuf.frees)
+    buf = undobuf.frees, undobuf.frees = buf->next;
+  else
+    buf = XNEW (struct undo);
+
+  buf->kind = UNDO_MODE;
+  buf->where.r = into;
+  buf->old_contents.m = oldval;
+  PUT_MODE (*into, newval);
+
+  buf->next = undobuf.undos, undobuf.undos = buf;
+}
+
+#define SUBST_MODE(INTO, NEWVAL)  do_SUBST_MODE(&(INTO), (NEWVAL))
+\f
+/* Subroutine of try_combine.  Determine whether the combine replacement
+   patterns NEWPAT and NEWI2PAT are cheaper according to insn_rtx_cost
+   that the original instruction sequence I1, I2 and I3.  Note that I1
+   and/or NEWI2PAT may be NULL_RTX.  This function returns false, if the
+   costs of all instructions can be estimated, and the replacements are
+   more expensive than the original sequence.  */
+
+static bool
+combine_validate_cost (rtx i1, rtx i2, rtx i3, rtx newpat, rtx newi2pat)
+{
+  int i1_cost, i2_cost, i3_cost;
+  int new_i2_cost, new_i3_cost;
+  int old_cost, new_cost;
+
+  /* Lookup the original insn_rtx_costs.  */
+  i2_cost = INSN_UID (i2) <= last_insn_cost
+           ? uid_insn_cost[INSN_UID (i2)] : 0;
+  i3_cost = INSN_UID (i3) <= last_insn_cost
+           ? uid_insn_cost[INSN_UID (i3)] : 0;
+
+  if (i1)
+    {
+      i1_cost = INSN_UID (i1) <= last_insn_cost
+               ? uid_insn_cost[INSN_UID (i1)] : 0;
+      old_cost = (i1_cost > 0 && i2_cost > 0 && i3_cost > 0)
+                ? i1_cost + i2_cost + i3_cost : 0;
+    }
+  else
+    {
+      old_cost = (i2_cost > 0 && i3_cost > 0) ? i2_cost + i3_cost : 0;
+      i1_cost = 0;
+    }
+
+  /* Calculate the replacement insn_rtx_costs.  */
+  new_i3_cost = insn_rtx_cost (newpat);
+  if (newi2pat)
+    {
+      new_i2_cost = insn_rtx_cost (newi2pat);
+      new_cost = (new_i2_cost > 0 && new_i3_cost > 0)
+                ? new_i2_cost + new_i3_cost : 0;
+    }
+  else
+    {
+      new_cost = new_i3_cost;
+      new_i2_cost = 0;
+    }
+
+  if (undobuf.other_insn)
+    {
+      int old_other_cost, new_other_cost;
+
+      old_other_cost = (INSN_UID (undobuf.other_insn) <= last_insn_cost
+                       ? uid_insn_cost[INSN_UID (undobuf.other_insn)] : 0);
+      new_other_cost = insn_rtx_cost (PATTERN (undobuf.other_insn));
+      if (old_other_cost > 0 && new_other_cost > 0)
+       {
+         old_cost += old_other_cost;
+         new_cost += new_other_cost;
+       }
+      else
+       old_cost = 0;
+    }
+
+  /* Disallow this recombination if both new_cost and old_cost are
+     greater than zero, and new_cost is greater than old cost.  */
+  if (old_cost > 0
+      && new_cost > old_cost)
+    {
+      if (dump_file)
+       {
+         if (i1)
+           {
+             fprintf (dump_file,
+                      "rejecting combination of insns %d, %d and %d\n",
+                      INSN_UID (i1), INSN_UID (i2), INSN_UID (i3));
+             fprintf (dump_file, "original costs %d + %d + %d = %d\n",
+                      i1_cost, i2_cost, i3_cost, old_cost);
+           }
+         else
+           {
+             fprintf (dump_file,
+                      "rejecting combination of insns %d and %d\n",
+                      INSN_UID (i2), INSN_UID (i3));
+             fprintf (dump_file, "original costs %d + %d = %d\n",
+                      i2_cost, i3_cost, old_cost);
+           }
+
+         if (newi2pat)
+           {
+             fprintf (dump_file, "replacement costs %d + %d = %d\n",
+                      new_i2_cost, new_i3_cost, new_cost);
+           }
+         else
+           fprintf (dump_file, "replacement cost %d\n", new_cost);
+       }
+
+      return false;
+    }
+
+  /* Update the uid_insn_cost array with the replacement costs.  */
+  uid_insn_cost[INSN_UID (i2)] = new_i2_cost;
+  uid_insn_cost[INSN_UID (i3)] = new_i3_cost;
+  if (i1)
+    uid_insn_cost[INSN_UID (i1)] = 0;
+
+  return true;
+}
 \f
 /* Main entry point for combiner.  F is the first insn of the function.
    NREGS is the first unused pseudo-reg number.
 
    Return nonzero if the combiner has turned an indirect jump
    instruction into a direct jump.  */
-int
+static int
 combine_instructions (rtx f, unsigned int nregs)
 {
   rtx insn, next;
@@ -517,7 +700,9 @@ combine_instructions (rtx f, unsigned int nregs)
   rtx prev;
 #endif
   int i;
+  unsigned int j = 0;
   rtx links, nextlinks;
+  sbitmap_iterator sbi;
 
   int new_direct_jump_p = 0;
 
@@ -530,7 +715,7 @@ combine_instructions (rtx f, unsigned int nregs)
 
   rtl_hooks = combine_rtl_hooks;
 
-  reg_stat = xcalloc (nregs, sizeof (struct reg_stat));
+  reg_stat = XCNEWVEC (struct reg_stat, nregs);
 
   init_recog_no_volatile ();
 
@@ -540,7 +725,7 @@ combine_instructions (rtx f, unsigned int nregs)
     if (INSN_UID (insn) > i)
       i = INSN_UID (insn);
 
-  uid_cuid = xmalloc ((i + 1) * sizeof (int));
+  uid_cuid = XNEWVEC (int, i + 1);
   max_uid_cuid = i;
 
   nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
@@ -568,6 +753,10 @@ combine_instructions (rtx f, unsigned int nregs)
   refresh_blocks = sbitmap_alloc (last_basic_block);
   sbitmap_zero (refresh_blocks);
 
+  /* Allocate array of current insn_rtx_costs.  */
+  uid_insn_cost = XCNEWVEC (int, max_uid_cuid + 1);
+  last_insn_cost = max_uid_cuid;
+
   for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
     {
       uid_cuid[INSN_UID (insn)] = ++i;
@@ -586,9 +775,16 @@ combine_instructions (rtx f, unsigned int nregs)
              set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX,
                                                NULL);
 #endif
+
+         /* Record the current insn_rtx_cost of this instruction.  */
+         if (NONJUMP_INSN_P (insn))
+           uid_insn_cost[INSN_UID (insn)] = insn_rtx_cost (PATTERN (insn));
+         if (dump_file)
+           fprintf(dump_file, "insn_cost %d: %d\n",
+                   INSN_UID (insn), uid_insn_cost[INSN_UID (insn)]);
        }
 
-      if (GET_CODE (insn) == CODE_LABEL)
+      if (LABEL_P (insn))
        label_tick++;
     }
 
@@ -605,19 +801,19 @@ combine_instructions (rtx f, unsigned int nregs)
   FOR_EACH_BB (this_basic_block)
     {
       for (insn = BB_HEAD (this_basic_block);
-           insn != NEXT_INSN (BB_END (this_basic_block));
+          insn != NEXT_INSN (BB_END (this_basic_block));
           insn = next ? next : NEXT_INSN (insn))
        {
          next = 0;
 
-         if (GET_CODE (insn) == CODE_LABEL)
+         if (LABEL_P (insn))
            label_tick++;
 
          else if (INSN_P (insn))
            {
              /* See if we know about function return values before this
                 insn based upon SUBREG flags.  */
-             check_promoted_subreg (insn, PATTERN (insn));
+             check_conversions (insn, PATTERN (insn));
 
              /* Try this insn with each insn it links back to.  */
 
@@ -634,7 +830,7 @@ combine_instructions (rtx f, unsigned int nregs)
 
                  /* If the linked insn has been replaced by a note, then there
                     is no point in pursuing this chain any further.  */
-                 if (GET_CODE (link) == NOTE)
+                 if (NOTE_P (link))
                    continue;
 
                  for (nextlinks = LOG_LINKS (link);
@@ -654,9 +850,9 @@ combine_instructions (rtx f, unsigned int nregs)
                 We need this special code because data flow connections
                 via CC0 do not get entered in LOG_LINKS.  */
 
-             if (GET_CODE (insn) == JUMP_INSN
+             if (JUMP_P (insn)
                  && (prev = prev_nonnote_insn (insn)) != 0
-                 && GET_CODE (prev) == INSN
+                 && NONJUMP_INSN_P (prev)
                  && sets_cc0_p (PATTERN (prev)))
                {
                  if ((next = try_combine (insn, prev,
@@ -672,9 +868,9 @@ combine_instructions (rtx f, unsigned int nregs)
                }
 
              /* Do the same for an insn that explicitly references CC0.  */
-             if (GET_CODE (insn) == INSN
+             if (NONJUMP_INSN_P (insn)
                  && (prev = prev_nonnote_insn (insn)) != 0
-                 && GET_CODE (prev) == INSN
+                 && NONJUMP_INSN_P (prev)
                  && sets_cc0_p (PATTERN (prev))
                  && GET_CODE (PATTERN (insn)) == SET
                  && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (insn))))
@@ -695,11 +891,11 @@ combine_instructions (rtx f, unsigned int nregs)
                 explicitly references CC0.  If so, try this insn, that insn,
                 and its predecessor if it sets CC0.  */
              for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
-               if (GET_CODE (XEXP (links, 0)) == INSN
+               if (NONJUMP_INSN_P (XEXP (links, 0))
                    && GET_CODE (PATTERN (XEXP (links, 0))) == SET
                    && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (XEXP (links, 0))))
                    && (prev = prev_nonnote_insn (XEXP (links, 0))) != 0
-                   && GET_CODE (prev) == INSN
+                   && NONJUMP_INSN_P (prev)
                    && sets_cc0_p (PATTERN (prev))
                    && (next = try_combine (insn, XEXP (links, 0),
                                            prev, &new_direct_jump_p)) != 0)
@@ -723,25 +919,31 @@ combine_instructions (rtx f, unsigned int nregs)
                  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
+                     && (note = XEXP (note, 0), GET_CODE (note)) != 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)))
+                     && ! unmentioned_reg_p (note, SET_SRC (set))
+                     && (GET_MODE (note) == VOIDmode
+                         ? SCALAR_INT_MODE_P (GET_MODE (SET_DEST (set)))
+                         : GET_MODE (SET_DEST (set)) == GET_MODE (note)))
                    {
                      /* 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);
+                     SET_SRC (set) = note;
+                     replaced_rhs_insn = temp;
+                     replaced_rhs_value = copy_rtx (note);
                      next = try_combine (insn, temp, NULL_RTX,
                                          &new_direct_jump_p);
+                     replaced_rhs_insn = NULL;
                      if (next)
                        goto retry;
                      SET_SRC (set) = orig;
                    }
                }
 
-             if (GET_CODE (insn) != NOTE)
+             if (!NOTE_P (insn))
                record_dead_and_set_regs (insn);
 
            retry:
@@ -751,9 +953,9 @@ combine_instructions (rtx f, unsigned int nregs)
     }
   clear_bb_flags ();
 
-  EXECUTE_IF_SET_IN_SBITMAP (refresh_blocks, 0, i,
-                            BASIC_BLOCK (i)->flags |= BB_DIRTY);
-  new_direct_jump_p |= purge_all_dead_edges (0);
+  EXECUTE_IF_SET_IN_SBITMAP (refresh_blocks, 0, j, sbi)
+    BASIC_BLOCK (j)->flags |= BB_DIRTY;
+  new_direct_jump_p |= purge_all_dead_edges ();
   delete_noop_moves ();
 
   update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
@@ -762,6 +964,7 @@ combine_instructions (rtx f, unsigned int nregs)
 
   /* Clean up.  */
   sbitmap_free (refresh_blocks);
+  free (uid_insn_cost);
   free (reg_stat);
   free (uid_cuid);
 
@@ -845,11 +1048,12 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set,
 {
   unsigned int num;
 
-  if (GET_CODE (x) == REG
+  if (REG_P (x)
       && REGNO (x) >= FIRST_PSEUDO_REGISTER
       /* If this register is undefined at the start of the file, we can't
         say what its contents were.  */
-      && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, REGNO (x))
+      && ! REGNO_REG_SET_P
+        (ENTRY_BLOCK_PTR->next_bb->il.rtl->global_live_at_start, REGNO (x))
       && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
     {
       if (set == 0 || GET_CODE (set) == CLOBBER)
@@ -979,7 +1183,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
                 something to tell them apart, e.g. different modes.  For
                 now, we forgo such complicated tests and simply disallow
                 combining of USES of pseudo registers with any other USE.  */
-             if (GET_CODE (XEXP (elt, 0)) == REG
+             if (REG_P (XEXP (elt, 0))
                  && GET_CODE (PATTERN (i3)) == PARALLEL)
                {
                  rtx i3pat = PATTERN (i3);
@@ -991,7 +1195,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
                      rtx i3elt = XVECEXP (i3pat, 0, i);
 
                      if (GET_CODE (i3elt) == USE
-                         && GET_CODE (XEXP (i3elt, 0)) == REG
+                         && REG_P (XEXP (i3elt, 0))
                          && (REGNO (XEXP (i3elt, 0)) == regno
                              ? reg_set_between_p (XEXP (elt, 0),
                                                   PREV_INSN (insn), i3)
@@ -1054,14 +1258,16 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
       /* Can't merge a function call.  */
       || GET_CODE (src) == CALL
       /* Don't eliminate a function call argument.  */
-      || (GET_CODE (i3) == CALL_INSN
+      || (CALL_P (i3)
          && (find_reg_fusage (i3, USE, dest)
-             || (GET_CODE (dest) == REG
+             || (REG_P (dest)
                  && REGNO (dest) < FIRST_PSEUDO_REGISTER
                  && global_regs[REGNO (dest)])))
       /* Don't substitute into an incremented register.  */
       || FIND_REG_INC_NOTE (i3, dest)
       || (succ && FIND_REG_INC_NOTE (succ, dest))
+      /* Don't substitute into a non-local goto, this confuses CFG.  */
+      || (JUMP_P (i3) && find_reg_note (i3, REG_NON_LOCAL_GOTO, NULL_RTX))
 #if 0
       /* Don't combine the end of a libcall into anything.  */
       /* ??? This gives worse code, and appears to be unnecessary, since no
@@ -1083,7 +1289,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
         are intervening stores.  Also, don't move a volatile asm or
         UNSPEC_VOLATILE across any other insns.  */
       || (! all_adjacent
-         && (((GET_CODE (src) != MEM
+         && (((!MEM_P (src)
                || ! find_reg_note (insn, REG_EQUIV, src))
               && use_crosses_set_p (src, INSN_CUID (insn)))
              || (GET_CODE (src) == ASM_OPERANDS && MEM_VOLATILE_P (src))
@@ -1101,7 +1307,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
     return 0;
 
   /* DEST must either be a REG or CC0.  */
-  if (GET_CODE (dest) == REG)
+  if (REG_P (dest))
     {
       /* If register alignment is being enforced for multi-word items in all
         cases except for parameters, it is possible to have a register copy
@@ -1112,7 +1318,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
         Also, on some machines we don't want to extend the life of a hard
         register.  */
 
-      if (GET_CODE (src) == REG
+      if (REG_P (src)
          && ((REGNO (dest) < FIRST_PSEUDO_REGISTER
               && ! HARD_REGNO_MODE_OK (REGNO (dest), GET_MODE (dest)))
              /* Don't extend the life of a hard register unless it is
@@ -1129,16 +1335,30 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
   else if (GET_CODE (dest) != CC0)
     return 0;
 
-  /* Don't substitute for a register intended as a clobberable operand.
-     Similarly, don't substitute an expression containing a register that
-     will be clobbered in I3.  */
+
   if (GET_CODE (PATTERN (i3)) == PARALLEL)
     for (i = XVECLEN (PATTERN (i3), 0) - 1; i >= 0; i--)
-      if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER
-         && (reg_overlap_mentioned_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0),
-                                      src)
-             || rtx_equal_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0), dest)))
-       return 0;
+      if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER)
+       {
+         /* Don't substitute for a register intended as a clobberable
+            operand.  */
+         rtx reg = XEXP (XVECEXP (PATTERN (i3), 0, i), 0);
+         if (rtx_equal_p (reg, dest))
+           return 0;
+
+         /* If the clobber represents an earlyclobber operand, we must not
+            substitute an expression containing the clobbered register.
+            As we do not analyze the constraint strings here, we have to
+            make the conservative assumption.  However, if the register is
+            a fixed hard reg, the clobber cannot represent any operand;
+            we leave it up to the machine description to either accept or
+            reject use-and-clobber patterns.  */
+         if (!REG_P (reg)
+             || REGNO (reg) >= FIRST_PSEUDO_REGISTER
+             || !fixed_regs[REGNO (reg)])
+           if (reg_overlap_mentioned_p (reg, src))
+             return 0;
+       }
 
   /* If INSN contains anything volatile, or is an `asm' (whether volatile
      or not), reject, unless nothing volatile comes between it and I3 */
@@ -1147,10 +1367,10 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
     {
       /* Make sure succ doesn't contain a volatile reference.  */
       if (succ != 0 && volatile_refs_p (PATTERN (succ)))
-        return 0;
+       return 0;
 
       for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
-        if (INSN_P (p) && p != succ && volatile_refs_p (PATTERN (p)))
+       if (INSN_P (p) && p != succ && volatile_refs_p (PATTERN (p)))
          return 0;
     }
 
@@ -1158,7 +1378,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
      to be an explicit register variable, and was chosen for a reason.  */
 
   if (GET_CODE (src) == ASM_OPERANDS
-      && GET_CODE (dest) == REG && REGNO (dest) < FIRST_PSEUDO_REGISTER)
+      && REG_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER)
     return 0;
 
   /* If there are any volatile insns between INSN and I3, reject, because
@@ -1168,17 +1388,21 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
     if (INSN_P (p) && p != succ && volatile_insn_p (PATTERN (p)))
       return 0;
 
-  /* If INSN or I2 contains an autoincrement or autodecrement,
-     make sure that register is not used between there and I3,
-     and not already used in I3 either.
+  /* If INSN contains an autoincrement or autodecrement, make sure that
+     register is not used between there and I3, and not already used in
+     I3 either.  Neither must it be used in PRED or SUCC, if they exist.
      Also insist that I3 not be a jump; if it were one
      and the incremented register were spilled, we would lose.  */
 
 #ifdef AUTO_INC_DEC
   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
     if (REG_NOTE_KIND (link) == REG_INC
-       && (GET_CODE (i3) == JUMP_INSN
+       && (JUMP_P (i3)
            || reg_used_between_p (XEXP (link, 0), insn, i3)
+           || (pred != NULL_RTX
+               && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (pred)))
+           || (succ != NULL_RTX
+               && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (succ)))
            || reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i3))))
       return 0;
 #endif
@@ -1194,7 +1418,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
      but that would be much slower, and this ought to be equivalent.  */
 
   p = prev_nonnote_insn (insn);
-  if (p && p != pred && GET_CODE (p) == INSN && sets_cc0_p (PATTERN (p))
+  if (p && p != pred && NONJUMP_INSN_P (p) && sets_cc0_p (PATTERN (p))
       && ! all_adjacent)
     return 0;
 #endif
@@ -1217,12 +1441,12 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
 
    Consider:
 
-         (set (reg:DI 101) (reg:DI 100))
+        (set (reg:DI 101) (reg:DI 100))
         (set (subreg:SI (reg:DI 101) 0) <foo>)
 
    This is NOT equivalent to:
 
-         (parallel [(set (subreg:SI (reg:DI 100) 0) <foo>)
+        (parallel [(set (subreg:SI (reg:DI 100) 0) <foo>)
                    (set (reg:DI 101) (reg:DI 100))])
 
    Not only does this modify 100 (in which case it might still be valid
@@ -1257,6 +1481,7 @@ combinable_i3pat (rtx i3, rtx *loc, rtx i2dest, rtx i1dest,
       rtx dest = SET_DEST (set);
       rtx src = SET_SRC (set);
       rtx inner_dest = dest;
+      rtx subdest;
 
       while (GET_CODE (inner_dest) == STRICT_LOW_PART
             || GET_CODE (inner_dest) == SUBREG
@@ -1268,7 +1493,7 @@ combinable_i3pat (rtx i3, rtx *loc, rtx i2dest, rtx i1dest,
         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
+          (!MEM_P (inner_dest)
            || rtx_equal_p (i2dest, inner_dest)
            || (i1dest && rtx_equal_p (i1dest, inner_dest)))
           && (reg_overlap_mentioned_p (i2dest, inner_dest)
@@ -1284,34 +1509,42 @@ combinable_i3pat (rtx i3, rtx *loc, rtx i2dest, rtx i1dest,
             function argument; the all_adjacent test in can_combine_p also
             checks this; here, we do a more specific test for this case.  */
 
-         || (GET_CODE (inner_dest) == REG
+         || (REG_P (inner_dest)
              && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
              && (! HARD_REGNO_MODE_OK (REGNO (inner_dest),
                                        GET_MODE (inner_dest))))
          || (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src)))
        return 0;
 
-      /* If DEST is used in I3, it is being killed in this insn,
-        so record that for later.
+      /* If DEST is used in I3, it is being killed in this insn, so
+        record that for later.  We have to consider paradoxical
+        subregs here, since they kill the whole register, but we
+        ignore partial subregs, STRICT_LOW_PART, etc.
         Never add REG_DEAD notes for the FRAME_POINTER_REGNUM or the
         STACK_POINTER_REGNUM, since these are always considered to be
         live.  Similarly for ARG_POINTER_REGNUM if it is fixed.  */
-      if (pi3dest_killed && GET_CODE (dest) == REG
-         && reg_referenced_p (dest, PATTERN (i3))
-         && REGNO (dest) != FRAME_POINTER_REGNUM
+      subdest = dest;
+      if (GET_CODE (subdest) == SUBREG
+         && (GET_MODE_SIZE (GET_MODE (subdest))
+             >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (subdest)))))
+       subdest = SUBREG_REG (subdest);
+      if (pi3dest_killed
+         && REG_P (subdest)
+         && reg_referenced_p (subdest, PATTERN (i3))
+         && REGNO (subdest) != FRAME_POINTER_REGNUM
 #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
-         && REGNO (dest) != HARD_FRAME_POINTER_REGNUM
+         && REGNO (subdest) != HARD_FRAME_POINTER_REGNUM
 #endif
 #if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
-         && (REGNO (dest) != ARG_POINTER_REGNUM
-             || ! fixed_regs [REGNO (dest)])
+         && (REGNO (subdest) != ARG_POINTER_REGNUM
+             || ! fixed_regs [REGNO (subdest)])
 #endif
-         && REGNO (dest) != STACK_POINTER_REGNUM)
+         && REGNO (subdest) != STACK_POINTER_REGNUM)
        {
          if (*pi3dest_killed)
            return 0;
 
-         *pi3dest_killed = dest;
+         *pi3dest_killed = subdest;
        }
     }
 
@@ -1373,7 +1606,7 @@ cant_combine_insn_p (rtx insn)
   /* 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.
+     substitutions of likely-spilled regs, reload might die.
      As an exception, we allow combinations involving fixed regs; these are
      not available to the register allocator so there's no risk involved.  */
 
@@ -1398,6 +1631,85 @@ cant_combine_insn_p (rtx insn)
   return 0;
 }
 
+struct likely_spilled_retval_info
+{
+  unsigned regno, nregs;
+  unsigned mask;
+};
+
+/* Called via note_stores by likely_spilled_retval_p.  Remove from info->mask
+   hard registers that are known to be written to / clobbered in full.  */
+static void
+likely_spilled_retval_1 (rtx x, rtx set, void *data)
+{
+  struct likely_spilled_retval_info *info = data;
+  unsigned regno, nregs;
+  unsigned new_mask;
+
+  if (!REG_P (XEXP (set, 0)))
+    return;
+  regno = REGNO (x);
+  if (regno >= info->regno + info->nregs)
+    return;
+  nregs = hard_regno_nregs[regno][GET_MODE (x)];
+  if (regno + nregs <= info->regno)
+    return;
+  new_mask = (2U << (nregs - 1)) - 1;
+  if (regno < info->regno)
+    new_mask >>= info->regno - regno;
+  else
+    new_mask <<= regno - info->regno;
+  info->mask &= new_mask;
+}
+
+/* Return nonzero iff part of the return value is live during INSN, and
+   it is likely spilled.  This can happen when more than one insn is needed
+   to copy the return value, e.g. when we consider to combine into the
+   second copy insn for a complex value.  */
+
+static int
+likely_spilled_retval_p (rtx insn)
+{
+  rtx use = BB_END (this_basic_block);
+  rtx reg, p;
+  unsigned regno, nregs;
+  /* We assume here that no machine mode needs more than
+     32 hard registers when the value overlaps with a register
+     for which FUNCTION_VALUE_REGNO_P is true.  */
+  unsigned mask;
+  struct likely_spilled_retval_info info;
+
+  if (!NONJUMP_INSN_P (use) || GET_CODE (PATTERN (use)) != USE || insn == use)
+    return 0;
+  reg = XEXP (PATTERN (use), 0);
+  if (!REG_P (reg) || !FUNCTION_VALUE_REGNO_P (REGNO (reg)))
+    return 0;
+  regno = REGNO (reg);
+  nregs = hard_regno_nregs[regno][GET_MODE (reg)];
+  if (nregs == 1)
+    return 0;
+  mask = (2U << (nregs - 1)) - 1;
+
+  /* Disregard parts of the return value that are set later.  */
+  info.regno = regno;
+  info.nregs = nregs;
+  info.mask = mask;
+  for (p = PREV_INSN (use); info.mask && p != insn; p = PREV_INSN (p))
+    note_stores (PATTERN (insn), likely_spilled_retval_1, &info);
+  mask = info.mask;
+
+  /* Check if any of the (probably) live return value registers is
+     likely spilled.  */
+  nregs --;
+  do
+    {
+      if ((mask & 1 << nregs)
+         && CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (regno + nregs)))
+       return 1;
+    } while (nregs--);
+  return 0;
+}
+
 /* Adjust INSN after we made a change to its destination.
 
    Changing the destination can invalidate notes that say something about
@@ -1425,6 +1737,50 @@ adjust_for_new_dest (rtx insn)
   distribute_links (gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX));
 }
 
+/* Return TRUE if combine can reuse reg X in mode MODE.
+   ADDED_SETS is nonzero if the original set is still required.  */
+static bool
+can_change_dest_mode (rtx x, int added_sets, enum machine_mode mode)
+{
+  unsigned int regno;
+
+  if (!REG_P(x))
+    return false;
+
+  regno = REGNO (x);
+  /* Allow hard registers if the new mode is legal, and occupies no more
+     registers than the old mode.  */
+  if (regno < FIRST_PSEUDO_REGISTER)
+    return (HARD_REGNO_MODE_OK (regno, mode)
+           && (hard_regno_nregs[regno][GET_MODE (x)]
+               >= hard_regno_nregs[regno][mode]));
+
+  /* Or a pseudo that is only used once.  */
+  return (REG_N_SETS (regno) == 1 && !added_sets
+         && !REG_USERVAR_P (x));
+}
+
+
+/* Check whether X, the destination of a set, refers to part of
+   the register specified by REG.  */
+
+static bool
+reg_subword_p (rtx x, rtx reg)
+{
+  /* Check that reg is an integer mode register.  */
+  if (!REG_P (reg) || GET_MODE_CLASS (GET_MODE (reg)) != MODE_INT)
+    return false;
+
+  if (GET_CODE (x) == STRICT_LOW_PART
+      || GET_CODE (x) == ZERO_EXTRACT)
+    x = XEXP (x, 0);
+
+  return GET_CODE (x) == SUBREG
+        && SUBREG_REG (x) == reg
+        && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT;
+}
+
+
 /* 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.
@@ -1446,6 +1802,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 {
   /* New patterns for I3 and I2, respectively.  */
   rtx newpat, newi2pat = 0;
+  rtvec newpat_vec_with_clobbers = 0;
   int substed_i2 = 0, substed_i1 = 0;
   /* Indicates need to preserve SET in I1 or I2 in I3 if it is not dead.  */
   int added_sets_1, added_sets_2;
@@ -1465,6 +1822,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   rtx i2pat;
   /* Indicates if I2DEST or I1DEST is in I2SRC or I1_SRC.  */
   int i2dest_in_i2src = 0, i1dest_in_i1src = 0, i2dest_in_i1src = 0;
+  int i2dest_killed = 0, i1dest_killed = 0;
   int i1_feeds_i3 = 0;
   /* Notes that must be added to REG_NOTES in I3 and I2.  */
   rtx new_i3_notes, new_i2_notes;
@@ -1472,6 +1830,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   int i3_subst_into_i2 = 0;
   /* Notes that I1, I2 or I3 is a MULT operation.  */
   int have_mult = 0;
+  int swap_i2i3 = 0;
 
   int maxreg;
   rtx temp;
@@ -1483,6 +1842,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   if (cant_combine_insn_p (i3)
       || cant_combine_insn_p (i2)
       || (i1 && cant_combine_insn_p (i1))
+      || likely_spilled_retval_p (i3)
       /* We also can't do anything if I3 has a
         REG_LIBCALL note since we don't want to disrupt the contiguity of a
         libcall.  */
@@ -1523,8 +1883,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
      where I2 and I3 are adjacent to avoid making difficult register
      usage tests.  */
 
-  if (i1 == 0 && GET_CODE (i3) == INSN && GET_CODE (PATTERN (i3)) == SET
-      && GET_CODE (SET_SRC (PATTERN (i3))) == REG
+  if (i1 == 0 && NONJUMP_INSN_P (i3) && GET_CODE (PATTERN (i3)) == SET
+      && REG_P (SET_SRC (PATTERN (i3)))
       && REGNO (SET_SRC (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
       && find_reg_note (i3, REG_DEAD, SET_SRC (PATTERN (i3)))
       && GET_CODE (PATTERN (i2)) == PARALLEL
@@ -1571,6 +1931,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
              added_sets_2 = added_sets_1 = 0;
              i2dest = SET_SRC (PATTERN (i3));
+             i2dest_killed = dead_or_set_p (i2, i2dest);
 
              /* Replace the dest in I2 with our dest and make the resulting
                 insn the new pattern for I3.  Then skip to where we
@@ -1584,74 +1945,138 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
            }
     }
 
-  /* If I2 is setting a double-word pseudo to a constant and I3 is setting
-     one of those words to another constant, merge them by making a new
+  /* If I2 is setting a pseudo to a constant and I3 is setting some
+     sub-part of it to another constant, merge them by making a new
      constant.  */
   if (i1 == 0
       && (temp = single_set (i2)) != 0
       && (GET_CODE (SET_SRC (temp)) == CONST_INT
          || GET_CODE (SET_SRC (temp)) == CONST_DOUBLE)
-      && GET_CODE (SET_DEST (temp)) == REG
-      && GET_MODE_CLASS (GET_MODE (SET_DEST (temp))) == MODE_INT
-      && GET_MODE_SIZE (GET_MODE (SET_DEST (temp))) == 2 * UNITS_PER_WORD
       && GET_CODE (PATTERN (i3)) == SET
-      && GET_CODE (SET_DEST (PATTERN (i3))) == SUBREG
-      && SUBREG_REG (SET_DEST (PATTERN (i3))) == SET_DEST (temp)
-      && GET_MODE_CLASS (GET_MODE (SET_DEST (PATTERN (i3)))) == MODE_INT
-      && GET_MODE_SIZE (GET_MODE (SET_DEST (PATTERN (i3)))) == UNITS_PER_WORD
-      && GET_CODE (SET_SRC (PATTERN (i3))) == CONST_INT)
+      && (GET_CODE (SET_SRC (PATTERN (i3))) == CONST_INT
+         || GET_CODE (SET_SRC (PATTERN (i3))) == CONST_DOUBLE)
+      && reg_subword_p (SET_DEST (PATTERN (i3)), SET_DEST (temp)))
     {
-      HOST_WIDE_INT lo, hi;
+      rtx dest = SET_DEST (PATTERN (i3));
+      int offset = -1;
+      int width = 0;
 
-      if (GET_CODE (SET_SRC (temp)) == CONST_INT)
-       lo = INTVAL (SET_SRC (temp)), hi = lo < 0 ? -1 : 0;
+      if (GET_CODE (dest) == ZERO_EXTRACT)
+       {
+         if (GET_CODE (XEXP (dest, 1)) == CONST_INT
+             && GET_CODE (XEXP (dest, 2)) == CONST_INT)
+           {
+             width = INTVAL (XEXP (dest, 1));
+             offset = INTVAL (XEXP (dest, 2));
+             dest = XEXP (dest, 0);
+             if (BITS_BIG_ENDIAN)
+               offset = GET_MODE_BITSIZE (GET_MODE (dest)) - width - offset;
+           }
+       }
       else
        {
-         lo = CONST_DOUBLE_LOW (SET_SRC (temp));
-         hi = CONST_DOUBLE_HIGH (SET_SRC (temp));
+         if (GET_CODE (dest) == STRICT_LOW_PART)
+           dest = XEXP (dest, 0);
+         width = GET_MODE_BITSIZE (GET_MODE (dest));
+         offset = 0;
        }
 
-      if (subreg_lowpart_p (SET_DEST (PATTERN (i3))))
+      if (offset >= 0)
        {
-         /* We don't handle the case of the target word being wider
-            than a host wide int.  */
-         if (HOST_BITS_PER_WIDE_INT < BITS_PER_WORD)
-           abort ();
-
-         lo &= ~(UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1);
-         lo |= (INTVAL (SET_SRC (PATTERN (i3)))
-                & (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1));
+         /* If this is the low part, we're done.  */
+         if (subreg_lowpart_p (dest))
+           ;
+         /* Handle the case where inner is twice the size of outer.  */
+         else if (GET_MODE_BITSIZE (GET_MODE (SET_DEST (temp)))
+                  == 2 * GET_MODE_BITSIZE (GET_MODE (dest)))
+           offset += GET_MODE_BITSIZE (GET_MODE (dest));
+         /* Otherwise give up for now.  */
+         else
+           offset = -1;
        }
-      else if (HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
-       hi = INTVAL (SET_SRC (PATTERN (i3)));
-      else if (HOST_BITS_PER_WIDE_INT >= 2 * BITS_PER_WORD)
+
+      if (offset >= 0)
        {
-         int sign = -(int) ((unsigned HOST_WIDE_INT) lo
-                            >> (HOST_BITS_PER_WIDE_INT - 1));
+         HOST_WIDE_INT mhi, ohi, ihi;
+         HOST_WIDE_INT mlo, olo, ilo;
+         rtx inner = SET_SRC (PATTERN (i3));
+         rtx outer = SET_SRC (temp);
 
-         lo &= ~ (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD
-                  (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1));
-         lo |= (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD
-                (INTVAL (SET_SRC (PATTERN (i3)))));
-         if (hi == sign)
-           hi = lo < 0 ? -1 : 0;
-       }
-      else
-       /* We don't handle the case of the higher word not fitting
-          entirely in either hi or lo.  */
-       abort ();
+         if (GET_CODE (outer) == CONST_INT)
+           {
+             olo = INTVAL (outer);
+             ohi = olo < 0 ? -1 : 0;
+           }
+         else
+           {
+             olo = CONST_DOUBLE_LOW (outer);
+             ohi = CONST_DOUBLE_HIGH (outer);
+           }
 
-      combine_merges++;
-      subst_insn = i3;
-      subst_low_cuid = INSN_CUID (i2);
-      added_sets_2 = added_sets_1 = 0;
-      i2dest = SET_DEST (temp);
+         if (GET_CODE (inner) == CONST_INT)
+           {
+             ilo = INTVAL (inner);
+             ihi = ilo < 0 ? -1 : 0;
+           }
+         else
+           {
+             ilo = CONST_DOUBLE_LOW (inner);
+             ihi = CONST_DOUBLE_HIGH (inner);
+           }
+
+         if (width < HOST_BITS_PER_WIDE_INT)
+           {
+             mlo = ((unsigned HOST_WIDE_INT) 1 << width) - 1;
+             mhi = 0;
+           }
+         else if (width < HOST_BITS_PER_WIDE_INT * 2)
+           {
+             mhi = ((unsigned HOST_WIDE_INT) 1
+                    << (width - HOST_BITS_PER_WIDE_INT)) - 1;
+             mlo = -1;
+           }
+         else
+           {
+             mlo = -1;
+             mhi = -1;
+           }
+
+         ilo &= mlo;
+         ihi &= mhi;
+
+         if (offset >= HOST_BITS_PER_WIDE_INT)
+           {
+             mhi = mlo << (offset - HOST_BITS_PER_WIDE_INT);
+             mlo = 0;
+             ihi = ilo << (offset - HOST_BITS_PER_WIDE_INT);
+             ilo = 0;
+           }
+         else if (offset > 0)
+           {
+             mhi = (mhi << offset) | ((unsigned HOST_WIDE_INT) mlo
+                                      >> (HOST_BITS_PER_WIDE_INT - offset));
+             mlo = mlo << offset;
+             ihi = (ihi << offset) | ((unsigned HOST_WIDE_INT) ilo
+                                      >> (HOST_BITS_PER_WIDE_INT - offset));
+             ilo = ilo << offset;
+           }
+
+         olo = (olo & ~mlo) | ilo;
+         ohi = (ohi & ~mhi) | ihi;
 
-      SUBST (SET_SRC (temp),
-            immed_double_const (lo, hi, GET_MODE (SET_DEST (temp))));
+         combine_merges++;
+         subst_insn = i3;
+         subst_low_cuid = INSN_CUID (i2);
+         added_sets_2 = added_sets_1 = 0;
+         i2dest = SET_DEST (temp);
+         i2dest_killed = dead_or_set_p (i2, i2dest);
+
+         SUBST (SET_SRC (temp),
+                immed_double_const (olo, ohi, GET_MODE (SET_DEST (temp))));
 
-      newpat = PATTERN (i2);
-      goto validate_replacement;
+         newpat = PATTERN (i2);
+         goto validate_replacement;
+       }
     }
 
 #ifndef HAVE_cc0
@@ -1661,7 +2086,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
      make up a dummy I1 that is
        (set Y OP)
      and change I2 to be
-        (set (reg:CC X) (compare:CC Y (const_int 0)))
+       (set (reg:CC X) (compare:CC Y (const_int 0)))
 
      (We can ignore any trailing CLOBBERs.)
 
@@ -1676,7 +2101,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
       && GET_CODE (SET_SRC (XVECEXP (PATTERN (i2), 0, 0))) == COMPARE
       && XEXP (SET_SRC (XVECEXP (PATTERN (i2), 0, 0)), 1) == const0_rtx
       && GET_CODE (XVECEXP (PATTERN (i2), 0, 1)) == SET
-      && GET_CODE (SET_DEST (XVECEXP (PATTERN (i2), 0, 1))) == REG
+      && REG_P (SET_DEST (XVECEXP (PATTERN (i2), 0, 1)))
       && rtx_equal_p (XEXP (SET_SRC (XVECEXP (PATTERN (i2), 0, 0)), 0),
                      SET_SRC (XVECEXP (PATTERN (i2), 0, 1))))
     {
@@ -1716,6 +2141,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   i2dest_in_i2src = reg_overlap_mentioned_p (i2dest, i2src);
   i1dest_in_i1src = i1 && reg_overlap_mentioned_p (i1dest, i1src);
   i2dest_in_i1src = i1 && reg_overlap_mentioned_p (i2dest, i1src);
+  i2dest_killed = dead_or_set_p (i2, i2dest);
+  i1dest_killed = i1 && dead_or_set_p (i1, i1dest);
 
   /* See if I1 directly feeds into I3.  It does if I1DEST is not used
      in I2SRC.  */
@@ -1748,8 +2175,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
 #if 0
   if (!(GET_CODE (PATTERN (i3)) == SET
-       && GET_CODE (SET_SRC (PATTERN (i3))) == REG
-       && GET_CODE (SET_DEST (PATTERN (i3))) == MEM
+       && REG_P (SET_SRC (PATTERN (i3)))
+       && MEM_P (SET_DEST (PATTERN (i3)))
        && (GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_INC
            || GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_DEC)))
     /* It's not the exception.  */
@@ -1805,35 +2232,6 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
   subst_insn = i3;
 
-  /* It is possible that the source of I2 or I1 may be performing an
-     unneeded operation, such as a ZERO_EXTEND of something that is known
-     to have the high part zero.  Handle that case by letting subst look at
-     the innermost one of them.
-
-     Another way to do this would be to have a function that tries to
-     simplify a single insn instead of merging two or more insns.  We don't
-     do this because of the potential of infinite loops and because
-     of the potential extra memory required.  However, doing it the way
-     we are is a bit of a kludge and doesn't catch all cases.
-
-     But only do this if -fexpensive-optimizations since it slows things down
-     and doesn't usually win.  */
-
-  if (flag_expensive_optimizations)
-    {
-      /* Pass pc_rtx so no substitutions are done, just simplifications.  */
-      if (i1)
-       {
-         subst_low_cuid = INSN_CUID (i1);
-         i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0);
-       }
-      else
-       {
-         subst_low_cuid = INSN_CUID (i2);
-         i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);
-       }
-    }
-
 #ifndef HAVE_cc0
   /* Many machines that don't use CC0 have insns that can both perform an
      arithmetic operation and set the condition code.  These operations will
@@ -1874,15 +2272,19 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
                                              i2src, const0_rtx))
              != GET_MODE (SET_DEST (newpat))))
        {
-         unsigned int regno = REGNO (SET_DEST (newpat));
-         rtx new_dest = gen_rtx_REG (compare_mode, regno);
-
-         if (regno < FIRST_PSEUDO_REGISTER
-             || (REG_N_SETS (regno) == 1 && ! added_sets_2
-                 && ! REG_USERVAR_P (SET_DEST (newpat))))
+         if (can_change_dest_mode(SET_DEST (newpat), added_sets_2,
+                                  compare_mode))
            {
-             if (regno >= FIRST_PSEUDO_REGISTER)
-               SUBST (regno_reg_rtx[regno], new_dest);
+             unsigned int regno = REGNO (SET_DEST (newpat));
+             rtx new_dest;
+
+             if (regno < FIRST_PSEUDO_REGISTER)
+               new_dest = gen_rtx_REG (compare_mode, regno);
+             else
+               {
+                 SUBST_MODE (regno_reg_rtx[regno], compare_mode);
+                 new_dest = regno_reg_rtx[regno];
+               }
 
              SUBST (SET_DEST (newpat), new_dest);
              SUBST (XEXP (*cc_use, 0), new_dest);
@@ -1897,6 +2299,41 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   else
 #endif
     {
+      /* It is possible that the source of I2 or I1 may be performing
+        an unneeded operation, such as a ZERO_EXTEND of something
+        that is known to have the high part zero.  Handle that case
+        by letting subst look at the innermost one of them.
+
+        Another way to do this would be to have a function that tries
+        to simplify a single insn instead of merging two or more
+        insns.  We don't do this because of the potential of infinite
+        loops and because of the potential extra memory required.
+        However, doing it the way we are is a bit of a kludge and
+        doesn't catch all cases.
+
+        But only do this if -fexpensive-optimizations since it slows
+        things down and doesn't usually win.
+
+        This is not done in the COMPARE case above because the
+        unmodified I2PAT is used in the PARALLEL and so a pattern
+        with a modified I2SRC would not match.  */
+
+      if (flag_expensive_optimizations)
+       {
+         /* Pass pc_rtx so no substitutions are done, just
+            simplifications.  */
+         if (i1)
+           {
+             subst_low_cuid = INSN_CUID (i1);
+             i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0);
+           }
+         else
+           {
+             subst_low_cuid = INSN_CUID (i2);
+             i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);
+           }
+       }
+
       n_occurrences = 0;               /* `subst' counts here */
 
       /* If I1 feeds into I2 (not into I3) and I1DEST is in I1SRC, we
@@ -1941,8 +2378,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
       || (i1 != 0 && FIND_REG_INC_NOTE (i1, NULL_RTX) != 0
          && (n_occurrences + added_sets_1 + (added_sets_2 && ! i1_feeds_i3)
              > 1))
-      /* Fail if we tried to make a new register (we used to abort, but there's
-        really no reason to).  */
+      /* Fail if we tried to make a new register.  */
       || max_reg_num () != maxreg
       /* Fail if we couldn't do something and have a CLOBBER.  */
       || GET_CODE (newpat) == CLOBBER
@@ -2006,6 +2442,18 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   /* Note which hard regs this insn has as inputs.  */
   mark_used_regs_combine (newpat);
 
+  /* If recog_for_combine fails, it strips existing clobbers.  If we'll
+     consider splitting this pattern, we might need these clobbers.  */
+  if (i1 && GET_CODE (newpat) == PARALLEL
+      && GET_CODE (XVECEXP (newpat, 0, XVECLEN (newpat, 0) - 1)) == CLOBBER)
+    {
+      int len = XVECLEN (newpat, 0);
+
+      newpat_vec_with_clobbers = rtvec_alloc (len);
+      for (i = 0; i < len; i++)
+       RTVEC_ELT (newpat_vec_with_clobbers, i) = XVECEXP (newpat, 0, i);
+    }
+
   /* Is the result of combination a valid instruction?  */
   insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
 
@@ -2039,7 +2487,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
       rtx set1 = XVECEXP (newpat, 0, 1);
       rtx note;
 
-      if (((GET_CODE (SET_DEST (set1)) == REG
+      if (((REG_P (SET_DEST (set1))
            && 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)))))
@@ -2051,7 +2499,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
          insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
        }
 
-      else if (((GET_CODE (SET_DEST (set0)) == REG
+      else if (((REG_P (SET_DEST (set0))
                 && find_reg_note (i3, REG_UNUSED, SET_DEST (set0)))
                || (GET_CODE (SET_DEST (set0)) == SUBREG
                    && find_reg_note (i3, REG_UNUSED,
@@ -2085,7 +2533,6 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
       && asm_noperands (newpat) < 0)
     {
       rtx m_split, *split;
-      rtx ni2dest = i2dest;
 
       /* See if the MD file can split NEWPAT.  If it can't, see if letting it
         use I2DEST as a scratch register will help.  In the latter case,
@@ -2100,39 +2547,65 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
         possible to try that as a scratch reg.  This would require adding
         more code to make it work though.  */
 
-      if (m_split == 0 && ! reg_overlap_mentioned_p (ni2dest, newpat))
+      if (m_split == 0 && ! reg_overlap_mentioned_p (i2dest, newpat))
        {
-         /* If I2DEST is a hard register or the only use of a pseudo,
-            we can change its mode.  */
-         if (GET_MODE (SET_DEST (newpat)) != GET_MODE (i2dest)
-             && GET_MODE (SET_DEST (newpat)) != VOIDmode
-             && GET_CODE (i2dest) == REG
-             && (REGNO (i2dest) < FIRST_PSEUDO_REGISTER
-                 || (REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2
-                     && ! REG_USERVAR_P (i2dest))))
-           ni2dest = gen_rtx_REG (GET_MODE (SET_DEST (newpat)),
-                                  REGNO (i2dest));
+         enum machine_mode new_mode = GET_MODE (SET_DEST (newpat));
 
+         /* First try to split using the original register as a
+            scratch register.  */
          m_split = split_insns (gen_rtx_PARALLEL
                                 (VOIDmode,
                                  gen_rtvec (2, newpat,
                                             gen_rtx_CLOBBER (VOIDmode,
-                                                             ni2dest))),
+                                                             i2dest))),
                                 i3);
-         /* If the split with the mode-changed register didn't work, try
-            the original register.  */
-         if (! m_split && ni2dest != i2dest)
+
+         /* If that didn't work, try changing the mode of I2DEST if
+            we can.  */
+         if (m_split == 0
+             && new_mode != GET_MODE (i2dest)
+             && new_mode != VOIDmode
+             && can_change_dest_mode (i2dest, added_sets_2, new_mode))
            {
-             ni2dest = i2dest;
+             enum machine_mode old_mode = GET_MODE (i2dest);
+             rtx ni2dest;
+
+             if (REGNO (i2dest) < FIRST_PSEUDO_REGISTER)
+               ni2dest = gen_rtx_REG (new_mode, REGNO (i2dest));
+             else
+               {
+                 SUBST_MODE (regno_reg_rtx[REGNO (i2dest)], new_mode);
+                 ni2dest = regno_reg_rtx[REGNO (i2dest)];
+               }
+
              m_split = split_insns (gen_rtx_PARALLEL
                                     (VOIDmode,
                                      gen_rtvec (2, newpat,
                                                 gen_rtx_CLOBBER (VOIDmode,
-                                                                 i2dest))),
+                                                                 ni2dest))),
                                     i3);
+
+             if (m_split == 0
+                 && REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
+               {
+                 struct undo *buf;
+
+                 PUT_MODE (regno_reg_rtx[REGNO (i2dest)], old_mode);
+                 buf = undobuf.undos;
+                 undobuf.undos = buf->next;
+                 buf->next = undobuf.frees;
+                 undobuf.frees = buf;
+               }
            }
        }
 
+      /* If recog_for_combine has discarded clobbers, try to use them
+        again for the split.  */
+      if (m_split == 0 && newpat_vec_with_clobbers)
+       m_split
+         = split_insns (gen_rtx_PARALLEL (VOIDmode,
+                                          newpat_vec_with_clobbers), i3);
+
       if (m_split && NEXT_INSN (m_split) == NULL_RTX)
        {
          m_split = PATTERN (m_split);
@@ -2151,13 +2624,6 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
          i3set = single_set (NEXT_INSN (m_split));
          i2set = single_set (m_split);
 
-         /* In case we changed the mode of I2DEST, replace it in the
-            pseudo-register table here.  We can't do it above in case this
-            code doesn't get executed and we do a split the other way.  */
-
-         if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
-           SUBST (regno_reg_rtx[REGNO (i2dest)], ni2dest);
-
          i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
 
          /* If I2 or I3 has multiple SETs, we won't know how to track
@@ -2190,8 +2656,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
                     || GET_CODE (new_i2_dest) == SUBREG)
                new_i2_dest = XEXP (new_i2_dest, 0);
 
-             if (GET_CODE (new_i3_dest) == REG
-                 && GET_CODE (new_i2_dest) == REG
+             if (REG_P (new_i3_dest)
+                 && REG_P (new_i2_dest)
                  && REGNO (new_i3_dest) == REGNO (new_i2_dest))
                REG_N_SETS (REGNO (new_i2_dest))++;
            }
@@ -2202,15 +2668,16 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
         are set between I2 and I3.  */
       if (insn_code_number < 0 && (split = find_split_point (&newpat, i3)) != 0
 #ifdef HAVE_cc0
-         && GET_CODE (i2dest) == REG
+         && REG_P (i2dest)
 #endif
          /* We need I2DEST in the proper mode.  If it is a hard register
-            or the only use of a pseudo, we can change its mode.  */
+            or the only use of a pseudo, we can change its mode.
+            Make sure we don't change a hard register to have a mode that
+            isn't valid for it, or change the number of registers.  */
          && (GET_MODE (*split) == GET_MODE (i2dest)
              || GET_MODE (*split) == VOIDmode
-             || REGNO (i2dest) < FIRST_PSEUDO_REGISTER
-             || (REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2
-                 && ! REG_USERVAR_P (i2dest)))
+             || can_change_dest_mode (i2dest, added_sets_2,
+                                      GET_MODE (*split)))
          && (next_real_insn (i2) == i3
              || ! use_crosses_set_p (*split, INSN_CUID (i2)))
          /* We can't overwrite I2DEST if its value is still used by
@@ -2220,15 +2687,20 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
          rtx newdest = i2dest;
          enum rtx_code split_code = GET_CODE (*split);
          enum machine_mode split_mode = GET_MODE (*split);
+         bool subst_done = false;
+         newi2pat = NULL_RTX;
 
          /* Get NEWDEST as a register in the proper mode.  We have already
             validated that we can do this.  */
          if (GET_MODE (i2dest) != split_mode && split_mode != VOIDmode)
            {
-             newdest = gen_rtx_REG (split_mode, REGNO (i2dest));
-
-             if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
-               SUBST (regno_reg_rtx[REGNO (i2dest)], newdest);
+             if (REGNO (i2dest) < FIRST_PSEUDO_REGISTER)
+               newdest = gen_rtx_REG (split_mode, REGNO (i2dest));
+             else
+               {
+                 SUBST_MODE (regno_reg_rtx[REGNO (i2dest)], split_mode);
+                 newdest = regno_reg_rtx[REGNO (i2dest)];
+               }
            }
 
          /* If *SPLIT is a (mult FOO (const_int pow2)), convert it to
@@ -2249,7 +2721,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 #ifdef INSN_SCHEDULING
          /* If *SPLIT is a paradoxical SUBREG, when we split it, it should
             be written as a ZERO_EXTEND.  */
-         if (split_code == SUBREG && GET_CODE (SUBREG_REG (*split)) == MEM)
+         if (split_code == SUBREG && MEM_P (SUBREG_REG (*split)))
            {
 #ifdef LOAD_EXTEND_OP
              /* Or as a SIGN_EXTEND if LOAD_EXTEND_OP says that that's
@@ -2265,10 +2737,85 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
            }
 #endif
 
-         newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
-         SUBST (*split, newdest);
+         /* Attempt to split binary operators using arithmetic identities.  */
+         if (BINARY_P (SET_SRC (newpat))
+             && split_mode == GET_MODE (SET_SRC (newpat))
+             && ! side_effects_p (SET_SRC (newpat)))
+           {
+             rtx setsrc = SET_SRC (newpat);
+             enum machine_mode mode = GET_MODE (setsrc);
+             enum rtx_code code = GET_CODE (setsrc);
+             rtx src_op0 = XEXP (setsrc, 0);
+             rtx src_op1 = XEXP (setsrc, 1);
+
+             /* Split "X = Y op Y" as "Z = Y; X = Z op Z".  */
+             if (rtx_equal_p (src_op0, src_op1))
+               {
+                 newi2pat = gen_rtx_SET (VOIDmode, newdest, src_op0);
+                 SUBST (XEXP (setsrc, 0), newdest);
+                 SUBST (XEXP (setsrc, 1), newdest);
+                 subst_done = true;
+               }
+             /* Split "((P op Q) op R) op S" where op is PLUS or MULT.  */
+             else if ((code == PLUS || code == MULT)
+                      && GET_CODE (src_op0) == code
+                      && GET_CODE (XEXP (src_op0, 0)) == code
+                      && (INTEGRAL_MODE_P (mode)
+                          || (FLOAT_MODE_P (mode)
+                              && flag_unsafe_math_optimizations)))
+               {
+                 rtx p = XEXP (XEXP (src_op0, 0), 0);
+                 rtx q = XEXP (XEXP (src_op0, 0), 1);
+                 rtx r = XEXP (src_op0, 1);
+                 rtx s = src_op1;
+
+                 /* Split both "((X op Y) op X) op Y" and
+                    "((X op Y) op Y) op X" as "T op T" where T is
+                    "X op Y".  */
+                 if ((rtx_equal_p (p,r) && rtx_equal_p (q,s))
+                      || (rtx_equal_p (p,s) && rtx_equal_p (q,r)))
+                   {
+                     newi2pat = gen_rtx_SET (VOIDmode, newdest,
+                                             XEXP (src_op0, 0));
+                     SUBST (XEXP (setsrc, 0), newdest);
+                     SUBST (XEXP (setsrc, 1), newdest);
+                     subst_done = true;
+                   }
+                 /* Split "((X op X) op Y) op Y)" as "T op T" where
+                    T is "X op Y".  */
+                 else if (rtx_equal_p (p,q) && rtx_equal_p (r,s))
+                   {
+                     rtx tmp = simplify_gen_binary (code, mode, p, r);
+                     newi2pat = gen_rtx_SET (VOIDmode, newdest, tmp);
+                     SUBST (XEXP (setsrc, 0), newdest);
+                     SUBST (XEXP (setsrc, 1), newdest);
+                     subst_done = true;
+                   }
+               }
+           }
+
+         if (!subst_done)
+           {
+             newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
+             SUBST (*split, newdest);
+           }
+
          i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
 
+         /* recog_for_combine might have added CLOBBERs to newi2pat.
+            Make sure NEWPAT does not depend on the clobbered regs.  */
+         if (GET_CODE (newi2pat) == PARALLEL)
+           for (i = XVECLEN (newi2pat, 0) - 1; i >= 0; i--)
+             if (GET_CODE (XVECEXP (newi2pat, 0, i)) == CLOBBER)
+               {
+                 rtx reg = XEXP (XVECEXP (newi2pat, 0, i), 0);
+                 if (reg_overlap_mentioned_p (reg, newpat))
+                   {
+                     undo_all ();
+                     return 0;
+                   }
+               }
+
          /* If the split point was a MULT and we didn't have one before,
             don't use one now.  */
          if (i2_code_number >= 0 && ! (split_code == MULT && ! have_mult))
@@ -2306,7 +2853,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
           && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != ZERO_EXTRACT
           && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART
           && ! (temp = SET_DEST (XVECEXP (newpat, 0, 1)),
-                (GET_CODE (temp) == REG
+                (REG_P (temp)
                  && 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
@@ -2314,7 +2861,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
                      != 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_P (temp)
                      && 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
@@ -2338,40 +2885,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
        insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
 
       if (insn_code_number >= 0)
-       {
-         rtx insn;
-         rtx link;
-
-         /* 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);
-
-         /* I3 now uses what used to be its destination and which is
-            now I2's destination.  That means we need a LOG_LINK from
-            I3 to I2.  But we used to have one, so we still will.
-
-            However, some later insn might be using I2's dest and have
-            a LOG_LINK pointing at I3.  We must remove this link.
-            The simplest way to remove the link is to point it at I1,
-            which we know will be a NOTE.  */
-
-         for (insn = NEXT_INSN (i3);
-              insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR
-                       || insn != BB_HEAD (this_basic_block->next_bb));
-              insn = NEXT_INSN (insn))
-           {
-             if (INSN_P (insn) && reg_referenced_p (ni2dest, PATTERN (insn)))
-               {
-                 for (link = LOG_LINKS (insn); link;
-                      link = XEXP (link, 1))
-                   if (XEXP (link, 0) == i3)
-                     XEXP (link, 0) = i1;
-
-                 break;
-               }
-           }
-       }
+       swap_i2i3 = 1;
     }
 
   /* Similarly, check for a case where we have a PARALLEL of two independent
@@ -2390,15 +2904,19 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
           && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART
           && ! use_crosses_set_p (SET_SRC (XVECEXP (newpat, 0, 1)),
                                   INSN_CUID (i2))
-          /* Don't pass sets with (USE (MEM ...)) dests to the following.  */
-          && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != USE
-          && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != USE
           && ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 1)),
                                  XVECEXP (newpat, 0, 0))
           && ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 0)),
                                  XVECEXP (newpat, 0, 1))
           && ! (contains_muldiv (SET_SRC (XVECEXP (newpat, 0, 0)))
-                && contains_muldiv (SET_SRC (XVECEXP (newpat, 0, 1)))))
+                && contains_muldiv (SET_SRC (XVECEXP (newpat, 0, 1))))
+#ifdef HAVE_cc0
+          /* We cannot split the parallel into two sets if both sets
+             reference cc0.  */
+          && ! (reg_referenced_p (cc0_rtx, XVECEXP (newpat, 0, 0))
+                && reg_referenced_p (cc0_rtx, XVECEXP (newpat, 0, 1)))
+#endif
+          )
     {
       /* Normally, it doesn't matter which of the two is done first,
         but it does if one references cc0.  In that case, it has to
@@ -2462,7 +2980,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
          if (REG_NOTE_KIND (note) == REG_UNUSED
              && ! reg_set_p (XEXP (note, 0), PATTERN (undobuf.other_insn)))
            {
-             if (GET_CODE (XEXP (note, 0)) == REG)
+             if (REG_P (XEXP (note, 0)))
                REG_N_DEATHS (REGNO (XEXP (note, 0)))--;
 
              remove_note (undobuf.other_insn, note);
@@ -2470,18 +2988,18 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
        }
 
       for (note = new_other_notes; note; note = XEXP (note, 1))
-       if (GET_CODE (XEXP (note, 0)) == REG)
+       if (REG_P (XEXP (note, 0)))
          REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
 
       distribute_notes (new_other_notes, undobuf.other_insn,
-                       undobuf.other_insn, NULL_RTX);
+                       undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
     }
 #ifdef HAVE_cc0
   /* 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);
-    if (p && p != i2 && GET_CODE (p) == INSN && newi2pat
+    if (p && p != i2 && NONJUMP_INSN_P (p) && newi2pat
        && sets_cc0_p (newi2pat))
       {
        undo_all ();
@@ -2490,14 +3008,76 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   }
 #endif
 
+  /* Only allow this combination if insn_rtx_costs reports that the
+     replacement instructions are cheaper than the originals.  */
+  if (!combine_validate_cost (i1, i2, i3, newpat, newi2pat))
+    {
+      undo_all ();
+      return 0;
+    }
+
   /* We now know that we can do this combination.  Merge the insns and
      update the status of registers and LOG_LINKS.  */
 
+  if (swap_i2i3)
+    {
+      rtx insn;
+      rtx link;
+      rtx ni2dest;
+
+      /* I3 now uses what used to be its destination and which is now
+        I2's destination.  This requires us to do a few adjustments.  */
+      PATTERN (i3) = newpat;
+      adjust_for_new_dest (i3);
+
+      /* We need a LOG_LINK from I3 to I2.  But we used to have one,
+        so we still will.
+
+        However, some later insn might be using I2's dest and have
+        a LOG_LINK pointing at I3.  We must remove this link.
+        The simplest way to remove the link is to point it at I1,
+        which we know will be a NOTE.  */
+
+      /* newi2pat is usually a SET here; however, recog_for_combine might
+        have added some clobbers.  */
+      if (GET_CODE (newi2pat) == PARALLEL)
+       ni2dest = SET_DEST (XVECEXP (newi2pat, 0, 0));
+      else
+       ni2dest = SET_DEST (newi2pat);
+
+      for (insn = NEXT_INSN (i3);
+          insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR
+                   || insn != BB_HEAD (this_basic_block->next_bb));
+          insn = NEXT_INSN (insn))
+       {
+         if (INSN_P (insn) && reg_referenced_p (ni2dest, PATTERN (insn)))
+           {
+             for (link = LOG_LINKS (insn); link;
+                  link = XEXP (link, 1))
+               if (XEXP (link, 0) == i3)
+                 XEXP (link, 0) = i1;
+
+             break;
+           }
+       }
+    }
+
   {
     rtx i3notes, i2notes, i1notes = 0;
     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
+                  || !i2dest_killed
+                  ? 0 : i2dest);
+    rtx elim_i1 = (i1 == 0 || i1dest_in_i1src
+                  || (newi2pat && reg_set_p (i1dest, newi2pat))
+                  || !i1dest_killed
+                  ? 0 : i1dest);
 
     /* Get the old REG_NOTES and LOG_LINKS from all our insns and
        clear them.  */
@@ -2529,7 +3109,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
     INSN_CODE (i3) = insn_code_number;
     PATTERN (i3) = newpat;
 
-    if (GET_CODE (i3) == CALL_INSN && CALL_INSN_FUNCTION_USAGE (i3))
+    if (CALL_P (i3) && CALL_INSN_FUNCTION_USAGE (i3))
       {
        rtx call_usage = CALL_INSN_FUNCTION_USAGE (i3);
 
@@ -2560,8 +3140,9 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
     if (i3_subst_into_i2)
       {
        for (i = 0; i < XVECLEN (PATTERN (i2), 0); i++)
-         if (GET_CODE (XVECEXP (PATTERN (i2), 0, i)) != USE
-             && GET_CODE (SET_DEST (XVECEXP (PATTERN (i2), 0, i))) == REG
+         if ((GET_CODE (XVECEXP (PATTERN (i2), 0, i)) == SET
+              || GET_CODE (XVECEXP (PATTERN (i2), 0, i)) == CLOBBER)
+             && REG_P (SET_DEST (XVECEXP (PATTERN (i2), 0, i)))
              && SET_DEST (XVECEXP (PATTERN (i2), 0, i)) != i2dest
              && ! find_reg_note (i2, REG_UNUSED,
                                  SET_DEST (XVECEXP (PATTERN (i2), 0, i))))
@@ -2597,19 +3178,13 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
        PATTERN (i2) = newi2pat;
       }
     else
-      {
-       PUT_CODE (i2, NOTE);
-       NOTE_LINE_NUMBER (i2) = NOTE_INSN_DELETED;
-       NOTE_SOURCE_FILE (i2) = 0;
-      }
+      SET_INSN_DELETED (i2);
 
     if (i1)
       {
        LOG_LINKS (i1) = 0;
        REG_NOTES (i1) = 0;
-       PUT_CODE (i1, NOTE);
-       NOTE_LINE_NUMBER (i1) = NOTE_INSN_DELETED;
-       NOTE_SOURCE_FILE (i1) = 0;
+       SET_INSN_DELETED (i1);
       }
 
     /* Get death notes for everything that is now used in either I3 or
@@ -2628,13 +3203,17 @@ try_combine (rtx i3, rtx i2, rtx i1, int *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);
+      distribute_notes (i3notes, i3, i3, newi2pat ? i2 : NULL_RTX,
+                       elim_i2, elim_i1);
     if (i2notes)
-      distribute_notes (i2notes, i2, i3, newi2pat ? i2 : NULL_RTX);
+      distribute_notes (i2notes, i2, i3, newi2pat ? i2 : NULL_RTX,
+                       elim_i2, elim_i1);
     if (i1notes)
-      distribute_notes (i1notes, i1, i3, newi2pat ? i2 : NULL_RTX);
+      distribute_notes (i1notes, i1, i3, newi2pat ? i2 : NULL_RTX,
+                       elim_i2, elim_i1);
     if (midnotes)
-      distribute_notes (midnotes, NULL_RTX, i3, newi2pat ? i2 : NULL_RTX);
+      distribute_notes (midnotes, NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
+                       elim_i2, elim_i1);
 
     /* 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,
@@ -2644,19 +3223,19 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
     if (newi2pat && new_i2_notes)
       {
        for (temp = new_i2_notes; temp; temp = XEXP (temp, 1))
-         if (GET_CODE (XEXP (temp, 0)) == REG)
+         if (REG_P (XEXP (temp, 0)))
            REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
 
-       distribute_notes (new_i2_notes, i2, i2, NULL_RTX);
+       distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
       }
 
     if (new_i3_notes)
       {
        for (temp = new_i3_notes; temp; temp = XEXP (temp, 1))
-         if (GET_CODE (XEXP (temp, 0)) == REG)
+         if (REG_P (XEXP (temp, 0)))
            REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
 
-       distribute_notes (new_i3_notes, i3, i3, NULL_RTX);
+       distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
       }
 
     /* If I3DEST was used in I3SRC, it really died in I3.  We may need to
@@ -2668,50 +3247,53 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
     if (i3dest_killed)
       {
-       if (GET_CODE (i3dest_killed) == REG)
+       if (REG_P (i3dest_killed))
          REG_N_DEATHS (REGNO (i3dest_killed))++;
 
        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);
+                           NULL_RTX, i2, NULL_RTX, elim_i2, elim_i1);
        else
          distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
                                               NULL_RTX),
-                           NULL_RTX, i3, newi2pat ? i2 : NULL_RTX);
+                           NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
+                           elim_i2, elim_i1);
       }
 
     if (i2dest_in_i2src)
       {
-       if (GET_CODE (i2dest) == REG)
+       if (REG_P (i2dest))
          REG_N_DEATHS (REGNO (i2dest))++;
 
        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, i2, NULL_RTX, NULL_RTX, NULL_RTX);
        else
          distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
-                           NULL_RTX, i3, newi2pat ? i2 : NULL_RTX);
+                           NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
+                           NULL_RTX, NULL_RTX);
       }
 
     if (i1dest_in_i1src)
       {
-       if (GET_CODE (i1dest) == REG)
+       if (REG_P (i1dest))
          REG_N_DEATHS (REGNO (i1dest))++;
 
        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, i2, NULL_RTX, NULL_RTX, NULL_RTX);
        else
          distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
-                           NULL_RTX, i3, newi2pat ? i2 : NULL_RTX);
+                           NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
+                           NULL_RTX, NULL_RTX);
       }
 
     distribute_links (i3links);
     distribute_links (i2links);
     distribute_links (i1links);
 
-    if (GET_CODE (i2dest) == REG)
+    if (REG_P (i2dest))
       {
        rtx link;
        rtx i2_insn = 0, i2_val = 0, set;
@@ -2742,7 +3324,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
          }
       }
 
-    if (i1 && GET_CODE (i1dest) == REG)
+    if (i1 && REG_P (i1dest))
       {
        rtx link;
        rtx i1_insn = 0, i1_val = 0, set;
@@ -2780,7 +3362,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
        mark_jump_label (PATTERN (i3), i3, 0);
 
        if ((temp = next_nonnote_insn (i3)) == NULL_RTX
-           || GET_CODE (temp) != BARRIER)
+           || !BARRIER_P (temp))
          emit_barrier_after (i3);
       }
 
@@ -2791,7 +3373,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
        *new_direct_jump_p = 1;
 
        if ((temp = next_nonnote_insn (undobuf.other_insn)) == NULL_RTX
-           || GET_CODE (temp) != BARRIER)
+           || !BARRIER_P (temp))
          emit_barrier_after (undobuf.other_insn);
       }
 
@@ -2824,10 +3406,20 @@ undo_all (void)
   for (undo = undobuf.undos; undo; undo = next)
     {
       next = undo->next;
-      if (undo->is_int)
-       *undo->where.i = undo->old_contents.i;
-      else
-       *undo->where.r = undo->old_contents.r;
+      switch (undo->kind)
+       {
+       case UNDO_RTX:
+         *undo->where.r = undo->old_contents.r;
+         break;
+       case UNDO_INT:
+         *undo->where.i = undo->old_contents.i;
+         break;
+       case UNDO_MODE:
+         PUT_MODE (*undo->where.r, undo->old_contents.m);
+         break;
+       default:
+         gcc_unreachable ();
+       }
 
       undo->next = undobuf.frees;
       undobuf.frees = undo;
@@ -2852,7 +3444,6 @@ undo_commit (void)
     }
   undobuf.undos = 0;
 }
-
 \f
 /* Find the innermost point within the rtx at LOC, possibly LOC itself,
    where we have an arithmetic expression and return that point.  LOC will
@@ -2879,7 +3470,7 @@ find_split_point (rtx *loc, rtx insn)
 #ifdef INSN_SCHEDULING
       /* If we are making a paradoxical SUBREG invalid, it becomes a split
         point.  */
-      if (GET_CODE (SUBREG_REG (x)) == MEM)
+      if (MEM_P (SUBREG_REG (x)))
        return loc;
 #endif
       return find_split_point (&SUBREG_REG (x), insn);
@@ -2920,12 +3511,12 @@ find_split_point (rtx *loc, rtx insn)
          if (seq
              && NEXT_INSN (seq) != NULL_RTX
              && NEXT_INSN (NEXT_INSN (seq)) == NULL_RTX
-             && GET_CODE (seq) == INSN
+             && NONJUMP_INSN_P (seq)
              && GET_CODE (PATTERN (seq)) == SET
              && SET_DEST (PATTERN (seq)) == reg
              && ! reg_mentioned_p (reg,
                                    SET_SRC (PATTERN (seq)))
-             && GET_CODE (NEXT_INSN (seq)) == INSN
+             && NONJUMP_INSN_P (NEXT_INSN (seq))
              && GET_CODE (PATTERN (NEXT_INSN (seq))) == SET
              && SET_DEST (PATTERN (NEXT_INSN (seq))) == reg
              && memory_address_p (GET_MODE (x),
@@ -3011,21 +3602,23 @@ find_split_point (rtx *loc, rtx insn)
          rtx dest = XEXP (SET_DEST (x), 0);
          enum machine_mode mode = GET_MODE (dest);
          unsigned HOST_WIDE_INT mask = ((HOST_WIDE_INT) 1 << len) - 1;
+         rtx or_mask;
 
          if (BITS_BIG_ENDIAN)
            pos = GET_MODE_BITSIZE (mode) - len - pos;
 
+         or_mask = gen_int_mode (src << pos, mode);
          if (src == mask)
            SUBST (SET_SRC (x),
-                  simplify_gen_binary (IOR, mode, dest, GEN_INT (src << pos)));
+                  simplify_gen_binary (IOR, mode, dest, or_mask));
          else
            {
              rtx negmask = gen_int_mode (~(mask << pos), mode);
              SUBST (SET_SRC (x),
                     simplify_gen_binary (IOR, mode,
-                                         simplify_gen_binary (AND, mode,
+                                         simplify_gen_binary (AND, mode,
                                                               dest, negmask),
-                                         GEN_INT (src << pos)));
+                                         or_mask));
            }
 
          SUBST (SET_DEST (x), dest);
@@ -3052,9 +3645,9 @@ find_split_point (rtx *loc, rtx insn)
             be better.  */
 
          if (GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
-             && GET_CODE (XEXP (SET_SRC (x), 0)) == REG
+             && REG_P (XEXP (SET_SRC (x), 0))
              && (pos = exact_log2 (INTVAL (XEXP (SET_SRC (x), 1)))) >= 7
-             && GET_CODE (SET_DEST (x)) == REG
+             && REG_P (SET_DEST (x))
              && (split = find_single_use (SET_DEST (x), insn, (rtx*) 0)) != 0
              && (GET_CODE (*split) == EQ || GET_CODE (*split) == NE)
              && XEXP (*split, 0) == SET_DEST (x)
@@ -3288,7 +3881,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
 
 #define COMBINE_RTX_EQUAL_P(X,Y)                       \
   ((X) == (Y)                                          \
-   || (GET_CODE (X) == REG && GET_CODE (Y) == REG      \
+   || (REG_P (X) && REG_P (Y)  \
        && REGNO (X) == REGNO (Y) && GET_MODE (X) == GET_MODE (Y)))
 
   if (! in_dest && COMBINE_RTX_EQUAL_P (x, from))
@@ -3304,7 +3897,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
      delete the feeding insn, which is incorrect.
 
      So force this insn not to match in this (rare) case.  */
-  if (! in_dest && code == REG && GET_CODE (from) == REG
+  if (! in_dest && code == REG && REG_P (from)
       && REGNO (x) == REGNO (from))
     return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
 
@@ -3348,7 +3941,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
        {
          rtx dest = SET_DEST (XVECEXP (x, 0, i));
 
-         if (GET_CODE (dest) != REG
+         if (!REG_P (dest)
              && GET_CODE (dest) != CC0
              && GET_CODE (dest) != PC)
            {
@@ -3373,7 +3966,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
         where we want to suppress replacing something inside a
         SET_SRC are handled via the IN_DEST operand.  */
       if (code == SET
-         && (GET_CODE (SET_DEST (x)) == REG
+         && (REG_P (SET_DEST (x))
              || GET_CODE (SET_DEST (x)) == CC0
              || GET_CODE (SET_DEST (x)) == PC))
        fmt = "ie";
@@ -3416,10 +4009,10 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
              /* If this is a register being set, ignore it.  */
              new = XEXP (x, i);
              if (in_dest
-                 && (code == SUBREG || code == STRICT_LOW_PART
-                     || code == ZERO_EXTRACT)
                  && i == 0
-                 && GET_CODE (new) == REG)
+                 && (((code == SUBREG || code == ZERO_EXTRACT)
+                      && REG_P (new))
+                     || code == STRICT_LOW_PART))
                ;
 
              else if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
@@ -3451,7 +4044,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
 
 #ifdef CANNOT_CHANGE_MODE_CLASS
                  if (code == SUBREG
-                     && GET_CODE (to) == REG
+                     && REG_P (to)
                      && REGNO (to) < FIRST_PSEUDO_REGISTER
                      && REG_CANNOT_CHANGE_MODE_P (REGNO (to),
                                                   GET_MODE (to),
@@ -3504,8 +4097,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
                {
                  x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
                                                new, GET_MODE (XEXP (x, 0)));
-                 if (! x)
-                   abort ();
+                 gcc_assert (x);
                }
              else
                SUBST (XEXP (x, i), new);
@@ -3550,7 +4142,6 @@ 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);
   rtx temp;
-  rtx reversed;
   int i;
 
   /* If this is a commutative operation, put a constant last and a complex
@@ -3563,47 +4154,6 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
       SUBST (XEXP (x, 1), temp);
     }
 
-  /* If this is a PLUS, MINUS, or MULT, and the first operand is the
-     sign extension of a PLUS with a constant, reverse the order of the sign
-     extension and the addition. Note that this not the same as the original
-     code, but overflow is undefined for signed values.  Also note that the
-     PLUS will have been partially moved "inside" the sign-extension, so that
-     the first operand of X will really look like:
-         (ashiftrt (plus (ashift A C4) C5) C4).
-     We convert this to
-         (plus (ashiftrt (ashift A C4) C2) C4)
-     and replace the first operand of X with that expression.  Later parts
-     of this function may simplify the expression further.
-
-     For example, if we start with (mult (sign_extend (plus A C1)) C2),
-     we swap the SIGN_EXTEND and PLUS.  Later code will apply the
-     distributive law to produce (plus (mult (sign_extend X) C1) C3).
-
-     We do this to simplify address expressions.  */
-
-  if ((code == PLUS || code == MINUS || code == MULT)
-      && GET_CODE (XEXP (x, 0)) == ASHIFTRT
-      && GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ASHIFT
-      && GET_CODE (XEXP (XEXP (XEXP (XEXP (x, 0), 0), 0), 1)) == CONST_INT
-      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
-      && XEXP (XEXP (XEXP (XEXP (x, 0), 0), 0), 1) == XEXP (XEXP (x, 0), 1)
-      && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT
-      && (temp = simplify_binary_operation (ASHIFTRT, mode,
-                                           XEXP (XEXP (XEXP (x, 0), 0), 1),
-                                           XEXP (XEXP (x, 0), 1))) != 0)
-    {
-      rtx new
-       = simplify_shift_const (NULL_RTX, ASHIFT, mode,
-                               XEXP (XEXP (XEXP (XEXP (x, 0), 0), 0), 0),
-                               INTVAL (XEXP (XEXP (x, 0), 1)));
-
-      new = simplify_shift_const (NULL_RTX, ASHIFTRT, mode, new,
-                                 INTVAL (XEXP (XEXP (x, 0), 1)));
-
-      SUBST (XEXP (x, 0), simplify_gen_binary (PLUS, mode, new, temp));
-    }
-
   /* If this is a simple operation applied to an IF_THEN_ELSE, try
      applying it to the arms of the IF_THEN_ELSE.  This often simplifies
      things.  Check for cases where both arms are testing the same
@@ -3619,7 +4169,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
               && ! (GET_CODE (XEXP (x, 1)) == SUBREG
                     && OBJECT_P (SUBREG_REG (XEXP (x, 1)))))))
       || (UNARY_P (x)
-          && (!OBJECT_P (XEXP (x, 0))
+         && (!OBJECT_P (XEXP (x, 0))
               && ! (GET_CODE (XEXP (x, 0)) == SUBREG
                     && OBJECT_P (SUBREG_REG (XEXP (x, 0)))))))
     {
@@ -3663,7 +4213,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
              else if (true_rtx == const0_rtx && false_rtx == const_true_rtx
                       && ((reversed = reversed_comparison_code_parts
                                        (cond_code, cond, cop1, NULL))
-                          != UNKNOWN))
+                          != UNKNOWN))
                x = simplify_gen_relational (reversed, mode, VOIDmode,
                                             cond, cop1);
 
@@ -3682,7 +4232,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
                       && true_rtx == const0_rtx
                       && ((reversed = reversed_comparison_code_parts
                                        (cond_code, cond, cop1, NULL))
-                          != UNKNOWN))
+                          != UNKNOWN))
                x = simplify_gen_unary (NEG, mode,
                                        simplify_gen_relational (reversed,
                                                                 mode, VOIDmode,
@@ -3826,7 +4376,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
        return gen_lowpart (mode, SUBREG_REG (x));
 
       if (GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_CC)
-        break;
+       break;
       {
        rtx temp;
        temp = simplify_subreg (mode, SUBREG_REG (x), op0_mode,
@@ -3837,7 +4387,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
 
       /* Don't change the mode of the MEM if that would change the meaning
         of the address.  */
-      if (GET_CODE (SUBREG_REG (x)) == MEM
+      if (MEM_P (SUBREG_REG (x))
          && (MEM_VOLATILE_P (SUBREG_REG (x))
              || mode_dependent_address_p (XEXP (SUBREG_REG (x), 0))))
        return gen_rtx_CLOBBER (mode, const0_rtx);
@@ -3848,60 +4398,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
 
       break;
 
-    case NOT:
-      if (GET_CODE (XEXP (x, 0)) == SUBREG
-         && subreg_lowpart_p (XEXP (x, 0))
-         && (GET_MODE_SIZE (GET_MODE (XEXP (x, 0)))
-             < GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (x, 0)))))
-         && GET_CODE (SUBREG_REG (XEXP (x, 0))) == ASHIFT
-         && XEXP (SUBREG_REG (XEXP (x, 0)), 0) == const1_rtx)
-       {
-         enum machine_mode inner_mode = GET_MODE (SUBREG_REG (XEXP (x, 0)));
-
-         x = gen_rtx_ROTATE (inner_mode,
-                             simplify_gen_unary (NOT, inner_mode, const1_rtx,
-                                                 inner_mode),
-                             XEXP (SUBREG_REG (XEXP (x, 0)), 1));
-         return gen_lowpart (mode, x);
-       }
-
-      /* 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
-        coded.  */
-
-      if (GET_CODE (XEXP (x, 0)) == IOR || GET_CODE (XEXP (x, 0)) == AND)
-       {
-         rtx in1 = XEXP (XEXP (x, 0), 0), in2 = XEXP (XEXP (x, 0), 1);
-         enum machine_mode op_mode;
-
-         op_mode = GET_MODE (in1);
-         in1 = simplify_gen_unary (NOT, op_mode, in1, op_mode);
-
-         op_mode = GET_MODE (in2);
-         if (op_mode == VOIDmode)
-           op_mode = mode;
-         in2 = simplify_gen_unary (NOT, op_mode, in2, op_mode);
-
-         if (GET_CODE (in2) == NOT && GET_CODE (in1) != NOT)
-           {
-             rtx tem = in2;
-             in2 = in1; in1 = tem;
-           }
-
-         return gen_rtx_fmt_ee (GET_CODE (XEXP (x, 0)) == IOR ? AND : IOR,
-                                mode, in1, in2);
-       }
-      break;
-
     case NEG:
-      /* (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
-         && nonzero_bits (XEXP (XEXP (x, 0), 0), mode) == 1)
-       return simplify_gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0),
-                                   constm1_rtx);
-
       temp = expand_compound_operation (XEXP (x, 0));
 
       /* For C equal to the width of MODE minus 1, (neg (ashiftrt X C)) can be
@@ -3911,7 +4408,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
       if (GET_CODE (temp) == ASHIFTRT
          && GET_CODE (XEXP (temp, 1)) == CONST_INT
          && INTVAL (XEXP (temp, 1)) == GET_MODE_BITSIZE (mode) - 1)
-       return simplify_shift_const (temp, LSHIFTRT, mode, XEXP (temp, 0),
+       return simplify_shift_const (NULL_RTX, LSHIFTRT, mode, XEXP (temp, 0),
                                     INTVAL (XEXP (temp, 1)));
 
       /* If X has only a single bit that might be nonzero, say, bit I, convert
@@ -3921,9 +4418,9 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
         or a SUBREG of one since we'd be making the expression more
         complex if it was just a register.  */
 
-      if (GET_CODE (temp) != REG
+      if (!REG_P (temp)
          && ! (GET_CODE (temp) == SUBREG
-               && GET_CODE (SUBREG_REG (temp)) == REG)
+               && REG_P (SUBREG_REG (temp)))
          && (i = exact_log2 (nonzero_bits (temp, mode))) >= 0)
        {
          rtx temp1 = simplify_shift_const
@@ -3953,134 +4450,19 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
          && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
                                    GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))))
        SUBST (XEXP (x, 0),
-              force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
-                             GET_MODE_MASK (mode), NULL_RTX, 0));
-
-      /* (truncate:SI ({sign,zero}_extend:DI foo:SI)) == foo:SI.  */
-      if ((GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
-          || GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
-         && GET_MODE (XEXP (XEXP (x, 0), 0)) == mode)
-       return XEXP (XEXP (x, 0), 0);
-
-      /* (truncate:SI (OP:DI ({sign,zero}_extend:DI foo:SI))) is
-        (OP:SI foo:SI) if OP is NEG or ABS.  */
-      if ((GET_CODE (XEXP (x, 0)) == ABS
-          || GET_CODE (XEXP (x, 0)) == NEG)
-         && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SIGN_EXTEND
-             || GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND)
-         && GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == mode)
-       return simplify_gen_unary (GET_CODE (XEXP (x, 0)), mode,
-                                  XEXP (XEXP (XEXP (x, 0), 0), 0), mode);
-
-      /* (truncate:SI (subreg:DI (truncate:SI X) 0)) is
-        (truncate:SI x).  */
-      if (GET_CODE (XEXP (x, 0)) == SUBREG
-         && GET_CODE (SUBREG_REG (XEXP (x, 0))) == TRUNCATE
-         && subreg_lowpart_p (XEXP (x, 0)))
-       return SUBREG_REG (XEXP (x, 0));
-
-      /* If we know that the value is already truncated, we can
-         replace the TRUNCATE with a SUBREG if TRULY_NOOP_TRUNCATION
-         is nonzero for the corresponding modes.  But don't do this
-         for an (LSHIFTRT (MULT ...)) since this will cause problems
-         with the umulXi3_highpart patterns.  */
-      if (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
-                                GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))
-         && num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
-            >= (unsigned int) (GET_MODE_BITSIZE (mode) + 1)
-         && ! (GET_CODE (XEXP (x, 0)) == LSHIFTRT
-               && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT))
-       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
-         && COMPARISON_P (XEXP (x, 0))
-         && ((HOST_WIDE_INT) STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0)
-       return gen_lowpart (mode, XEXP (x, 0));
+              force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
+                             GET_MODE_MASK (mode), 0));
 
-      /* Similarly, a truncate of a register whose value is a
-         comparison can be replaced with a subreg if STORE_FLAG_VALUE
-         permits.  */
+      /* Similarly to what we do in simplify-rtx.c, a truncate of a register
+        whose value is a comparison can be replaced with a subreg if
+        STORE_FLAG_VALUE permits.  */
       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)))
          && COMPARISON_P (temp))
        return gen_lowpart (mode, XEXP (x, 0));
-
-      break;
-
-    case FLOAT_TRUNCATE:
-      /* (float_truncate:SF (float_extend:DF foo:SF)) = foo:SF.  */
-      if (GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND
-         && 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 eliminate double rounding, so it is unsafe.
-
-         (float_truncate:SF (float_extend:XF foo:DF))
-         = (float_truncate:SF foo:DF).
-
-         (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)
-                                  ? FLOAT_TRUNCATE : FLOAT_EXTEND,
-                                  mode,
-                                  XEXP (XEXP (x, 0), 0), mode);
-
-      /*  (float_truncate (float x)) is (float x)  */
-      if (GET_CODE (XEXP (x, 0)) == FLOAT
-         && (flag_unsafe_math_optimizations
-             || ((unsigned)significand_size (GET_MODE (XEXP (x, 0)))
-                 >= (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (x, 0), 0)))
-                     - num_sign_bit_copies (XEXP (XEXP (x, 0), 0),
-                                            GET_MODE (XEXP (XEXP (x, 0), 0)))))))
-       return simplify_gen_unary (FLOAT, mode,
-                                  XEXP (XEXP (x, 0), 0),
-                                  GET_MODE (XEXP (XEXP (x, 0), 0)));
-
-      /* (float_truncate:SF (OP:DF (float_extend:DF foo:sf))) is
-        (OP:SF foo:SF) if OP is NEG or ABS.  */
-      if ((GET_CODE (XEXP (x, 0)) == ABS
-          || GET_CODE (XEXP (x, 0)) == NEG)
-         && GET_CODE (XEXP (XEXP (x, 0), 0)) == FLOAT_EXTEND
-         && GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == mode)
-       return simplify_gen_unary (GET_CODE (XEXP (x, 0)), mode,
-                                  XEXP (XEXP (XEXP (x, 0), 0), 0), mode);
-
-      /* (float_truncate:SF (subreg:DF (float_truncate:SF X) 0))
-        is (float_truncate:SF x).  */
-      if (GET_CODE (XEXP (x, 0)) == SUBREG
-         && subreg_lowpart_p (XEXP (x, 0))
-         && GET_CODE (SUBREG_REG (XEXP (x, 0))) == FLOAT_TRUNCATE)
-       return SUBREG_REG (XEXP (x, 0));
       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.
-          */
-      if (GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND
-         || (GET_CODE (XEXP (x, 0)) == FLOAT
-             && ((unsigned)significand_size (GET_MODE (XEXP (x, 0)))
-                 >= (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (x, 0), 0)))
-                     - num_sign_bit_copies (XEXP (XEXP (x, 0), 0),
-                                            GET_MODE (XEXP (XEXP (x, 0), 0)))))))
-       return simplify_gen_unary (GET_CODE (XEXP (x, 0)), mode,
-                                  XEXP (XEXP (x, 0), 0),
-                                  GET_MODE (XEXP (XEXP (x, 0), 0)));
 
-      break;
 #ifdef HAVE_cc0
     case COMPARE:
       /* Convert (compare FOO (const_int 0)) to FOO unless we aren't
@@ -4119,32 +4501,6 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
 #endif
 
     case PLUS:
-      /* Canonicalize (plus (mult (neg B) C) A) to (minus A (mult B C)).
-       */
-      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 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
-        outermost.  That's because that's the way indexed addresses are
-        supposed to appear.  This code used to check many more cases, but
-        they are now checked elsewhere.  */
-      if (GET_CODE (XEXP (x, 0)) == PLUS
-         && CONSTANT_ADDRESS_P (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
         bit-field and can be replaced by either a sign_extend or a
@@ -4171,27 +4527,14 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
                                 GET_MODE_BITSIZE (mode) - (i + 1)),
           GET_MODE_BITSIZE (mode) - (i + 1));
 
-      /* (plus (comparison A B) C) can become (neg (rev-comp A B)) if
-        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 (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,
-                                             XEXP (XEXP (x, 0), 0),
-                                             XEXP (XEXP (x, 0), 1))))
-       return
-         simplify_gen_unary (NEG, mode, reversed, mode);
-
       /* If only the low-order bit of X is possibly nonzero, (plus x -1)
         can become (ashiftrt (ashift (xor x 1) C) C) where C is
         the bitsize of the mode - 1.  This allows simplification of
         "a = (b & 8) == 0;"  */
       if (XEXP (x, 1) == constm1_rtx
-         && GET_CODE (XEXP (x, 0)) != REG
+         && !REG_P (XEXP (x, 0))
          && ! (GET_CODE (XEXP (x, 0)) == SUBREG
-               && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG)
+               && REG_P (SUBREG_REG (XEXP (x, 0))))
          && nonzero_bits (XEXP (x, 0), mode) == 1)
        return simplify_shift_const (NULL_RTX, ASHIFTRT, mode,
           simplify_shift_const (NULL_RTX, ASHIFT, mode,
@@ -4221,16 +4564,6 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
       break;
 
     case MINUS:
-      /* If STORE_FLAG_VALUE is 1, (minus 1 (comparison foo bar)) can be done
-        by reversing the comparison code if valid.  */
-      if (STORE_FLAG_VALUE == 1
-         && XEXP (x, 0) == const1_rtx
-         && COMPARISON_P (XEXP (x, 1))
-         && (reversed = reversed_comparison (XEXP (x, 1), mode,
-                                             XEXP (XEXP (x, 1), 0),
-                                             XEXP (XEXP (x, 1), 1))))
-       return reversed;
-
       /* (minus <foo> (and <foo> (const_int -pow2))) becomes
         (and <foo> (const_int pow2-1))  */
       if (GET_CODE (XEXP (x, 1)) == AND
@@ -4239,45 +4572,6 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
          && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
        return simplify_and_const_int (NULL_RTX, mode, XEXP (x, 0),
                                       -INTVAL (XEXP (XEXP (x, 1), 1)) - 1);
-
-      /* Canonicalize (minus A (mult (neg B) C)) to (plus (mult B C) A).
-       */
-      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 simplify_gen_binary (PLUS, mode,
-                                     simplify_gen_binary (MULT, mode,
-                                                          in1, in2),
-                                     XEXP (x, 0));
-       }
-
-      /* Canonicalize (minus (neg A) (mult B C)) to
-        (minus (mult (neg B) C) A).  */
-      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 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 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:
@@ -4287,7 +4581,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
 
       if (GET_CODE (XEXP (x, 0)) == PLUS)
        {
-         rtx result = distribute_and_simplify_rtx (x);
+         rtx result = distribute_and_simplify_rtx (x, 0);
          if (result)
            return result;
        }
@@ -4493,55 +4787,8 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
 
     case AND:
     case IOR:
-    case XOR:
       return simplify_logical (x);
 
-    case ABS:
-      /* (abs (neg <foo>)) -> (abs <foo>) */
-      if (GET_CODE (XEXP (x, 0)) == NEG)
-       SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
-
-      /* If the mode of the operand is VOIDmode (i.e. if it is ASM_OPERANDS),
-         do nothing.  */
-      if (GET_MODE (XEXP (x, 0)) == VOIDmode)
-       break;
-
-      /* If operand is something known to be positive, ignore the ABS.  */
-      if (GET_CODE (XEXP (x, 0)) == FFS || GET_CODE (XEXP (x, 0)) == ABS
-         || ((GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
-              <= HOST_BITS_PER_WIDE_INT)
-             && ((nonzero_bits (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
-                  & ((HOST_WIDE_INT) 1
-                     << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1)))
-                 == 0)))
-       return XEXP (x, 0);
-
-      /* If operand is known to be only -1 or 0, convert ABS to NEG.  */
-      if (num_sign_bit_copies (XEXP (x, 0), mode) == GET_MODE_BITSIZE (mode))
-       return gen_rtx_NEG (mode, XEXP (x, 0));
-
-      break;
-
-    case FFS:
-      /* (ffs (*_extend <X>)) = (ffs <X>) */
-      if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
-         || GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
-       SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
-      break;
-
-    case POPCOUNT:
-    case PARITY:
-      /* (pop* (zero_extend <X>)) = (pop* <X>) */
-      if (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
-       SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
-      break;
-
-    case FLOAT:
-      /* (float (sign_extend <X>)) = (float <X>).  */
-      if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND)
-       SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
-      break;
-
     case ASHIFT:
     case LSHIFTRT:
     case ASHIFTRT:
@@ -4552,52 +4799,13 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
        return simplify_shift_const (x, code, mode, XEXP (x, 0),
                                     INTVAL (XEXP (x, 1)));
 
-      else if (SHIFT_COUNT_TRUNCATED && GET_CODE (XEXP (x, 1)) != REG)
+      else if (SHIFT_COUNT_TRUNCATED && !REG_P (XEXP (x, 1)))
        SUBST (XEXP (x, 1),
               force_to_mode (XEXP (x, 1), GET_MODE (XEXP (x, 1)),
                              ((HOST_WIDE_INT) 1
                               << exact_log2 (GET_MODE_BITSIZE (GET_MODE (x))))
                              - 1,
-                             NULL_RTX, 0));
-      break;
-
-    case VEC_SELECT:
-      {
-       rtx op0 = XEXP (x, 0);
-       rtx op1 = XEXP (x, 1);
-       int len;
-
-       if (GET_CODE (op1) != PARALLEL)
-         abort ();
-       len = XVECLEN (op1, 0);
-       if (len == 1
-           && GET_CODE (XVECEXP (op1, 0, 0)) == CONST_INT
-           && GET_CODE (op0) == VEC_CONCAT)
-         {
-           int offset = INTVAL (XVECEXP (op1, 0, 0)) * GET_MODE_SIZE (GET_MODE (x));
-
-           /* Try to find the element in the VEC_CONCAT.  */
-           for (;;)
-             {
-               if (GET_MODE (op0) == GET_MODE (x))
-                 return op0;
-               if (GET_CODE (op0) == VEC_CONCAT)
-                 {
-                   HOST_WIDE_INT op0_size = GET_MODE_SIZE (GET_MODE (XEXP (op0, 0)));
-                   if (op0_size < offset)
-                     op0 = XEXP (op0, 0);
-                   else
-                     {
-                       offset -= op0_size;
-                       op0 = XEXP (op0, 1);
-                     }
-                 }
-               else
-                 break;
-             }
-         }
-      }
-
+                             0));
       break;
 
     default:
@@ -4631,8 +4839,7 @@ simplify_if_then_else (rtx x)
   /* Also when the truth value has to be reversed.  */
   if (comparison_p
       && true_rtx == const0_rtx && false_rtx == const_true_rtx
-      && (reversed = reversed_comparison (cond, mode, XEXP (cond, 0),
-                                         XEXP (cond, 1))))
+      && (reversed = reversed_comparison (cond, mode)))
     return reversed;
 
   /* Sometimes we can simplify the arm of an IF_THEN_ELSE if a register used
@@ -4640,9 +4847,9 @@ simplify_if_then_else (rtx x)
      comparisons and see if that says anything about the value of each arm.  */
 
   if (comparison_p
-      && ((false_code = combine_reversed_comparison_code (cond))
+      && ((false_code = reversed_comparison_code (cond, NULL))
          != UNKNOWN)
-      && GET_CODE (XEXP (cond, 0)) == REG)
+      && REG_P (XEXP (cond, 0)))
     {
       HOST_WIDE_INT nzb;
       rtx from = XEXP (cond, 0);
@@ -4698,7 +4905,7 @@ simplify_if_then_else (rtx x)
      the false arm is more complicated than the true arm.  */
 
   if (comparison_p
-      && combine_reversed_comparison_code (cond) != UNKNOWN
+      && reversed_comparison_code (cond, NULL) != UNKNOWN
       && (true_rtx == pc_rtx
          || (CONSTANT_P (true_rtx)
              && GET_CODE (false_rtx) != CONST_INT && false_rtx != pc_rtx)
@@ -4710,10 +4917,7 @@ simplify_if_then_else (rtx x)
          || rtx_equal_p (false_rtx, XEXP (cond, 0))))
     {
       true_code = reversed_comparison_code (cond, NULL);
-      SUBST (XEXP (x, 0),
-            reversed_comparison (cond, GET_MODE (cond), XEXP (cond, 0),
-                                 XEXP (cond, 1)));
-
+      SUBST (XEXP (x, 0), reversed_comparison (cond, GET_MODE (cond)));
       SUBST (XEXP (x, 1), false_rtx);
       SUBST (XEXP (x, 2), true_rtx);
 
@@ -4806,7 +5010,7 @@ simplify_if_then_else (rtx x)
       rtx f = make_compound_operation (false_rtx, SET);
       rtx cond_op0 = XEXP (cond, 0);
       rtx cond_op1 = XEXP (cond, 1);
-      enum rtx_code op = NIL, extend_op = NIL;
+      enum rtx_code op = UNKNOWN, extend_op = UNKNOWN;
       enum machine_mode m = mode;
       rtx z = 0, c1 = NULL_RTX;
 
@@ -4907,7 +5111,7 @@ simplify_if_then_else (rtx x)
          temp = subst (temp, pc_rtx, pc_rtx, 0, 0);
          temp = simplify_gen_binary (op, m, gen_lowpart (m, z), temp);
 
-         if (extend_op != NIL)
+         if (extend_op != UNKNOWN)
            temp = simplify_gen_unary (extend_op, mode, temp, m);
 
          return temp;
@@ -4965,7 +5169,7 @@ simplify_set (rtx x)
   if (GET_MODE_CLASS (mode) == MODE_INT
       && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
     {
-      src = force_to_mode (src, mode, ~(HOST_WIDE_INT) 0, NULL_RTX, 0);
+      src = force_to_mode (src, mode, ~(HOST_WIDE_INT) 0, 0);
       SUBST (SET_SRC (x), src);
     }
 
@@ -4989,18 +5193,18 @@ simplify_set (rtx x)
       if (GET_CODE (src) == COMPARE)
        op0 = XEXP (src, 0), op1 = XEXP (src, 1);
       else
-       op0 = src, op1 = const0_rtx;
+       op0 = src, op1 = CONST0_RTX (GET_MODE (src));
 
       tmp = simplify_relational_operation (old_code, compare_mode, VOIDmode,
                                           op0, op1);
       if (!tmp)
-        new_code = old_code;
+       new_code = old_code;
       else if (!CONSTANT_P (tmp))
-        {
-          new_code = GET_CODE (tmp);
-          op0 = XEXP (tmp, 0);
-          op1 = XEXP (tmp, 1);
-        }
+       {
+         new_code = GET_CODE (tmp);
+         op0 = XEXP (tmp, 0);
+         op1 = XEXP (tmp, 1);
+       }
       else
        {
          rtx pat = PATTERN (other_insn);
@@ -5040,14 +5244,18 @@ simplify_set (rtx x)
         which case we can safely change its mode.  */
       if (compare_mode != GET_MODE (dest))
        {
-         unsigned int regno = REGNO (dest);
-         rtx new_dest = gen_rtx_REG (compare_mode, regno);
-
-         if (regno < FIRST_PSEUDO_REGISTER
-             || (REG_N_SETS (regno) == 1 && ! REG_USERVAR_P (dest)))
+         if (can_change_dest_mode (dest, 0, compare_mode))
            {
-             if (regno >= FIRST_PSEUDO_REGISTER)
-               SUBST (regno_reg_rtx[regno], new_dest);
+             unsigned int regno = REGNO (dest);
+             rtx new_dest;
+
+             if (regno < FIRST_PSEUDO_REGISTER)
+               new_dest = gen_rtx_REG (compare_mode, regno);
+             else
+               {
+                 SUBST_MODE (regno_reg_rtx[regno], compare_mode);
+                 new_dest = regno_reg_rtx[regno];
+               }
 
              SUBST (SET_DEST (x), new_dest);
              SUBST (XEXP (*cc_use, 0), new_dest);
@@ -5117,6 +5325,11 @@ simplify_set (rtx x)
          SUBST (SET_SRC (x), gen_rtx_COMPARE (compare_mode, op0, op1));
          src = SET_SRC (x);
        }
+      else if (GET_MODE (op0) == compare_mode && op1 == const0_rtx)
+       {
+         SUBST(SET_SRC (x), op0);
+         src = SET_SRC (x);
+       }
       else
        {
          /* Otherwise, update the COMPARE if needed.  */
@@ -5152,17 +5365,17 @@ simplify_set (rtx x)
               + (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_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER
            && REG_CANNOT_CHANGE_MODE_P (REGNO (dest),
                                         GET_MODE (SUBREG_REG (src)),
                                         GET_MODE (src)))
 #endif
-      && (GET_CODE (dest) == REG
+      && (REG_P (dest)
          || (GET_CODE (dest) == SUBREG
-             && GET_CODE (SUBREG_REG (dest)) == REG)))
+             && REG_P (SUBREG_REG (dest)))))
     {
       SUBST (SET_DEST (x),
             gen_lowpart (GET_MODE (SUBREG_REG (src)),
@@ -5202,11 +5415,11 @@ simplify_set (rtx x)
      zero_extend to avoid the reload that would otherwise be required.  */
 
   if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
-      && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))) != NIL
+      && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))) != UNKNOWN
       && SUBREG_BYTE (src) == 0
       && (GET_MODE_SIZE (GET_MODE (src))
          > GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))
-      && GET_CODE (SUBREG_REG (src)) == MEM)
+      && MEM_P (SUBREG_REG (src)))
     {
       SUBST (SET_SRC (x),
             gen_rtx_fmt_e (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))),
@@ -5292,42 +5505,10 @@ simplify_logical (rtx x)
   enum machine_mode mode = GET_MODE (x);
   rtx op0 = XEXP (x, 0);
   rtx op1 = XEXP (x, 1);
-  rtx reversed;
 
   switch (GET_CODE (x))
     {
     case AND:
-      /* Convert (A ^ B) & A to A & (~B) since the latter is often a single
-        insn (and may simplify more).  */
-      if (GET_CODE (op0) == XOR
-         && rtx_equal_p (XEXP (op0, 0), op1)
-         && ! side_effects_p (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 = 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 = 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 = 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
         "unsigned HOST_WIDE_INT".  */
@@ -5336,22 +5517,6 @@ simplify_logical (rtx x)
              || INTVAL (op1) > 0))
        {
          x = simplify_and_const_int (x, mode, op0, INTVAL (op1));
-
-         /* 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.  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
-             && (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;
 
@@ -5359,177 +5524,44 @@ simplify_logical (rtx x)
          op1 = XEXP (x, 1);
        }
 
-      /* Convert (A | B) & A to A.  */
-      if (GET_CODE (op0) == IOR
-         && (rtx_equal_p (XEXP (op0, 0), op1)
-             || rtx_equal_p (XEXP (op0, 1), op1))
-         && ! side_effects_p (XEXP (op0, 0))
-         && ! side_effects_p (XEXP (op0, 1)))
-       return op1;
-
       /* 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)
+      if (GET_CODE (op0) == IOR || GET_CODE (op0) == XOR)
+       {
+         rtx result = distribute_and_simplify_rtx (x, 0);
+         if (result)
+           return result;
+       }
+      if (GET_CODE (op1) == IOR || GET_CODE (op1) == XOR)
        {
-         rtx result = distribute_and_simplify_rtx (x);
+         rtx result = distribute_and_simplify_rtx (x, 1);
          if (result)
            return result;
        }
       break;
 
     case IOR:
-      /* (ior A C) is C if all bits of A that might be nonzero are on in C.  */
-      if (GET_CODE (op1) == CONST_INT
-         && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-         && (nonzero_bits (op0, mode) & ~INTVAL (op1)) == 0)
-       return op1;
-
-      /* Convert (A & B) | A to A.  */
-      if (GET_CODE (op0) == AND
-         && (rtx_equal_p (XEXP (op0, 0), op1)
-             || rtx_equal_p (XEXP (op0, 1), op1))
-         && ! side_effects_p (XEXP (op0, 0))
-         && ! side_effects_p (XEXP (op0, 1)))
-       return op1;
-
       /* 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 || GET_CODE (op1) == AND)
+      if (GET_CODE (op0) == AND)
        {
-         rtx result = distribute_and_simplify_rtx (x);
+         rtx result = distribute_and_simplify_rtx (x, 0);
          if (result)
            return result;
        }
 
-      /* Convert (ior (ashift A CX) (lshiftrt A CY)) where CX+CY equals the
-        mode size to (rotate A CX).  */
-
-      if (((GET_CODE (op0) == ASHIFT && GET_CODE (op1) == LSHIFTRT)
-          || (GET_CODE (op1) == ASHIFT && GET_CODE (op0) == LSHIFTRT))
-         && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))
-         && GET_CODE (XEXP (op0, 1)) == CONST_INT
-         && GET_CODE (XEXP (op1, 1)) == CONST_INT
-         && (INTVAL (XEXP (op0, 1)) + INTVAL (XEXP (op1, 1))
-             == GET_MODE_BITSIZE (mode)))
-       return gen_rtx_ROTATE (mode, XEXP (op0, 0),
-                              (GET_CODE (op0) == ASHIFT
-                               ? XEXP (op0, 1) : XEXP (op1, 1)));
-
-      /* If OP0 is (ashiftrt (plus ...) C), it might actually be
-        a (sign_extend (plus ...)).  If so, OP1 is a CONST_INT, and the PLUS
-        does not affect any of the bits in OP1, it can really be done
-        as a PLUS and we can associate.  We do this by seeing if OP1
-        can be safely shifted left C bits.  */
-      if (GET_CODE (op1) == CONST_INT && GET_CODE (op0) == ASHIFTRT
-         && GET_CODE (XEXP (op0, 0)) == PLUS
-         && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
-         && GET_CODE (XEXP (op0, 1)) == CONST_INT
-         && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT)
+      if (GET_CODE (op1) == AND)
        {
-         int count = INTVAL (XEXP (op0, 1));
-         HOST_WIDE_INT mask = INTVAL (op1) << count;
-
-         if (mask >> count == INTVAL (op1)
-             && (mask & nonzero_bits (XEXP (op0, 0), mode)) == 0)
-           {
-             SUBST (XEXP (XEXP (op0, 0), 1),
-                    GEN_INT (INTVAL (XEXP (XEXP (op0, 0), 1)) | mask));
-             return op0;
-           }
+         rtx result = distribute_and_simplify_rtx (x, 1);
+         if (result)
+           return result;
        }
       break;
 
-    case XOR:
-      /* If we are XORing two things that have no bits in common,
-        convert them into an IOR.  This helps to detect rotation encoded
-        using those methods and possibly other simplifications.  */
-
-      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-         && (nonzero_bits (op0, mode)
-             & nonzero_bits (op1, mode)) == 0)
-       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
-        (NOT y).  */
-      {
-       int num_negated = 0;
-
-       if (GET_CODE (op0) == NOT)
-         num_negated++, op0 = XEXP (op0, 0);
-       if (GET_CODE (op1) == NOT)
-         num_negated++, op1 = XEXP (op1, 0);
-
-       if (num_negated == 2)
-         {
-           SUBST (XEXP (x, 0), op0);
-           SUBST (XEXP (x, 1), op1);
-         }
-       else if (num_negated == 1)
-         return
-           simplify_gen_unary (NOT, mode,
-                               simplify_gen_binary (XOR, mode, op0, op1),
-                               mode);
-      }
-
-      /* Convert (xor (and A B) B) to (and (not A) B).  The latter may
-        correspond to a machine insn or result in further simplifications
-        if B is a constant.  */
-
-      if (GET_CODE (op0) == AND
-         && rtx_equal_p (XEXP (op0, 1), op1)
-         && ! side_effects_p (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 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
-         && COMPARISON_P (op0)
-         && (reversed = reversed_comparison (op0, mode, XEXP (op0, 0),
-                                             XEXP (op0, 1))))
-       return reversed;
-
-      /* (lshiftrt foo C) where C is the number of bits in FOO minus 1
-        is (lt foo (const_int 0)), so we can perform the above
-        simplification if STORE_FLAG_VALUE is 1.  */
-
-      if (STORE_FLAG_VALUE == 1
-         && op1 == const1_rtx
-         && GET_CODE (op0) == LSHIFTRT
-         && GET_CODE (XEXP (op0, 1)) == CONST_INT
-         && INTVAL (XEXP (op0, 1)) == GET_MODE_BITSIZE (mode) - 1)
-       return gen_rtx_GE (mode, XEXP (op0, 0), const0_rtx);
-
-      /* (xor (comparison foo bar) (const_int sign-bit))
-        when STORE_FLAG_VALUE is the sign bit.  */
-      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-         && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
-             == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
-         && op1 == const_true_rtx
-         && COMPARISON_P (op0)
-         && (reversed = reversed_comparison (op0, mode, XEXP (op0, 0),
-                                             XEXP (op0, 1))))
-       return reversed;
-
-      break;
-
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   return x;
@@ -5601,6 +5633,9 @@ expand_compound_operation (rtx x)
 
     case ZERO_EXTRACT:
       unsignedp = 1;
+
+      /* ... fall through ...  */
+
     case SIGN_EXTRACT:
       /* If the operand is a CLOBBER, just return it.  */
       if (GET_CODE (XEXP (x, 0)) == CLOBBER)
@@ -5620,11 +5655,9 @@ expand_compound_operation (rtx x)
       len = INTVAL (XEXP (x, 1));
       pos = INTVAL (XEXP (x, 2));
 
-      /* If this goes outside the object being extracted, replace the object
-        with a (use (mem ...)) construct that only combine understands
-        and is used only for this purpose.  */
+      /* This should stay within the object being extracted, fail otherwise.  */
       if (len + pos > GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))
-       SUBST (XEXP (x, 0), gen_rtx_USE (GET_MODE (x), XEXP (x, 0)));
+       return x;
 
       if (BITS_BIG_ENDIAN)
        pos = GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - len - pos;
@@ -5661,8 +5694,8 @@ expand_compound_operation (rtx x)
   if (GET_CODE (x) == ZERO_EXTEND)
     {
       /* (zero_extend:DI (truncate:SI foo:DI)) is just foo:DI if we
-         know that the last value didn't have any inappropriate bits
-         set.  */
+        know that the last value didn't have any inappropriate bits
+        set.  */
       if (GET_CODE (XEXP (x, 0)) == TRUNCATE
          && GET_MODE (XEXP (XEXP (x, 0), 0)) == GET_MODE (x)
          && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
@@ -5680,9 +5713,9 @@ expand_compound_operation (rtx x)
        return SUBREG_REG (XEXP (x, 0));
 
       /* (zero_extend:DI (truncate:SI foo:DI)) is just foo:DI when foo
-         is a comparison and STORE_FLAG_VALUE permits.  This is like
-         the first case, but it works even when GET_MODE (x) is larger
-         than HOST_WIDE_INT.  */
+        is a comparison and STORE_FLAG_VALUE permits.  This is like
+        the first case, but it works even when GET_MODE (x) is larger
+        than HOST_WIDE_INT.  */
       if (GET_CODE (XEXP (x, 0)) == TRUNCATE
          && GET_MODE (XEXP (XEXP (x, 0), 0)) == GET_MODE (x)
          && COMPARISON_P (XEXP (XEXP (x, 0), 0))
@@ -5722,14 +5755,16 @@ expand_compound_operation (rtx x)
 
   modewidth = GET_MODE_BITSIZE (GET_MODE (x));
   if (modewidth + len >= pos)
-    tem = simplify_shift_const (NULL_RTX, unsignedp ? LSHIFTRT : ASHIFTRT,
-                               GET_MODE (x),
-                               simplify_shift_const (NULL_RTX, ASHIFT,
-                                                     GET_MODE (x),
-                                                     XEXP (x, 0),
-                                                     modewidth - pos - len),
-                               modewidth - len);
-
+    {
+      enum machine_mode mode = GET_MODE (x);
+      tem = gen_lowpart (mode, XEXP (x, 0));
+      if (!tem || GET_CODE (tem) == CLOBBER)
+       return x;
+      tem = simplify_shift_const (NULL_RTX, ASHIFT, mode,
+                                 tem, modewidth - pos - len);
+      tem = simplify_shift_const (NULL_RTX, unsignedp ? LSHIFTRT : ASHIFTRT,
+                                 mode, tem, modewidth - len);
+    }
   else if (unsignedp && len < HOST_BITS_PER_WIDE_INT)
     tem = simplify_and_const_int (NULL_RTX, GET_MODE (x),
                                  simplify_shift_const (NULL_RTX, LSHIFTRT,
@@ -5782,11 +5817,10 @@ expand_field_assignment (rtx x)
          len = INTVAL (XEXP (SET_DEST (x), 1));
          pos = XEXP (SET_DEST (x), 2);
 
-         /* If the position is constant and spans the width of INNER,
-            surround INNER  with a USE to indicate this.  */
+         /* A constant position should stay within the width of INNER.  */
          if (GET_CODE (pos) == CONST_INT
              && INTVAL (pos) + len > GET_MODE_BITSIZE (GET_MODE (inner)))
-           inner = gen_rtx_USE (GET_MODE (SET_DEST (x)), inner);
+           break;
 
          if (BITS_BIG_ENDIAN)
            {
@@ -5884,13 +5918,6 @@ expand_field_assignment (rtx x)
    it is an RTX that represents a variable starting position; otherwise,
    POS is the (constant) starting bit position (counted from the LSB).
 
-   INNER may be a USE.  This will occur when we started with a bitfield
-   that went outside the boundary of the object in memory, which is
-   allowed on most machines.  To isolate this case, we produce a USE
-   whose mode is wide enough and surround the MEM with it.  The only
-   code that understands the USE is this routine.  If it is not removed,
-   it will cause the resulting insn not to match.
-
    UNSIGNEDP is nonzero for an unsigned reference and zero for a
    signed reference.
 
@@ -5917,30 +5944,23 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
      ignore the POS lowest bits, etc.  */
   enum machine_mode is_mode = GET_MODE (inner);
   enum machine_mode inner_mode;
-  enum machine_mode wanted_inner_mode = byte_mode;
+  enum machine_mode wanted_inner_mode;
   enum machine_mode wanted_inner_reg_mode = word_mode;
   enum machine_mode pos_mode = word_mode;
   enum machine_mode extraction_mode = word_mode;
   enum machine_mode tmode = mode_for_size (len, MODE_INT, 1);
-  int spans_byte = 0;
   rtx new = 0;
   rtx orig_pos_rtx = pos_rtx;
   HOST_WIDE_INT orig_pos;
 
-  /* Get some information about INNER and get the innermost object.  */
-  if (GET_CODE (inner) == USE)
-    /* (use:SI (mem:QI foo)) stands for (mem:SI foo).  */
-    /* We don't need to adjust the position because we set up the USE
-       to pretend that it was a full-word object.  */
-    spans_byte = 1, inner = XEXP (inner, 0);
-  else if (GET_CODE (inner) == SUBREG && subreg_lowpart_p (inner))
+  if (GET_CODE (inner) == SUBREG && subreg_lowpart_p (inner))
     {
       /* If going from (subreg:SI (mem:QI ...)) to (mem:QI ...),
         consider just the QI as the memory to extract from.
         The subreg adds or removes high bits; its mode is
         irrelevant to the meaning of this extraction,
         since POS and LEN count from the lsb.  */
-      if (GET_CODE (SUBREG_REG (inner)) == MEM)
+      if (MEM_P (SUBREG_REG (inner)))
        is_mode = GET_MODE (SUBREG_REG (inner));
       inner = SUBREG_REG (inner);
     }
@@ -5972,20 +5992,20 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
      appropriate STRICT_LOW_PART operation available.
 
      For MEM, we can avoid an extract if the field starts on an appropriate
-     boundary and we can change the mode of the memory reference.  However,
-     we cannot directly access the MEM if we have a USE and the underlying
-     MEM is not TMODE.  This combination means that MEM was being used in a
-     context where bits outside its mode were being referenced; that is only
-     valid in bit-field insns.  */
+     boundary and we can change the mode of the memory reference.  */
 
   if (tmode != BLKmode
-      && ! (spans_byte && inner_mode != tmode)
       && ((pos_rtx == 0 && (pos % BITS_PER_WORD) == 0
-          && GET_CODE (inner) != MEM
+          && !MEM_P (inner)
+          && (inner_mode == tmode
+              || !REG_P (inner)
+              || TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (tmode),
+                                        GET_MODE_BITSIZE (inner_mode))
+              || reg_truncated_to_mode (tmode, inner))
           && (! in_dest
-              || (GET_CODE (inner) == REG
+              || (REG_P (inner)
                   && have_insn_for (STRICT_LOW_PART, tmode))))
-         || (GET_CODE (inner) == MEM && pos_rtx == 0
+         || (MEM_P (inner) && pos_rtx == 0
              && (pos
                  % (STRICT_ALIGNMENT ? GET_MODE_ALIGNMENT (tmode)
                     : BITS_PER_UNIT)) == 0
@@ -6003,7 +6023,7 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
         If INNER is not a MEM, get a piece consisting of just the field
         of interest (in this case POS % BITS_PER_WORD must be 0).  */
 
-      if (GET_CODE (inner) == MEM)
+      if (MEM_P (inner))
        {
          HOST_WIDE_INT offset;
 
@@ -6015,7 +6035,7 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
 
          new = adjust_address_nv (inner, tmode, offset);
        }
-      else if (GET_CODE (inner) == REG)
+      else if (REG_P (inner))
        {
          if (tmode != inner_mode)
            {
@@ -6040,7 +6060,7 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
 
                  /* Avoid creating invalid subregs, for example when
                     simplifying (x>>32)&255.  */
-                 if (final_word >= GET_MODE_SIZE (inner_mode))
+                 if (!validate_subreg (tmode, inner_mode, inner, final_word))
                    return NULL_RTX;
 
                  new = gen_rtx_SUBREG (tmode, inner, final_word);
@@ -6056,13 +6076,13 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
                             len >= HOST_BITS_PER_WIDE_INT
                             ? ~(unsigned HOST_WIDE_INT) 0
                             : ((unsigned HOST_WIDE_INT) 1 << len) - 1,
-                            NULL_RTX, 0);
+                            0);
 
       /* If this extraction is going into the destination of a SET,
         make a STRICT_LOW_PART unless we made a MEM.  */
 
       if (in_dest)
-       return (GET_CODE (new) == MEM ? new
+       return (MEM_P (new) ? new
                : (GET_CODE (new) != SUBREG
                   ? gen_rtx_CLOBBER (tmode, const0_rtx)
                   : gen_rtx_STRICT_LOW_PART (VOIDmode, new)));
@@ -6105,15 +6125,14 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
      don't do anything with zero-extending field extracts starting at
      the low-order bit since they are simple AND operations.  */
   if (pos_rtx == 0 && pos == 0 && ! in_dest
-      && ! in_compare && ! spans_byte && unsignedp)
+      && ! in_compare && unsignedp)
     return 0;
 
-  /* Unless we are allowed to span bytes or INNER is not MEM, reject this if
-     we would be spanning bytes or if the position is not a constant and the
-     length is not 1.  In all other cases, we would only be going outside
-     our object in cases when an original shift would have been
-     undefined.  */
-  if (! spans_byte && GET_CODE (inner) == MEM
+  /* Unless INNER is not MEM, reject this if we would be spanning bytes or
+     if the position is not a constant and the length is not 1.  In all
+     other cases, we would only be going outside our object in cases when
+     an original shift would have been undefined.  */
+  if (MEM_P (inner)
       && ((pos_rtx == 0 && pos + len > GET_MODE_BITSIZE (is_mode))
          || (pos_rtx != 0 && len != 1)))
     return 0;
@@ -6153,15 +6172,31 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
       && GET_MODE_SIZE (pos_mode) < GET_MODE_SIZE (GET_MODE (pos_rtx)))
     pos_mode = GET_MODE (pos_rtx);
 
-  /* If this is not from memory, the desired mode is wanted_inner_reg_mode;
-     if we have to change the mode of memory and cannot, the desired mode is
-     EXTRACTION_MODE.  */
-  if (GET_CODE (inner) != MEM)
+  /* If this is not from memory, the desired mode is the preferred mode
+     for an extraction pattern's first input operand, or word_mode if there
+     is none.  */
+  if (!MEM_P (inner))
     wanted_inner_mode = wanted_inner_reg_mode;
-  else if (inner_mode != wanted_inner_mode
-          && (mode_dependent_address_p (XEXP (inner, 0))
-              || MEM_VOLATILE_P (inner)))
-    wanted_inner_mode = extraction_mode;
+  else
+    {
+      /* Be careful not to go beyond the extracted object and maintain the
+        natural alignment of the memory.  */
+      wanted_inner_mode = smallest_mode_for_size (len, MODE_INT);
+      while (pos % GET_MODE_BITSIZE (wanted_inner_mode) + len
+            > GET_MODE_BITSIZE (wanted_inner_mode))
+       {
+         wanted_inner_mode = GET_MODE_WIDER_MODE (wanted_inner_mode);
+         gcc_assert (wanted_inner_mode != VOIDmode);
+       }
+
+      /* If we have to change the mode of memory and cannot, the desired mode
+        is EXTRACTION_MODE.  */
+      if (inner_mode != wanted_inner_mode
+         && (mode_dependent_address_p (XEXP (inner, 0))
+             || MEM_VOLATILE_P (inner)
+             || pos_rtx))
+       wanted_inner_mode = extraction_mode;
+    }
 
   orig_pos = pos;
 
@@ -6174,7 +6209,7 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
         If it's a MEM we need to recompute POS relative to that.
         However, if we're extracting from (or inserting into) a register,
         we want to recompute POS relative to wanted_inner_mode.  */
-      int width = (GET_CODE (inner) == MEM
+      int width = (MEM_P (inner)
                   ? GET_MODE_BITSIZE (is_mode)
                   : GET_MODE_BITSIZE (wanted_inner_mode));
 
@@ -6184,18 +6219,19 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
        pos_rtx
          = gen_rtx_MINUS (GET_MODE (pos_rtx), GEN_INT (width - len), pos_rtx);
       /* POS may be less than 0 now, but we check for that below.
-        Note that it can only be less than 0 if GET_CODE (inner) != MEM.  */
+        Note that it can only be less than 0 if !MEM_P (inner).  */
     }
 
-  /* If INNER has a wider mode, make it smaller.  If this is a constant
-     extract, try to adjust the byte to point to the byte containing
+  /* If INNER has a wider mode, and this is a constant extraction, try to
+     make it smaller and adjust the byte to point to the byte containing
      the value.  */
   if (wanted_inner_mode != VOIDmode
+      && inner_mode != wanted_inner_mode
+      && ! pos_rtx
       && GET_MODE_SIZE (wanted_inner_mode) < GET_MODE_SIZE (is_mode)
-      && ((GET_CODE (inner) == MEM
-          && (inner_mode == wanted_inner_mode
-              || (! mode_dependent_address_p (XEXP (inner, 0))
-                  && ! MEM_VOLATILE_P (inner))))))
+      && MEM_P (inner)
+      && ! mode_dependent_address_p (XEXP (inner, 0))
+      && ! MEM_VOLATILE_P (inner))
     {
       int offset = 0;
 
@@ -6206,44 +6242,42 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
       /* If bytes are big endian and we had a paradoxical SUBREG, we must
         adjust OFFSET to compensate.  */
       if (BYTES_BIG_ENDIAN
-         && ! spans_byte
          && GET_MODE_SIZE (inner_mode) < GET_MODE_SIZE (is_mode))
        offset -= GET_MODE_SIZE (is_mode) - GET_MODE_SIZE (inner_mode);
 
-      /* If this is a constant position, we can move to the desired byte.  */
-      if (pos_rtx == 0)
-       {
-         offset += pos / BITS_PER_UNIT;
-         pos %= GET_MODE_BITSIZE (wanted_inner_mode);
-       }
+      /* We can now move to the desired byte.  */
+      offset += (pos / GET_MODE_BITSIZE (wanted_inner_mode))
+               * GET_MODE_SIZE (wanted_inner_mode);
+      pos %= GET_MODE_BITSIZE (wanted_inner_mode);
 
       if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN
-         && ! spans_byte
          && is_mode != wanted_inner_mode)
        offset = (GET_MODE_SIZE (is_mode)
                  - GET_MODE_SIZE (wanted_inner_mode) - offset);
 
-      if (offset != 0 || inner_mode != wanted_inner_mode)
-       inner = adjust_address_nv (inner, wanted_inner_mode, offset);
+      inner = adjust_address_nv (inner, wanted_inner_mode, offset);
     }
 
   /* If INNER is not memory, we can always get it into the proper mode.  If we
      are changing its mode, POS must be a constant and smaller than the size
      of the new mode.  */
-  else if (GET_CODE (inner) != MEM)
+  else if (!MEM_P (inner))
     {
       if (GET_MODE (inner) != wanted_inner_mode
          && (pos_rtx != 0
              || orig_pos + len > GET_MODE_BITSIZE (wanted_inner_mode)))
        return 0;
 
+      if (orig_pos < 0)
+       return 0;
+
       inner = force_to_mode (inner, wanted_inner_mode,
                             pos_rtx
                             || len + orig_pos >= HOST_BITS_PER_WIDE_INT
                             ? ~(unsigned HOST_WIDE_INT) 0
                             : ((((unsigned HOST_WIDE_INT) 1 << len) - 1)
                                << orig_pos),
-                            NULL_RTX, 0);
+                            0);
     }
 
   /* Adjust mode of POS_RTX, if needed.  If we want a wider mode, we
@@ -6562,41 +6596,33 @@ make_compound_operation (rtx x, enum rtx_code in_code)
         what it originally did, do this SUBREG as a force_to_mode.  */
 
       tem = make_compound_operation (SUBREG_REG (x), in_code);
-      if (GET_CODE (tem) != GET_CODE (SUBREG_REG (x))
-         && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (tem))
-         && subreg_lowpart_p (x))
-       {
-         rtx newer = force_to_mode (tem, mode, ~(HOST_WIDE_INT) 0,
-                                    NULL_RTX, 0);
 
-         /* If we have something other than a SUBREG, we might have
-            done an expansion, so rerun ourselves.  */
-         if (GET_CODE (newer) != SUBREG)
-           newer = make_compound_operation (newer, in_code);
+      {
+       rtx simplified;
+       simplified = simplify_subreg (GET_MODE (x), tem, GET_MODE (tem),
+                                     SUBREG_BYTE (x));
 
-         return newer;
-       }
+       if (simplified)
+         tem = simplified;
 
-      /* If this is a paradoxical subreg, and the new code is a sign or
-        zero extension, omit the subreg and widen the extension.  If it
-        is a regular subreg, we can still get rid of the subreg by not
-        widening so much, or in fact removing the extension entirely.  */
-      if ((GET_CODE (tem) == SIGN_EXTEND
-          || GET_CODE (tem) == ZERO_EXTEND)
-         && subreg_lowpart_p (x))
-       {
-         if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (tem))
-             || (GET_MODE_SIZE (mode) >
-                 GET_MODE_SIZE (GET_MODE (XEXP (tem, 0)))))
-           {
-             if (! SCALAR_INT_MODE_P (mode))
-               break;
-             tem = gen_rtx_fmt_e (GET_CODE (tem), mode, XEXP (tem, 0));
-           }
-         else
-           tem = gen_lowpart (mode, XEXP (tem, 0));
+       if (GET_CODE (tem) != GET_CODE (SUBREG_REG (x))
+           && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (tem))
+           && subreg_lowpart_p (x))
+         {
+           rtx newer = force_to_mode (tem, mode, ~(HOST_WIDE_INT) 0,
+                                      0);
+
+           /* If we have something other than a SUBREG, we might have
+              done an expansion, so rerun ourselves.  */
+           if (GET_CODE (newer) != SUBREG)
+             newer = make_compound_operation (newer, in_code);
+
+           return newer;
+         }
+
+       if (simplified)
          return tem;
-       }
+      }
       break;
 
     default:
@@ -6618,6 +6644,16 @@ make_compound_operation (rtx x, enum rtx_code in_code)
        SUBST (XEXP (x, i), new);
       }
 
+  /* If this is a commutative operation, the changes to the operands
+     may have made it noncanonical.  */
+  if (COMMUTATIVE_ARITH_P (x)
+      && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
+    {
+      tem = XEXP (x, 0);
+      SUBST (XEXP (x, 0), XEXP (x, 1));
+      SUBST (XEXP (x, 1), tem);
+    }
+
   return x;
 }
 \f
@@ -6647,6 +6683,121 @@ get_pos_from_mask (unsigned HOST_WIDE_INT m, unsigned HOST_WIDE_INT *plen)
   return pos;
 }
 \f
+/* If X refers to a register that equals REG in value, replace these
+   references with REG.  */
+static rtx
+canon_reg_for_combine (rtx x, rtx reg)
+{
+  rtx op0, op1, op2;
+  const char *fmt;
+  int i;
+  bool copied;
+
+  enum rtx_code code = GET_CODE (x);
+  switch (GET_RTX_CLASS (code))
+    {
+    case RTX_UNARY:
+      op0 = canon_reg_for_combine (XEXP (x, 0), reg);
+      if (op0 != XEXP (x, 0))
+       return simplify_gen_unary (GET_CODE (x), GET_MODE (x), op0,
+                                  GET_MODE (reg));
+      break;
+
+    case RTX_BIN_ARITH:
+    case RTX_COMM_ARITH:
+      op0 = canon_reg_for_combine (XEXP (x, 0), reg);
+      op1 = canon_reg_for_combine (XEXP (x, 1), reg);
+      if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
+       return simplify_gen_binary (GET_CODE (x), GET_MODE (x), op0, op1);
+      break;
+
+    case RTX_COMPARE:
+    case RTX_COMM_COMPARE:
+      op0 = canon_reg_for_combine (XEXP (x, 0), reg);
+      op1 = canon_reg_for_combine (XEXP (x, 1), reg);
+      if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
+       return simplify_gen_relational (GET_CODE (x), GET_MODE (x),
+                                       GET_MODE (op0), op0, op1);
+      break;
+
+    case RTX_TERNARY:
+    case RTX_BITFIELD_OPS:
+      op0 = canon_reg_for_combine (XEXP (x, 0), reg);
+      op1 = canon_reg_for_combine (XEXP (x, 1), reg);
+      op2 = canon_reg_for_combine (XEXP (x, 2), reg);
+      if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1) || op2 != XEXP (x, 2))
+       return simplify_gen_ternary (GET_CODE (x), GET_MODE (x),
+                                    GET_MODE (op0), op0, op1, op2);
+
+    case RTX_OBJ:
+      if (REG_P (x))
+       {
+         if (rtx_equal_p (get_last_value (reg), x)
+             || rtx_equal_p (reg, get_last_value (x)))
+           return reg;
+         else
+           break;
+       }
+
+      /* fall through */
+
+    default:
+      fmt = GET_RTX_FORMAT (code);
+      copied = false;
+      for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+       if (fmt[i] == 'e')
+         {
+           rtx op = canon_reg_for_combine (XEXP (x, i), reg);
+           if (op != XEXP (x, i))
+             {
+               if (!copied)
+                 {
+                   copied = true;
+                   x = copy_rtx (x);
+                 }
+               XEXP (x, i) = op;
+             }
+         }
+       else if (fmt[i] == 'E')
+         {
+           int j;
+           for (j = 0; j < XVECLEN (x, i); j++)
+             {
+               rtx op = canon_reg_for_combine (XVECEXP (x, i, j), reg);
+               if (op != XVECEXP (x, i, j))
+                 {
+                   if (!copied)
+                     {
+                       copied = true;
+                       x = copy_rtx (x);
+                     }
+                   XVECEXP (x, i, j) = op;
+                 }
+             }
+         }
+
+      break;
+    }
+
+  return x;
+}
+
+/* Return X converted to MODE.  If the value is already truncated to
+   MODE we can just return a subreg even though in the general case we
+   would need an explicit truncation.  */
+
+static rtx
+gen_lowpart_or_truncate (enum machine_mode mode, rtx x)
+{
+  if (GET_MODE_SIZE (GET_MODE (x)) <= GET_MODE_SIZE (mode)
+      || TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+                               GET_MODE_BITSIZE (GET_MODE (x)))
+      || (REG_P (x) && reg_truncated_to_mode (mode, x)))
+    return gen_lowpart (mode, x);
+  else
+    return simplify_gen_unary (TRUNCATE, mode, x, GET_MODE (x));
+}
+
 /* See if X can be simplified knowing that we will only refer to it in
    MODE and will only refer to those bits that are nonzero in MASK.
    If other bits are being computed or if masking operations are done
@@ -6656,16 +6807,13 @@ get_pos_from_mask (unsigned HOST_WIDE_INT m, unsigned HOST_WIDE_INT *plen)
    Return a possibly simplified expression, but always convert X to
    MODE.  If X is a CONST_INT, AND the CONST_INT with MASK.
 
-   Also, if REG is nonzero and X is a register equal in value to REG,
-   replace X with REG.
-
    If JUST_SELECT is nonzero, don't optimize by noticing that bits in MASK
    are all off in X.  This is used when X will be complemented, by either
    NOT, NEG, or XOR.  */
 
 static rtx
 force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
-              rtx reg, int just_select)
+              int just_select)
 {
   enum rtx_code code = GET_CODE (x);
   int next_select = just_select || code == XOR || code == NOT || code == NEG;
@@ -6712,7 +6860,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
   nonzero = nonzero_bits (x, mode);
 
   /* If none of the bits in X are needed, return a zero.  */
-  if (! just_select && (nonzero & mask) == 0)
+  if (!just_select && (nonzero & mask) == 0 && !side_effects_p (x))
     x = const0_rtx;
 
   /* If X is a CONST_INT, return a new one.  Do this here since the
@@ -6720,7 +6868,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
   if (GET_CODE (x) == CONST_INT)
     {
       if (SCALAR_INT_MODE_P (mode))
-        return gen_int_mode (INTVAL (x) & mask, mode);
+       return gen_int_mode (INTVAL (x) & mask, mode);
       else
        {
          x = GEN_INT (INTVAL (x) & mask);
@@ -6734,11 +6882,6 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       && (GET_MODE_MASK (GET_MODE (x)) & ~mask) == 0)
     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.  */
-  if (GET_MODE (x) == mode && code != SUBREG && (~mask & nonzero) == 0)
-    return x;
-
   switch (code)
     {
     case CLOBBER:
@@ -6746,28 +6889,13 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
         generating something that won't match.  */
       return x;
 
-    case USE:
-      /* X is a (use (mem ..)) that was made from a bit-field extraction that
-        spanned the boundary of the MEM.  If we are now masking so it is
-        within that boundary, we don't need the USE any more.  */
-      if (! BITS_BIG_ENDIAN
-         && (mask & ~GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
-       return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
-      break;
-
     case SIGN_EXTEND:
     case ZERO_EXTEND:
     case ZERO_EXTRACT:
     case SIGN_EXTRACT:
       x = expand_compound_operation (x);
       if (GET_CODE (x) != code)
-       return force_to_mode (x, mode, mask, reg, next_select);
-      break;
-
-    case REG:
-      if (reg != 0 && (rtx_equal_p (get_last_value (reg), x)
-                      || rtx_equal_p (reg, get_last_value (x))))
-       x = reg;
+       return force_to_mode (x, mode, mask, next_select);
       break;
 
     case SUBREG:
@@ -6780,7 +6908,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
              || (0 == (mask
                        & GET_MODE_MASK (GET_MODE (x))
                        & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))))))
-       return force_to_mode (SUBREG_REG (x), mode, mask, reg, next_select);
+       return force_to_mode (SUBREG_REG (x), mode, mask, next_select);
       break;
 
     case AND:
@@ -6856,7 +6984,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
            && (INTVAL (XEXP (x, 1)) & ~smask) != 0)
          return force_to_mode (plus_constant (XEXP (x, 0),
                                               (INTVAL (XEXP (x, 1)) & smask)),
-                               mode, smask, reg, next_select);
+                               mode, smask, next_select);
       }
 
       /* ... fall through ...  */
@@ -6878,7 +7006,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
        {
          x = simplify_gen_unary (NEG, GET_MODE (x), XEXP (x, 1),
                                  GET_MODE (x));
-         return force_to_mode (x, mode, mask, reg, next_select);
+         return force_to_mode (x, mode, mask, next_select);
        }
 
       /* Similarly, if C contains every bit in the fuller_mask, then we may
@@ -6889,7 +7017,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
        {
          x = simplify_gen_unary (NOT, GET_MODE (x),
                                  XEXP (x, 1), GET_MODE (x));
-         return force_to_mode (x, mode, mask, reg, next_select);
+         return force_to_mode (x, mode, mask, next_select);
        }
 
       mask = fuller_mask;
@@ -6919,19 +7047,19 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
                                      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);
+         return force_to_mode (x, mode, mask, next_select);
        }
 
     binop:
       /* For most binary operations, just propagate into the operation and
         change the mode if we have an operation of that mode.  */
 
-      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));
+      op0 = gen_lowpart_or_truncate (op_mode,
+                                    force_to_mode (XEXP (x, 0), mode, mask,
+                                                   next_select));
+      op1 = gen_lowpart_or_truncate (op_mode,
+                                    force_to_mode (XEXP (x, 1), mode, mask,
+                                       next_select));
 
       if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
        x = simplify_gen_binary (code, op_mode, op0, op1);
@@ -6963,9 +7091,9 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       else
        mask = fuller_mask;
 
-      op0 = gen_lowpart (op_mode,
-                        force_to_mode (XEXP (x, 0), op_mode,
-                                       mask, reg, next_select));
+      op0 = gen_lowpart_or_truncate (op_mode,
+                                    force_to_mode (XEXP (x, 0), op_mode,
+                                                   mask, next_select));
 
       if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
        x = simplify_gen_binary (code, op_mode, op0, XEXP (x, 1));
@@ -6988,12 +7116,11 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
 
          /* We can only change the mode of the shift if we can do arithmetic
             in the mode of the shift and INNER_MASK is no wider than the
-            width of OP_MODE.  */
-         if (GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT
-             || (inner_mask & ~GET_MODE_MASK (op_mode)) != 0)
+            width of X's mode.  */
+         if ((inner_mask & ~GET_MODE_MASK (GET_MODE (x))) != 0)
            op_mode = GET_MODE (x);
 
-         inner = force_to_mode (inner, op_mode, inner_mask, reg, next_select);
+         inner = force_to_mode (inner, op_mode, inner_mask, next_select);
 
          if (GET_MODE (x) != op_mode || inner != XEXP (x, 0))
            x = simplify_gen_binary (LSHIFTRT, op_mode, inner, XEXP (x, 1));
@@ -7030,7 +7157,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       if (GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
          && (mask == ((unsigned HOST_WIDE_INT) 1
                       << (GET_MODE_BITSIZE (GET_MODE (x)) - 1))))
-       return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
+       return force_to_mode (XEXP (x, 0), mode, mask, next_select);
 
       /* If this is a shift by a constant, get a mask that contains those bits
         that are not copies of the sign bit.  We then have two cases:  If
@@ -7042,7 +7169,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0
          && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
        {
-         int i = -1;
+         int i;
 
          /* If the considered data is wider than HOST_WIDE_INT, we can't
             represent a mask for all its bits in a single scalar.
@@ -7069,16 +7196,22 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
              nonzero >>= INTVAL (XEXP (x, 1));
            }
 
-         if ((mask & ~nonzero) == 0
-             || (i = exact_log2 (mask)) >= 0)
+         if ((mask & ~nonzero) == 0)
+           {
+             x = simplify_shift_const (NULL_RTX, LSHIFTRT, GET_MODE (x),
+                                       XEXP (x, 0), INTVAL (XEXP (x, 1)));
+             if (GET_CODE (x) != ASHIFTRT)
+               return force_to_mode (x, mode, mask, next_select);
+           }
+
+         else if ((i = exact_log2 (mask)) >= 0)
            {
              x = simplify_shift_const
-               (x, LSHIFTRT, GET_MODE (x), XEXP (x, 0),
-                i < 0 ? INTVAL (XEXP (x, 1))
-                : GET_MODE_BITSIZE (GET_MODE (x)) - 1 - i);
+                 (NULL_RTX, LSHIFTRT, GET_MODE (x), XEXP (x, 0),
+                  GET_MODE_BITSIZE (GET_MODE (x)) - 1 - i);
 
              if (GET_CODE (x) != ASHIFTRT)
-               return force_to_mode (x, mode, mask, reg, next_select);
+               return force_to_mode (x, mode, mask, next_select);
            }
        }
 
@@ -7102,7 +7235,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
          && GET_CODE (XEXP (x, 0)) == ASHIFT
          && XEXP (XEXP (x, 0), 1) == XEXP (x, 1))
        return force_to_mode (XEXP (XEXP (x, 0), 0), mode, mask,
-                             reg, next_select);
+                             next_select);
 
       break;
 
@@ -7121,7 +7254,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
          if (temp && GET_CODE (temp) == CONST_INT)
            SUBST (XEXP (x, 0),
                   force_to_mode (XEXP (x, 0), GET_MODE (x),
-                                 INTVAL (temp), reg, next_select));
+                                 INTVAL (temp), next_select));
        }
       break;
 
@@ -7129,7 +7262,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       /* If we just want the low-order bit, the NEG isn't needed since it
         won't change the low-order bit.  */
       if (mask == 1)
-       return force_to_mode (XEXP (x, 0), mode, mask, reg, just_select);
+       return force_to_mode (XEXP (x, 0), mode, mask, just_select);
 
       /* We need any bits less significant than the most significant bit in
         MASK since carries from those bits will affect the bits we are
@@ -7156,7 +7289,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
          x = simplify_gen_binary (LSHIFTRT, GET_MODE (x),
                                   temp, XEXP (XEXP (x, 0), 1));
 
-         return force_to_mode (x, mode, mask, reg, next_select);
+         return force_to_mode (x, mode, mask, next_select);
        }
 
       /* (and (not FOO) CONST) is (not (or FOO (not CONST))), so we must
@@ -7164,9 +7297,9 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       mask = fuller_mask;
 
     unop:
-      op0 = gen_lowpart (op_mode,
-                        force_to_mode (XEXP (x, 0), mode, mask,
-                                       reg, next_select));
+      op0 = gen_lowpart_or_truncate (op_mode,
+                                    force_to_mode (XEXP (x, 0), mode, mask,
+                                                   next_select));
       if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
        x = simplify_gen_unary (code, op_mode, op0, op_mode);
       break;
@@ -7176,10 +7309,11 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
         in STORE_FLAG_VALUE and FOO has a single bit that might be nonzero,
         which is equal to STORE_FLAG_VALUE.  */
       if ((mask & ~STORE_FLAG_VALUE) == 0 && XEXP (x, 1) == const0_rtx
+         && GET_MODE (XEXP (x, 0)) == mode
          && exact_log2 (nonzero_bits (XEXP (x, 0), mode)) >= 0
          && (nonzero_bits (XEXP (x, 0), mode)
              == (unsigned HOST_WIDE_INT) STORE_FLAG_VALUE))
-       return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
+       return force_to_mode (XEXP (x, 0), mode, mask, next_select);
 
       break;
 
@@ -7188,13 +7322,13 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
         written in a narrower mode.  We play it safe and do not do so.  */
 
       SUBST (XEXP (x, 1),
-            gen_lowpart (GET_MODE (x),
+            gen_lowpart_or_truncate (GET_MODE (x),
                                      force_to_mode (XEXP (x, 1), mode,
-                                                    mask, reg, next_select)));
+                                                    mask, next_select)));
       SUBST (XEXP (x, 2),
-            gen_lowpart (GET_MODE (x),
+            gen_lowpart_or_truncate (GET_MODE (x),
                                      force_to_mode (XEXP (x, 2), mode,
-                                                    mask, reg, next_select)));
+                                                    mask, next_select)));
       break;
 
     default:
@@ -7202,7 +7336,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
     }
 
   /* Ensure we return a value of the proper mode.  */
-  return gen_lowpart (mode, x);
+  return gen_lowpart_or_truncate (mode, x);
 }
 \f
 /* Return nonzero if X is an expression that has one of two values depending on
@@ -7269,7 +7403,7 @@ if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
              *ptrue = simplify_gen_relational (code, mode, VOIDmode,
                                                true0, true1);
              *pfalse = simplify_gen_relational (code, mode, VOIDmode,
-                                                false0, false1);
+                                                false0, false1);
             }
          else
            {
@@ -7297,11 +7431,11 @@ if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
 
          if (COMPARISON_P (cond0)
              && COMPARISON_P (cond1)
-             && ((GET_CODE (cond0) == combine_reversed_comparison_code (cond1)
+             && ((GET_CODE (cond0) == reversed_comparison_code (cond1, NULL)
                   && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
                   && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
                  || ((swap_condition (GET_CODE (cond0))
-                      == combine_reversed_comparison_code (cond1))
+                      == reversed_comparison_code (cond1, NULL))
                      && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 1))
                      && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 0))))
              && ! side_effects_p (x))
@@ -7328,11 +7462,11 @@ if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
 
          if (COMPARISON_P (cond0)
              && COMPARISON_P (cond1)
-             && ((GET_CODE (cond0) == combine_reversed_comparison_code (cond1)
+             && ((GET_CODE (cond0) == reversed_comparison_code (cond1, NULL)
                   && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
                   && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
                  || ((swap_condition (GET_CODE (cond0))
-                      == combine_reversed_comparison_code (cond1))
+                      == reversed_comparison_code (cond1, NULL))
                      && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 1))
                      && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 0))))
              && ! side_effects_p (x))
@@ -7477,7 +7611,7 @@ known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val)
              if (comparison_dominates_p (cond, code))
                return const_true_rtx;
 
-             code = combine_reversed_comparison_code (x);
+             code = reversed_comparison_code (x, NULL);
              if (code != UNKNOWN
                  && comparison_dominates_p (cond, code))
                return const0_rtx;
@@ -7546,7 +7680,7 @@ known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val)
       if (XEXP (x, 0) != r)
        {
          /* We must simplify the zero_extend here, before we lose
-             track of the original inner_mode.  */
+            track of the original inner_mode.  */
          new = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
                                          r, inner_mode);
          if (new)
@@ -7587,14 +7721,14 @@ rtx_equal_for_field_assignment_p (rtx x, rtx y)
   /* Check for a paradoxical SUBREG of a MEM compared with the MEM.
      Note that all SUBREGs of MEM are paradoxical; otherwise they
      would have been rewritten.  */
-  if (GET_CODE (x) == MEM && GET_CODE (y) == SUBREG
-      && GET_CODE (SUBREG_REG (y)) == MEM
+  if (MEM_P (x) && GET_CODE (y) == SUBREG
+      && MEM_P (SUBREG_REG (y))
       && rtx_equal_p (SUBREG_REG (y),
                      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
+  if (MEM_P (y) && GET_CODE (x) == SUBREG
+      && MEM_P (SUBREG_REG (x))
       && rtx_equal_p (SUBREG_REG (x),
                      gen_lowpart (GET_MODE (SUBREG_REG (x)), y)))
     return 1;
@@ -7642,14 +7776,14 @@ make_field_assignment (rtx x)
       return x;
     }
 
-  else if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == SUBREG
-          && subreg_lowpart_p (XEXP (src, 0))
-          && (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)))
+  if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == SUBREG
+      && subreg_lowpart_p (XEXP (src, 0))
+      && (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)))
     {
       assign = make_extraction (VOIDmode, dest, 0,
                                XEXP (SUBREG_REG (XEXP (src, 0)), 1),
@@ -7661,9 +7795,9 @@ make_field_assignment (rtx x)
 
   /* If SRC is (ior (ashift (const_int 1) POS) DEST), this is a set of a
      one-bit field.  */
-  else if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 0)) == ASHIFT
-          && XEXP (XEXP (src, 0), 0) == const1_rtx
-          && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
+  if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 0)) == ASHIFT
+      && XEXP (XEXP (src, 0), 0) == const1_rtx
+      && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
     {
       assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1),
                                1, 1, 1, 0);
@@ -7672,6 +7806,37 @@ make_field_assignment (rtx x)
       return x;
     }
 
+  /* If DEST is already a field assignment, i.e. ZERO_EXTRACT, and the
+     SRC is an AND with all bits of that field set, then we can discard
+     the AND.  */
+  if (GET_CODE (dest) == ZERO_EXTRACT
+      && GET_CODE (XEXP (dest, 1)) == CONST_INT
+      && GET_CODE (src) == AND
+      && GET_CODE (XEXP (src, 1)) == CONST_INT)
+    {
+      HOST_WIDE_INT width = INTVAL (XEXP (dest, 1));
+      unsigned HOST_WIDE_INT and_mask = INTVAL (XEXP (src, 1));
+      unsigned HOST_WIDE_INT ze_mask;
+
+      if (width >= HOST_BITS_PER_WIDE_INT)
+       ze_mask = -1;
+      else
+       ze_mask = ((unsigned HOST_WIDE_INT)1 << width) - 1;
+
+      /* Complete overlap.  We can remove the source AND.  */
+      if ((and_mask & ze_mask) == ze_mask)
+       return gen_rtx_SET (VOIDmode, dest, XEXP (src, 0));
+
+      /* Partial overlap.  We can reduce the source AND.  */
+      if ((and_mask & ze_mask) != and_mask)
+       {
+         mode = GET_MODE (src);
+         src = gen_rtx_AND (mode, XEXP (src, 0),
+                            gen_int_mode (and_mask & ze_mask, mode));
+         return gen_rtx_SET (VOIDmode, dest, src);
+       }
+    }
+
   /* The other case we handle is assignments into a constant-position
      field.  They look like (ior/xor (and DEST C1) OTHER).  If C1 represents
      a mask that has all one bits except for a group of zero bits and
@@ -7715,13 +7880,15 @@ make_field_assignment (rtx x)
   /* Shift OTHER right POS places and make it the source, restricting it
      to the proper length and mode.  */
 
-  src = force_to_mode (simplify_shift_const (NULL_RTX, LSHIFTRT,
-                                            GET_MODE (src), other, pos),
-                      mode,
+  src = canon_reg_for_combine (simplify_shift_const (NULL_RTX, LSHIFTRT,
+                                                    GET_MODE (src),
+                                                    other, pos),
+                              dest);
+  src = force_to_mode (src, mode,
                       GET_MODE_BITSIZE (mode) >= HOST_BITS_PER_WIDE_INT
                       ? ~(unsigned HOST_WIDE_INT) 0
                       : ((unsigned HOST_WIDE_INT) 1 << len) - 1,
-                      dest, 0);
+                      0);
 
   /* If SRC is masked by an AND that does not make a difference in
      the value being stored, strip it.  */
@@ -7795,14 +7962,15 @@ apply_distributive_law (rtx x)
       break;
 
     case SUBREG:
-      /* Non-paradoxical SUBREGs distributes over all operations, provided
-        the inner modes and byte offsets are the same, this is an extraction
-        of a low-order part, we don't convert an fp operation to int or
-        vice versa, and we would not be converting a single-word
-        operation into a multi-word operation.  The latter test is not
-        required, but it prevents generating unneeded multi-word operations.
-        Some of the previous tests are redundant given the latter test, but
-        are retained because they are required for correctness.
+      /* Non-paradoxical SUBREGs distributes over all operations,
+        provided the inner modes and byte offsets are the same, this
+        is an extraction of a low-order part, we don't convert an fp
+        operation to int or vice versa, this is not a vector mode,
+        and we would not be converting a single-word operation into a
+        multi-word operation.  The latter test is not required, but
+        it prevents generating unneeded multi-word operations.  Some
+        of the previous tests are redundant given the latter test,
+        but are retained because they are required for correctness.
 
         We produce the result slightly differently in this case.  */
 
@@ -7813,7 +7981,13 @@ apply_distributive_law (rtx x)
              != GET_MODE_CLASS (GET_MODE (SUBREG_REG (lhs))))
          || (GET_MODE_SIZE (GET_MODE (lhs))
              > GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs))))
-         || GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs))) > UNITS_PER_WORD)
+         || VECTOR_MODE_P (GET_MODE (lhs))
+         || GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs))) > UNITS_PER_WORD
+         /* Result might need to be truncated.  Don't change mode if
+            explicit truncation is needed.  */
+         || !TRULY_NOOP_TRUNCATION
+              (GET_MODE_BITSIZE (GET_MODE (x)),
+               GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (lhs)))))
        return x;
 
       tem = simplify_gen_binary (code, GET_MODE (SUBREG_REG (lhs)),
@@ -7860,8 +8034,8 @@ apply_distributive_law (rtx 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.
+/* 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
@@ -7871,95 +8045,81 @@ apply_distributive_law (rtx x)
    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.  */
+   few places where this routine is called.
+
+   N is the index of the term that is decomposed (the arithmetic operation,
+   i.e. (+ A B) in the first example above).  !N is the index of the term that
+   is distributed, i.e. of C in the first example above.  */
 static rtx
-distribute_and_simplify_rtx (rtx x)
+distribute_and_simplify_rtx (rtx x, int n)
 {
   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));
+  enum rtx_code outer_code, inner_code;
+  rtx decomposed, distributed, inner_op0, inner_op1, new_op0, new_op1, tmp;
 
-         if (GET_CODE (x) != outer)
-           return x;
-       }
-    }
+  decomposed = XEXP (x, n);
+  if (!ARITHMETIC_P (decomposed))
+    return NULL_RTX;
 
-  if (ARITHMETIC_P (op1))
-    {
-      inner = GET_CODE (op1);
-      inner_op0 = XEXP (op1, 0);
-      inner_op1 = XEXP (op1, 1);
+  mode = GET_MODE (x);
+  outer_code = GET_CODE (x);
+  distributed = XEXP (x, !n);
 
-      /* (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));
+  inner_code = GET_CODE (decomposed);
+  inner_op0 = XEXP (decomposed, 0);
+  inner_op1 = XEXP (decomposed, 1);
 
-         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));
+  /* Special case (and (xor B C) (not A)), which is equivalent to
+     (xor (ior A B) (ior A C))  */
+  if (outer_code == AND && inner_code == XOR && GET_CODE (distributed) == NOT)
+    {
+      distributed = XEXP (distributed, 0);
+      outer_code = IOR;
+    }
 
-         if (GET_CODE (x) != outer)
-           return x;
-       }
+  if (n == 0)
+    {
+      /* Distribute the second term.  */
+      new_op0 = simplify_gen_binary (outer_code, mode, inner_op0, distributed);
+      new_op1 = simplify_gen_binary (outer_code, mode, inner_op1, distributed);
+    }
+  else
+    {
+      /* Distribute the first term.  */
+      new_op0 = simplify_gen_binary (outer_code, mode, distributed, inner_op0);
+      new_op1 = simplify_gen_binary (outer_code, mode, distributed, inner_op1);
     }
 
+  tmp = apply_distributive_law (simplify_gen_binary (inner_code, mode,
+                                                    new_op0, new_op1));
+  if (GET_CODE (tmp) != outer_code
+      && rtx_cost (tmp, SET) < rtx_cost (x, SET))
+    return tmp;
+
   return NULL_RTX;
 }
 \f
-/* We have X, a logical `and' of VAROP with the constant CONSTOP, to be done
-   in MODE.
-
-   Return an equivalent form, if different from X.  Otherwise, return X.  If
-   X is zero, we are to always construct the equivalent form.  */
+/* Simplify a logical `and' of VAROP with the constant CONSTOP, to be done
+   in MODE.  Return an equivalent form, if different from (and VAROP
+   (const_int CONSTOP)).  Otherwise, return NULL_RTX.  */
 
 static rtx
-simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
-                       unsigned HOST_WIDE_INT constop)
+simplify_and_const_int_1 (enum machine_mode mode, rtx varop,
+                         unsigned HOST_WIDE_INT constop)
 {
   unsigned HOST_WIDE_INT nonzero;
+  unsigned HOST_WIDE_INT orig_constop;
+  rtx orig_varop;
   int i;
 
+  orig_varop = varop;
+  orig_constop = constop;
+  if (GET_CODE (varop) == CLOBBER)
+    return NULL_RTX;
+
   /* Simplify VAROP knowing that we will be only looking at some of the
      bits in it.
 
@@ -7967,7 +8127,7 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
      CONSTOP are not significant and will never be examined.  We must
      ensure that is the case by explicitly masking out those bits
      before returning.  */
-  varop = force_to_mode (varop, mode, constop, NULL_RTX, 0);
+  varop = force_to_mode (varop, mode, constop, 0);
 
   /* If VAROP is a CLOBBER, we will fail so return it.  */
   if (GET_CODE (varop) == CLOBBER)
@@ -7976,7 +8136,7 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
   /* If VAROP is a CONST_INT, then we need to apply the mask in CONSTOP
      to VAROP and return the new constant.  */
   if (GET_CODE (varop) == CONST_INT)
-    return GEN_INT (trunc_int_for_mode (INTVAL (varop) & constop, mode));
+    return gen_int_mode (INTVAL (varop) & constop, mode);
 
   /* See what bits may be nonzero in VAROP.  Unlike the general case of
      a call to nonzero_bits, here we don't care about bits outside
@@ -8021,7 +8181,7 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
                                                       XEXP (varop, 1),
                                                       constop))));
 
-  /* If VAROP is PLUS, and the constant is a mask of low bite, distribute
+  /* If VAROP is PLUS, and the constant is a mask of low bits, distribute
      the AND and see if one of the operands simplifies to zero.  If so, we
      may eliminate it.  */
 
@@ -8038,40 +8198,42 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
        return o0;
     }
 
-  /* Get VAROP in MODE.  Try to get a SUBREG if not.  Don't make a new SUBREG
-     if we already had one (just check for the simplest cases).  */
-  if (x && GET_CODE (XEXP (x, 0)) == SUBREG
-      && GET_MODE (XEXP (x, 0)) == mode
-      && SUBREG_REG (XEXP (x, 0)) == varop)
-    varop = XEXP (x, 0);
-  else
-    varop = gen_lowpart (mode, varop);
-
-  /* If we can't make the SUBREG, try to return what we were given.  */
-  if (GET_CODE (varop) == CLOBBER)
-    return x ? x : varop;
+  /* Make a SUBREG if necessary.  If we can't make it, fail.  */
+  varop = gen_lowpart (mode, varop);
+  if (varop == NULL_RTX || GET_CODE (varop) == CLOBBER)
+    return NULL_RTX;
 
   /* If we are only masking insignificant bits, return VAROP.  */
   if (constop == nonzero)
-    x = varop;
-  else
-    {
-      /* Otherwise, return an AND.  */
-      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 = simplify_gen_binary (AND, mode, varop, GEN_INT (constop));
+    return varop;
 
-      else
-       {
-         if (GET_CODE (XEXP (x, 1)) != CONST_INT
-             || (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) != constop)
-           SUBST (XEXP (x, 1), GEN_INT (constop));
+  if (varop == orig_varop && constop == orig_constop)
+    return NULL_RTX;
 
-         SUBST (XEXP (x, 0), varop);
-       }
-    }
+  /* Otherwise, return an AND.  */
+  return simplify_gen_binary (AND, mode, varop, gen_int_mode (constop, mode));
+}
+
+
+/* We have X, a logical `and' of VAROP with the constant CONSTOP, to be done
+   in MODE.
+
+   Return an equivalent form, if different from X.  Otherwise, return X.  If
+   X is zero, we are to always construct the equivalent form.  */
+
+static rtx
+simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
+                       unsigned HOST_WIDE_INT constop)
+{
+  rtx tem = simplify_and_const_int_1 (mode, varop, constop);
+  if (tem)
+    return tem;
 
+  if (!x)
+    x = simplify_gen_binary (AND, GET_MODE (varop), varop,
+                            gen_int_mode (constop, mode));
+  if (GET_MODE (x) != mode)
+    x = gen_lowpart (mode, x);
   return x;
 }
 \f
@@ -8097,13 +8259,14 @@ reg_nonzero_bits_for_combine (rtx x, enum machine_mode mode,
 
   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 (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))))
+             && ! REGNO_REG_SET_P
+                (ENTRY_BLOCK_PTR->next_bb->il.rtl->global_live_at_start,
+                 REGNO (x))))
       && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid)
     {
       *nonzero &= reg_stat[REGNO (x)].last_set_nonzero_bits;
@@ -8116,13 +8279,13 @@ reg_nonzero_bits_for_combine (rtx x, enum machine_mode mode,
     {
 #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.
+        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.  */
+        ??? 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
@@ -8141,8 +8304,8 @@ reg_nonzero_bits_for_combine (rtx x, enum machine_mode mode,
       unsigned HOST_WIDE_INT mask = reg_stat[REGNO (x)].nonzero_bits;
 
       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));
+       /* We don't know anything about the upper bits.  */
+       mask |= GET_MODE_MASK (mode) ^ GET_MODE_MASK (GET_MODE (x));
       *nonzero &= mask;
     }
 
@@ -8167,10 +8330,11 @@ reg_num_sign_bit_copies_for_combine (rtx x, enum machine_mode mode,
   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
+         || (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))))
+             && ! REGNO_REG_SET_P
+                (ENTRY_BLOCK_PTR->next_bb->il.rtl->global_live_at_start,
+                 REGNO (x))))
       && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid)
     {
       *result = reg_stat[REGNO (x)].last_set_sign_bit_copies;
@@ -8184,7 +8348,7 @@ reg_num_sign_bit_copies_for_combine (rtx x, enum machine_mode mode,
   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
@@ -8227,7 +8391,7 @@ extended_count (rtx x, enum machine_mode mode, int unsignedp)
    the width of this mode matter.  It is assumed that the width of this mode
    is smaller than or equal to HOST_BITS_PER_WIDE_INT.
 
-   If *POP0 or OP1 are NIL, it means no operation is required.  Only NEG, PLUS,
+   If *POP0 or OP1 are UNKNOWN, it means no operation is required.  Only NEG, PLUS,
    IOR, XOR, and AND are supported.  We may set *POP0 to SET if the proper
    result is simply *PCONST0.
 
@@ -8247,13 +8411,13 @@ merge_outer_ops (enum rtx_code *pop0, HOST_WIDE_INT *pconst0, enum rtx_code op1,
   if (op0 == AND)
     const1 &= const0;
 
-  /* If OP0 or OP1 is NIL, this is easy.  Similarly if they are the same or
+  /* If OP0 or OP1 is UNKNOWN, this is easy.  Similarly if they are the same or
      if OP0 is SET.  */
 
-  if (op1 == NIL || op0 == SET)
+  if (op1 == UNKNOWN || op0 == SET)
     return 1;
 
-  else if (op0 == NIL)
+  else if (op0 == UNKNOWN)
     op0 = op1, const0 = const1;
 
   else if (op0 == op1)
@@ -8273,7 +8437,7 @@ merge_outer_ops (enum rtx_code *pop0, HOST_WIDE_INT *pconst0, enum rtx_code op1,
          const0 += const1;
          break;
        case NEG:
-         op0 = NIL;
+         op0 = UNKNOWN;
          break;
        default:
          break;
@@ -8326,12 +8490,12 @@ merge_outer_ops (enum rtx_code *pop0, HOST_WIDE_INT *pconst0, enum rtx_code op1,
   const0 &= GET_MODE_MASK (mode);
   if (const0 == 0
       && (op0 == IOR || op0 == XOR || op0 == PLUS))
-    op0 = NIL;
+    op0 = UNKNOWN;
   else if (const0 == 0 && op0 == AND)
     op0 = SET;
   else if ((unsigned HOST_WIDE_INT) const0 == GET_MODE_MASK (mode)
           && op0 == AND)
-    op0 = NIL;
+    op0 = UNKNOWN;
 
   /* ??? Slightly redundant with the above mask, but not entirely.
      Moving this above means we'd have to sign-extend the mode mask
@@ -8345,31 +8509,29 @@ merge_outer_ops (enum rtx_code *pop0, HOST_WIDE_INT *pconst0, enum rtx_code op1,
 }
 \f
 /* Simplify a shift of VAROP by COUNT bits.  CODE says what kind of shift.
-   The result of the shift is RESULT_MODE.  X, if nonzero, is an expression
-   that we started with.
+   The result of the shift is RESULT_MODE.  Return NULL_RTX if we cannot
+   simplify it.  Otherwise, return a simplified value.
 
    The shift is normally computed in the widest mode we find in VAROP, as
    long as it isn't a different number of words than RESULT_MODE.  Exceptions
-   are ASHIFTRT and ROTATE, which are always done in their original mode,  */
+   are ASHIFTRT and ROTATE, which are always done in their original mode.  */
 
 static rtx
-simplify_shift_const (rtx x, enum rtx_code code,
-                     enum machine_mode result_mode, rtx varop,
-                     int orig_count)
+simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
+                       rtx varop, int orig_count)
 {
   enum rtx_code orig_code = code;
-  unsigned int count;
-  int signed_count;
+  rtx orig_varop = varop;
+  int count;
   enum machine_mode mode = result_mode;
   enum machine_mode shift_mode, tmode;
   unsigned int mode_words
     = (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
   /* We form (outer_op (code varop count) (outer_const)).  */
-  enum rtx_code outer_op = NIL;
+  enum rtx_code outer_op = UNKNOWN;
   HOST_WIDE_INT outer_const = 0;
-  rtx const_rtx;
   int complement_p = 0;
-  rtx new;
+  rtx new, x;
 
   /* 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
@@ -8381,12 +8543,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
      what was requested.  */
 
   if (orig_count < 0 || orig_count >= (int) GET_MODE_BITSIZE (mode))
-    {
-      if (x)
-       return x;
-
-      return gen_rtx_fmt_ee (code, mode, varop, GEN_INT (orig_count));
-    }
+    return NULL_RTX;
 
   count = orig_count;
 
@@ -8395,10 +8552,9 @@ simplify_shift_const (rtx x, enum rtx_code code,
 
   while (count != 0)
     {
-      /* If we have an operand of (clobber (const_int 0)), just return that
-        value.  */
+      /* If we have an operand of (clobber (const_int 0)), fail.  */
       if (GET_CODE (varop) == CLOBBER)
-       return varop;
+       return NULL_RTX;
 
       /* If we discovered we had to complement VAROP, leave.  Making a NOT
         here would cause an infinite loop.  */
@@ -8434,7 +8590,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
         multiple operations, each of which are defined, we know what the
         result is supposed to be.  */
 
-      if (count > (unsigned int) (GET_MODE_BITSIZE (shift_mode) - 1))
+      if (count > (GET_MODE_BITSIZE (shift_mode) - 1))
        {
          if (code == ASHIFTRT)
            count = GET_MODE_BITSIZE (shift_mode) - 1;
@@ -8481,14 +8637,14 @@ simplify_shift_const (rtx x, enum rtx_code code,
              == 0))
        code = LSHIFTRT;
 
-      if (code == LSHIFTRT
-         && GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
-         && !(nonzero_bits (varop, shift_mode) >> count))
-       varop = const0_rtx;
-      if (code == ASHIFT
-         && GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
-         && !((nonzero_bits (varop, shift_mode) << count)
-              & GET_MODE_MASK (shift_mode)))
+      if (((code == LSHIFTRT
+           && GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
+           && !(nonzero_bits (varop, shift_mode) >> count))
+          || (code == ASHIFT
+              && GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
+              && !((nonzero_bits (varop, shift_mode) << count)
+                   & GET_MODE_MASK (shift_mode))))
+         && !side_effects_p (varop))
        varop = const0_rtx;
 
       switch (GET_CODE (varop))
@@ -8526,33 +8682,6 @@ simplify_shift_const (rtx x, enum rtx_code code,
            }
          break;
 
-       case USE:
-         /* Similar to the case above, except that we can only do this if
-            the resulting mode is the same as that of the underlying
-            MEM and adjust the address depending on the *bits* endianness
-            because of the way that bit-field extract insns are defined.  */
-         if ((code == ASHIFTRT || code == LSHIFTRT)
-             && (tmode = mode_for_size (GET_MODE_BITSIZE (mode) - count,
-                                        MODE_INT, 1)) != BLKmode
-             && tmode == GET_MODE (XEXP (varop, 0)))
-           {
-             if (BITS_BIG_ENDIAN)
-               new = XEXP (varop, 0);
-             else
-               {
-                 new = copy_rtx (XEXP (varop, 0));
-                 SUBST (XEXP (new, 0),
-                        plus_constant (XEXP (new, 0),
-                                       count / BITS_PER_UNIT));
-               }
-
-             varop = gen_rtx_fmt_e (code == ASHIFTRT ? SIGN_EXTEND
-                                    : ZERO_EXTEND, mode, new);
-             count = 0;
-             continue;
-           }
-         break;
-
        case SUBREG:
          /* If VAROP is a SUBREG, strip it as long as the inner operand has
             the same number of words as what we've seen so far.  Then store
@@ -8608,7 +8737,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
             interpreted as the sign bit in a narrower mode, so, if
             the result is narrower, don't discard the shift.  */
          if (code == LSHIFTRT
-             && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
+             && count == (GET_MODE_BITSIZE (result_mode) - 1)
              && (GET_MODE_BITSIZE (result_mode)
                  >= GET_MODE_BITSIZE (GET_MODE (varop))))
            {
@@ -8627,7 +8756,8 @@ simplify_shift_const (rtx x, enum rtx_code code,
              && INTVAL (XEXP (varop, 1)) >= 0
              && INTVAL (XEXP (varop, 1)) < GET_MODE_BITSIZE (GET_MODE (varop))
              && GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT
-             && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+             && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+             && !VECTOR_MODE_P (result_mode))
            {
              enum rtx_code first_code = GET_CODE (varop);
              unsigned int first_count = INTVAL (XEXP (varop, 1));
@@ -8642,8 +8772,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
                 (ashiftrt:M1 (ashift:M1 (and:M1 (subreg:M1 FOO 0 C2) C3) C1).
                 This simplifies certain SIGN_EXTEND operations.  */
              if (code == ASHIFT && first_code == ASHIFTRT
-                 && count == (unsigned int)
-                             (GET_MODE_BITSIZE (result_mode)
+                 && count == (GET_MODE_BITSIZE (result_mode)
                               - GET_MODE_BITSIZE (GET_MODE (varop))))
                {
                  /* C3 has the low-order C1 bits zero.  */
@@ -8673,12 +8802,12 @@ simplify_shift_const (rtx x, enum rtx_code code,
                      > first_count))
                {
                  varop = XEXP (varop, 0);
-
-                 signed_count = count - first_count;
-                 if (signed_count < 0)
-                   count = -signed_count, code = ASHIFT;
-                 else
-                   count = signed_count;
+                 count -= first_count;
+                 if (count < 0)
+                   {
+                     count = -count;
+                     code = ASHIFT;
+                   }
 
                  continue;
                }
@@ -8726,8 +8855,8 @@ simplify_shift_const (rtx x, enum rtx_code code,
              mask_rtx = GEN_INT (nonzero_bits (varop, GET_MODE (varop)));
 
              mask_rtx
-               = simplify_binary_operation (code, result_mode, mask_rtx,
-                                            GEN_INT (count));
+               = simplify_const_binary_operation (code, result_mode, mask_rtx,
+                                                  GEN_INT (count));
 
              /* Give up if we can't compute an outer operation to use.  */
              if (mask_rtx == 0
@@ -8739,25 +8868,22 @@ simplify_shift_const (rtx x, enum rtx_code code,
 
              /* If the shifts are in the same direction, we add the
                 counts.  Otherwise, we subtract them.  */
-             signed_count = count;
              if ((code == ASHIFTRT || code == LSHIFTRT)
                  == (first_code == ASHIFTRT || first_code == LSHIFTRT))
-               signed_count += first_count;
+               count += first_count;
              else
-               signed_count -= first_count;
+               count -= first_count;
 
              /* If COUNT is positive, the new shift is usually CODE,
                 except for the two exceptions below, in which case it is
                 FIRST_CODE.  If the count is negative, FIRST_CODE should
                 always be used  */
-             if (signed_count > 0
+             if (count > 0
                  && ((first_code == ROTATE && code == ASHIFT)
                      || (first_code == ASHIFTRT && code == LSHIFTRT)))
-               code = first_code, count = signed_count;
-             else if (signed_count < 0)
-               code = first_code, count = -signed_count;
-             else
-               count = signed_count;
+               code = first_code;
+             else if (count < 0)
+               code = first_code, count = -count;
 
              varop = XEXP (varop, 0);
              continue;
@@ -8768,12 +8894,12 @@ simplify_shift_const (rtx x, enum rtx_code code,
             B is not a constant.  */
 
          else if (GET_CODE (varop) == code
-                  && GET_CODE (XEXP (varop, 1)) != CONST_INT
-                  && 0 != (new
-                           = simplify_binary_operation (code, mode,
-                                                        XEXP (varop, 0),
-                                                        GEN_INT (count))))
+                  && GET_CODE (XEXP (varop, 0)) == CONST_INT
+                  && GET_CODE (XEXP (varop, 1)) != CONST_INT)
            {
+             rtx new = simplify_const_binary_operation (code, mode,
+                                                        XEXP (varop, 0),
+                                                        GEN_INT (count));
              varop = gen_rtx_fmt_ee (code, mode, new, XEXP (varop, 1));
              count = 0;
              continue;
@@ -8800,8 +8926,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
              && XEXP (XEXP (varop, 0), 1) == constm1_rtx
              && (STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
              && (code == LSHIFTRT || code == ASHIFTRT)
-             && count == (unsigned int)
-                         (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
+             && count == (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
              && rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
            {
              count = 0;
@@ -8826,9 +8951,9 @@ simplify_shift_const (rtx x, enum rtx_code code,
              && !(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
+             && (new = simplify_const_binary_operation (code, result_mode,
+                                                        XEXP (varop, 1),
+                                                        GEN_INT (count))) != 0
              && GET_CODE (new) == CONST_INT
              && merge_outer_ops (&outer_op, &outer_const, GET_CODE (varop),
                                  INTVAL (new), result_mode, &complement_p))
@@ -8841,9 +8966,10 @@ simplify_shift_const (rtx x, enum rtx_code code,
             logical expression, make a new logical expression, and apply
             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))
+         if (GET_CODE (XEXP (varop, 1)) == CONST_INT
+            && !(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);
@@ -8855,6 +8981,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
              varop = apply_distributive_law (varop);
 
              count = 0;
+             continue;
            }
          break;
 
@@ -8866,11 +8993,9 @@ simplify_shift_const (rtx x, enum rtx_code code,
          if (code == LSHIFTRT
              && XEXP (varop, 1) == const0_rtx
              && GET_MODE (XEXP (varop, 0)) == result_mode
-             && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
+             && count == (GET_MODE_BITSIZE (result_mode) - 1)
              && GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT
-             && ((STORE_FLAG_VALUE
-                  & ((HOST_WIDE_INT) 1
-                     < (GET_MODE_BITSIZE (result_mode) - 1))))
+             && STORE_FLAG_VALUE == -1
              && nonzero_bits (XEXP (varop, 0), result_mode) == 1
              && merge_outer_ops (&outer_op, &outer_const, XOR,
                                  (HOST_WIDE_INT) 1, result_mode,
@@ -8886,7 +9011,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
          /* (lshiftrt (neg A) C) where A is either 0 or 1 and C is one less
             than the number of bits in the mode is equivalent to A.  */
          if (code == LSHIFTRT
-             && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
+             && count == (GET_MODE_BITSIZE (result_mode) - 1)
              && nonzero_bits (XEXP (varop, 0), result_mode) == 1)
            {
              varop = XEXP (varop, 0);
@@ -8911,7 +9036,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
             is one less than the number of bits in the mode is
             equivalent to (xor A 1).  */
          if (code == LSHIFTRT
-             && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
+             && count == (GET_MODE_BITSIZE (result_mode) - 1)
              && XEXP (varop, 1) == constm1_rtx
              && nonzero_bits (XEXP (varop, 0), result_mode) == 1
              && merge_outer_ops (&outer_op, &outer_const, XOR,
@@ -8954,9 +9079,9 @@ simplify_shift_const (rtx x, enum rtx_code code,
          /* (ashift (plus foo C) N) is (plus (ashift foo N) C').  */
          if (code == ASHIFT
              && GET_CODE (XEXP (varop, 1)) == CONST_INT
-             && (new = simplify_binary_operation (ASHIFT, result_mode,
-                                                  XEXP (varop, 1),
-                                                  GEN_INT (count))) != 0
+             && (new = simplify_const_binary_operation (ASHIFT, result_mode,
+                                                        XEXP (varop, 1),
+                                                        GEN_INT (count))) != 0
              && GET_CODE (new) == CONST_INT
              && merge_outer_ops (&outer_op, &outer_const, PLUS,
                                  INTVAL (new), result_mode, &complement_p))
@@ -8964,6 +9089,26 @@ simplify_shift_const (rtx x, enum rtx_code code,
              varop = XEXP (varop, 0);
              continue;
            }
+
+         /* Check for 'PLUS signbit', which is the canonical form of 'XOR
+            signbit', and attempt to change the PLUS to an XOR and move it to
+            the outer operation as is done above in the AND/IOR/XOR case
+            leg for shift(logical). See details in logical handling above
+            for reasoning in doing so.  */
+         if (code == LSHIFTRT
+             && GET_CODE (XEXP (varop, 1)) == CONST_INT
+             && mode_signbit_p (result_mode, XEXP (varop, 1))
+             && (new = simplify_const_binary_operation (code, result_mode,
+                                                        XEXP (varop, 1),
+                                                        GEN_INT (count))) != 0
+             && GET_CODE (new) == CONST_INT
+             && merge_outer_ops (&outer_op, &outer_const, XOR,
+                                 INTVAL (new), result_mode, &complement_p))
+           {
+             varop = XEXP (varop, 0);
+             continue;
+           }
+
          break;
 
        case MINUS:
@@ -8976,12 +9121,10 @@ simplify_shift_const (rtx x, enum rtx_code code,
 
          if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
              && GET_CODE (XEXP (varop, 0)) == ASHIFTRT
-             && count == (unsigned int)
-                         (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
+             && count == (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
              && (code == LSHIFTRT || code == ASHIFTRT)
              && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
-             && (unsigned HOST_WIDE_INT) INTVAL (XEXP (XEXP (varop, 0), 1))
-                == count
+             && INTVAL (XEXP (XEXP (varop, 0), 1)) == count
              && rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
            {
              count = 0;
@@ -9036,46 +9179,33 @@ simplify_shift_const (rtx x, enum rtx_code code,
 
   /* We have now finished analyzing the shift.  The result should be
      a shift of type CODE with SHIFT_MODE shifting VAROP COUNT places.  If
-     OUTER_OP is non-NIL, it is an operation that needs to be applied
+     OUTER_OP is non-UNKNOWN, it is an operation that needs to be applied
      to the result of the shift.  OUTER_CONST is the relevant constant,
-     but we must turn off all bits turned off in the shift.
-
-     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)) == RTX_BIN_ARITH
-      && GET_CODE (XEXP (x, 1)) == CONST_INT
-      && (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) == count)
-    const_rtx = XEXP (x, 1);
-  else
-    const_rtx = GEN_INT (count);
-
-  if (x && GET_CODE (XEXP (x, 0)) == SUBREG
-      && GET_MODE (XEXP (x, 0)) == shift_mode
-      && SUBREG_REG (XEXP (x, 0)) == varop)
-    varop = XEXP (x, 0);
-  else if (GET_MODE (varop) != shift_mode)
-    varop = gen_lowpart (shift_mode, varop);
+     but we must turn off all bits turned off in the shift.  */
 
-  /* If we can't make the SUBREG, try to return what we were given.  */
-  if (GET_CODE (varop) == CLOBBER)
-    return x ? x : varop;
+  if (outer_op == UNKNOWN
+      && orig_code == code && orig_count == count
+      && varop == orig_varop
+      && shift_mode == GET_MODE (varop))
+    return NULL_RTX;
 
-  new = simplify_binary_operation (code, shift_mode, varop, const_rtx);
-  if (new != 0)
-    x = new;
-  else
-    x = gen_rtx_fmt_ee (code, shift_mode, varop, const_rtx);
+  /* Make a SUBREG if necessary.  If we can't make it, fail.  */
+  varop = gen_lowpart (shift_mode, varop);
+  if (varop == NULL_RTX || GET_CODE (varop) == CLOBBER)
+    return NULL_RTX;
 
   /* If we have an outer operation and we just made a shift, it is
      possible that we could have simplified the shift were it not
      for the outer operation.  So try to do the simplification
      recursively.  */
 
-  if (outer_op != NIL && GET_CODE (x) == code
-      && GET_CODE (XEXP (x, 1)) == CONST_INT)
-    x = simplify_shift_const (x, code, shift_mode, XEXP (x, 0),
-                             INTVAL (XEXP (x, 1)));
+  if (outer_op != UNKNOWN)
+    x = simplify_shift_const_1 (code, shift_mode, varop, count);
+  else
+    x = NULL_RTX;
+
+  if (x == NULL_RTX)
+    x = simplify_gen_binary (code, shift_mode, varop, GEN_INT (count));
 
   /* If we were doing an LSHIFTRT in a wider mode than it was originally,
      turn off all the bits that the shift would have turned off.  */
@@ -9084,14 +9214,14 @@ simplify_shift_const (rtx x, enum rtx_code code,
                                GET_MODE_MASK (result_mode) >> orig_count);
 
   /* Do the remainder of the processing in RESULT_MODE.  */
-  x = gen_lowpart (result_mode, x);
+  x = gen_lowpart_or_truncate (result_mode, x);
 
   /* If COMPLEMENT_P is set, we have to complement X before doing the outer
      operation.  */
   if (complement_p)
     x = simplify_gen_unary (NOT, result_mode, x, result_mode);
 
-  if (outer_op != NIL)
+  if (outer_op != UNKNOWN)
     {
       if (GET_MODE_BITSIZE (result_mode) < HOST_BITS_PER_WIDE_INT)
        outer_const = trunc_int_for_mode (outer_const, result_mode);
@@ -9099,9 +9229,12 @@ simplify_shift_const (rtx x, enum rtx_code code,
       if (outer_op == AND)
        x = simplify_and_const_int (NULL_RTX, result_mode, x, outer_const);
       else if (outer_op == SET)
-       /* This means that we have determined that the result is
-          equivalent to a constant.  This should be rare.  */
-       x = GEN_INT (outer_const);
+       {
+         /* This means that we have determined that the result is
+            equivalent to a constant.  This should be rare.  */
+         if (!side_effects_p (x))
+           x = GEN_INT (outer_const);
+       }
       else if (GET_RTX_CLASS (outer_op) == RTX_UNARY)
        x = simplify_gen_unary (outer_op, result_mode, x, result_mode);
       else
@@ -9111,6 +9244,31 @@ simplify_shift_const (rtx x, enum rtx_code code,
 
   return x;
 }
+
+/* Simplify a shift of VAROP by COUNT bits.  CODE says what kind of shift.
+   The result of the shift is RESULT_MODE.  If we cannot simplify it,
+   return X or, if it is NULL, synthesize the expression with
+   simplify_gen_binary.  Otherwise, return a simplified value.
+
+   The shift is normally computed in the widest mode we find in VAROP, as
+   long as it isn't a different number of words than RESULT_MODE.  Exceptions
+   are ASHIFTRT and ROTATE, which are always done in their original mode.  */
+
+static rtx
+simplify_shift_const (rtx x, enum rtx_code code, enum machine_mode result_mode,
+                     rtx varop, int count)
+{
+  rtx tem = simplify_shift_const_1 (code, result_mode, varop, count);
+  if (tem)
+    return tem;
+
+  if (!x)
+    x = simplify_gen_binary (code, GET_MODE (varop), varop, GEN_INT (count));
+  if (GET_MODE (x) != result_mode)
+    x = gen_lowpart (result_mode, x);
+  return x;
+}
+
 \f
 /* Like recog, but we receive the address of a pointer to a new pattern.
    We try to match the rtx that the pointer points to.
@@ -9205,7 +9363,7 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
       for (i = XVECLEN (newpat, 0) - num_clobbers_to_add;
           i < XVECLEN (newpat, 0); i++)
        {
-         if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) == REG
+         if (REG_P (XEXP (XVECEXP (newpat, 0, i), 0))
              && ! reg_dead_at_p (XEXP (XVECEXP (newpat, 0, i), 0), insn))
            return -1;
          notes = gen_rtx_EXPR_LIST (REG_UNUSED,
@@ -9231,16 +9389,18 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
    An insn containing that will not be recognized.  */
 
 static rtx
-gen_lowpart_for_combine (enum machine_mode mode, rtx x)
+gen_lowpart_for_combine (enum machine_mode omode, rtx x)
 {
+  enum machine_mode imode = GET_MODE (x);
+  unsigned int osize = GET_MODE_SIZE (omode);
+  unsigned int isize = GET_MODE_SIZE (imode);
   rtx result;
 
-  if (GET_MODE (x) == mode)
+  if (omode == imode)
     return x;
 
-  /* Return identity if this is a CONST or symbolic
-     reference.  */
-  if (mode == Pmode
+  /* Return identity if this is a CONST or symbolic reference.  */
+  if (omode == Pmode
       && (GET_CODE (x) == CONST
          || GET_CODE (x) == SYMBOL_REF
          || GET_CODE (x) == LABEL_REF))
@@ -9248,72 +9408,71 @@ gen_lowpart_for_combine (enum machine_mode mode, rtx x)
 
   /* We can only support MODE being wider than a word if X is a
      constant integer or has a mode the same size.  */
-
-  if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
-      && ! ((GET_MODE (x) == VOIDmode
+  if (GET_MODE_SIZE (omode) > UNITS_PER_WORD
+      && ! ((imode == VOIDmode
             && (GET_CODE (x) == CONST_INT
                 || GET_CODE (x) == CONST_DOUBLE))
-           || GET_MODE_SIZE (GET_MODE (x)) == GET_MODE_SIZE (mode)))
-    return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
+           || isize == osize))
+    goto fail;
 
   /* X might be a paradoxical (subreg (mem)).  In that case, gen_lowpart
      won't know what to do.  So we will strip off the SUBREG here and
      process normally.  */
-  if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == MEM)
+  if (GET_CODE (x) == SUBREG && MEM_P (SUBREG_REG (x)))
     {
       x = SUBREG_REG (x);
-      if (GET_MODE (x) == mode)
+
+      /* For use in case we fall down into the address adjustments
+        further below, we need to adjust the known mode and size of
+        x; imode and isize, since we just adjusted x.  */
+      imode = GET_MODE (x);
+
+      if (imode == omode)
        return x;
+
+      isize = GET_MODE_SIZE (imode);
     }
 
-  result = gen_lowpart_common (mode, x);
+  result = gen_lowpart_common (omode, x);
+
 #ifdef CANNOT_CHANGE_MODE_CLASS
-  if (result != 0
-      && GET_CODE (result) == SUBREG
-      && GET_CODE (SUBREG_REG (result)) == REG
-      && REGNO (SUBREG_REG (result)) >= FIRST_PSEUDO_REGISTER)
-    bitmap_set_bit (&subregs_of_mode, REGNO (SUBREG_REG (result))
-                                     * MAX_MACHINE_MODE
-                                     + GET_MODE (result));
+  if (result != 0 && GET_CODE (result) == SUBREG)
+    record_subregs_of_mode (result);
 #endif
 
   if (result)
     return result;
 
-  if (GET_CODE (x) == MEM)
+  if (MEM_P (x))
     {
       int offset = 0;
 
       /* Refuse to work on a volatile memory ref or one with a mode-dependent
         address.  */
       if (MEM_VOLATILE_P (x) || mode_dependent_address_p (XEXP (x, 0)))
-       return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
+       goto fail;
 
       /* If we want to refer to something bigger than the original memref,
         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);
+      if (isize < osize)
+       return gen_rtx_SUBREG (omode, x, 0);
 
       if (WORDS_BIG_ENDIAN)
-       offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
-                 - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
+       offset = MAX (isize, UNITS_PER_WORD) - MAX (osize, UNITS_PER_WORD);
 
+      /* Adjust the address so that the address-after-the-data is
+        unchanged.  */
       if (BYTES_BIG_ENDIAN)
-       {
-         /* Adjust the address so that the address-after-the-data is
-            unchanged.  */
-         offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
-                    - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
-       }
+       offset -= MIN (UNITS_PER_WORD, osize) - MIN (UNITS_PER_WORD, isize);
 
-      return adjust_address_nv (x, mode, offset);
+      return adjust_address_nv (x, omode, offset);
     }
 
   /* If X is a comparison operator, rewrite it in a new mode.  This
      probably won't match, but may allow further simplifications.  */
   else if (COMPARISON_P (x))
-    return gen_rtx_fmt_ee (GET_CODE (x), mode, XEXP (x, 0), XEXP (x, 1));
+    return gen_rtx_fmt_ee (GET_CODE (x), omode, XEXP (x, 0), XEXP (x, 1));
 
   /* If we couldn't simplify X any other way, just enclose it in a
      SUBREG.  Normally, this SUBREG won't match, but some patterns may
@@ -9322,21 +9481,22 @@ gen_lowpart_for_combine (enum machine_mode mode, rtx x)
     {
       int offset = 0;
       rtx res;
-      enum machine_mode sub_mode = GET_MODE (x);
 
-      offset = subreg_lowpart_offset (mode, sub_mode);
-      if (sub_mode == VOIDmode)
+      offset = subreg_lowpart_offset (omode, imode);
+      if (imode == VOIDmode)
        {
-         sub_mode = int_mode_for_mode (mode);
-         x = gen_lowpart_common (sub_mode, x);
-         if (x == 0)
-           return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
+         imode = int_mode_for_mode (omode);
+         x = gen_lowpart_common (imode, x);
+         if (x == NULL)
+           goto fail;
        }
-      res = simplify_gen_subreg (mode, x, sub_mode, offset);
+      res = simplify_gen_subreg (omode, x, imode, offset);
       if (res)
        return res;
-      return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
     }
+
+ fail:
+  return gen_rtx_CLOBBER (imode, const0_rtx);
 }
 \f
 /* Simplify a comparison between *POP0 and *POP1 where CODE is the
@@ -9664,7 +9824,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
          break;
 
        case GEU:
-         /* >= C is equivalent to < (C - 1).  */
+         /* >= C is equivalent to > (C - 1).  */
          if (const_op > 1)
            {
              const_op -= 1;
@@ -9716,7 +9876,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
        op0 = force_to_mode (op0, mode,
                             ((HOST_WIDE_INT) 1
                              << (GET_MODE_BITSIZE (mode) - 1)),
-                            NULL_RTX, 0);
+                            0);
 
       /* Now try cases based on the opcode of OP0.  If none of the cases
         does a "continue", we exit this loop immediately after the
@@ -9867,16 +10027,22 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
          break;
 
        case SIGN_EXTEND:
-         /* Can simplify (compare (zero/sign_extend FOO) CONST)
-            to (compare FOO CONST) if CONST fits in FOO's mode and we
-            are either testing inequality or have an unsigned comparison
-            with ZERO_EXTEND or a signed comparison with SIGN_EXTEND.  */
-         if (! unsigned_comparison_p
-             && (GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0)))
-                 <= HOST_BITS_PER_WIDE_INT)
+         /* Can simplify (compare (zero/sign_extend FOO) CONST) to
+            (compare FOO CONST) if CONST fits in FOO's mode and we
+            are either testing inequality or have an unsigned
+            comparison with ZERO_EXTEND or a signed comparison with
+            SIGN_EXTEND.  But don't do it if we don't have a compare
+            insn of the given mode, since we'd have to revert it
+            later on, and then we wouldn't know whether to sign- or
+            zero-extend.  */
+         mode = GET_MODE (XEXP (op0, 0));
+         if (mode != VOIDmode && GET_MODE_CLASS (mode) == MODE_INT
+             && ! unsigned_comparison_p
+             && (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
              && ((unsigned HOST_WIDE_INT) const_op
                  < (((unsigned HOST_WIDE_INT) 1
-                     << (GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0))) - 1)))))
+                     << (GET_MODE_BITSIZE (mode) - 1))))
+             && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
            {
              op0 = XEXP (op0, 0);
              continue;
@@ -9884,34 +10050,61 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
          break;
 
        case SUBREG:
-         /* Check for the case where we are comparing A - C1 with C2,
-            both constants are smaller than 1/2 the maximum positive
-            value in MODE, and the comparison is equality or unsigned.
-            In that case, if A is either zero-extended to MODE or has
-            sufficient sign bits so that the high-order bit in MODE
-            is a copy of the sign in the inner mode, we can prove that it is
-            safe to do the operation in the wider mode.  This simplifies
-            many range checks.  */
+         /* Check for the case where we are comparing A - C1 with C2, that is
+
+              (subreg:MODE (plus (A) (-C1))) op (C2)
+
+            with C1 a constant, and try to lift the SUBREG, i.e. to do the
+            comparison in the wider mode.  One of the following two conditions
+            must be true in order for this to be valid:
+
+              1. The mode extension results in the same bit pattern being added
+                 on both sides and the comparison is equality or unsigned.  As
+                 C2 has been truncated to fit in MODE, the pattern can only be
+                 all 0s or all 1s.
+
+              2. The mode extension results in the sign bit being copied on
+                 each side.
+
+            The difficulty here is that we have predicates for A but not for
+            (A - C1) so we need to check that C1 is within proper bounds so
+            as to perturbate A as little as possible.  */
 
          if (mode_width <= HOST_BITS_PER_WIDE_INT
              && subreg_lowpart_p (op0)
+             && GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0))) > mode_width
              && GET_CODE (SUBREG_REG (op0)) == PLUS
-             && GET_CODE (XEXP (SUBREG_REG (op0), 1)) == CONST_INT
-             && INTVAL (XEXP (SUBREG_REG (op0), 1)) < 0
-             && (-INTVAL (XEXP (SUBREG_REG (op0), 1))
-                 < (HOST_WIDE_INT) (GET_MODE_MASK (mode) / 2))
-             && (unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode) / 2
-             && (0 == (nonzero_bits (XEXP (SUBREG_REG (op0), 0),
-                                     GET_MODE (SUBREG_REG (op0)))
-                       & ~GET_MODE_MASK (mode))
-                 || (num_sign_bit_copies (XEXP (SUBREG_REG (op0), 0),
-                                          GET_MODE (SUBREG_REG (op0)))
-                     > (unsigned int)
-                       (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
-                        - GET_MODE_BITSIZE (mode)))))
-           {
-             op0 = SUBREG_REG (op0);
-             continue;
+             && GET_CODE (XEXP (SUBREG_REG (op0), 1)) == CONST_INT)
+           {
+             enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
+             rtx a = XEXP (SUBREG_REG (op0), 0);
+             HOST_WIDE_INT c1 = -INTVAL (XEXP (SUBREG_REG (op0), 1));
+
+             if ((c1 > 0
+                  && (unsigned HOST_WIDE_INT) c1
+                      < (unsigned HOST_WIDE_INT) 1 << (mode_width - 1)
+                  && (equality_comparison_p || unsigned_comparison_p)
+                  /* (A - C1) zero-extends if it is positive and sign-extends
+                     if it is negative, C2 both zero- and sign-extends.  */
+                  && ((0 == (nonzero_bits (a, inner_mode)
+                             & ~GET_MODE_MASK (mode))
+                       && const_op >= 0)
+                      /* (A - C1) sign-extends if it is positive and 1-extends
+                         if it is negative, C2 both sign- and 1-extends.  */
+                      || (num_sign_bit_copies (a, inner_mode)
+                          > (unsigned int) (GET_MODE_BITSIZE (inner_mode)
+                                            - mode_width)
+                          && const_op < 0)))
+                 || ((unsigned HOST_WIDE_INT) c1
+                      < (unsigned HOST_WIDE_INT) 1 << (mode_width - 2)
+                     /* (A - C1) always sign-extends, like C2.  */
+                     && num_sign_bit_copies (a, inner_mode)
+                        > (unsigned int) (GET_MODE_BITSIZE (inner_mode)
+                                          - (mode_width - 1))))
+               {
+                 op0 = SUBREG_REG (op0);
+                 continue;
+               }
            }
 
          /* If the inner mode is narrower and we are extracting the low part,
@@ -9925,11 +10118,12 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
          /* ... fall through ...  */
 
        case ZERO_EXTEND:
-         if ((unsigned_comparison_p || equality_comparison_p)
-             && (GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0)))
-                 <= HOST_BITS_PER_WIDE_INT)
-             && ((unsigned HOST_WIDE_INT) const_op
-                 < GET_MODE_MASK (GET_MODE (XEXP (op0, 0)))))
+         mode = GET_MODE (XEXP (op0, 0));
+         if (mode != VOIDmode && GET_MODE_CLASS (mode) == MODE_INT
+             && (unsigned_comparison_p || equality_comparison_p)
+             && (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+             && ((unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode))
+             && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
            {
              op0 = XEXP (op0, 0);
              continue;
@@ -10018,7 +10212,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
        case UNEQ:  case LTGT:
        case LT:  case LTU:  case UNLT:  case LE:  case LEU:  case UNLE:
        case GT:  case GTU:  case UNGT:  case GE:  case GEU:  case UNGE:
-        case UNORDERED: case ORDERED:
+       case UNORDERED: case ORDERED:
          /* We can't do anything if OP0 is a condition code value, rather
             than an actual data value.  */
          if (const_op != 0
@@ -10046,7 +10240,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              if (code == LT || code == NE)
                new_code = GET_CODE (op0);
              else
-               new_code = combine_reversed_comparison_code (op0);
+               new_code = reversed_comparison_code (op0, NULL);
 
              if (new_code != UNKNOWN)
                {
@@ -10079,9 +10273,9 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              && XEXP (XEXP (op0, 0), 0) == const1_rtx)
            {
              op0 = simplify_and_const_int
-               (op0, mode, gen_rtx_LSHIFTRT (mode,
-                                             XEXP (op0, 1),
-                                             XEXP (XEXP (op0, 0), 1)),
+               (NULL_RTX, mode, gen_rtx_LSHIFTRT (mode,
+                                                  XEXP (op0, 1),
+                                                  XEXP (XEXP (op0, 0), 1)),
                 (HOST_WIDE_INT) 1);
              continue;
            }
@@ -10127,14 +10321,27 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
          /* If this AND operation is really a ZERO_EXTEND from a narrower
             mode, the constant fits within that mode, and this is either an
             equality or unsigned comparison, try to do this comparison in
-            the narrower mode.  */
+            the narrower mode.
+
+            Note that in:
+
+            (ne:DI (and:DI (reg:DI 4) (const_int 0xffffffff)) (const_int 0))
+            -> (ne:DI (reg:SI 4) (const_int 0))
+
+            unless TRULY_NOOP_TRUNCATION allows it or the register is
+            known to hold a value of the required mode the
+            transformation is invalid.  */
          if ((equality_comparison_p || unsigned_comparison_p)
              && GET_CODE (XEXP (op0, 1)) == CONST_INT
              && (i = exact_log2 ((INTVAL (XEXP (op0, 1))
                                   & GET_MODE_MASK (mode))
                                  + 1)) >= 0
              && const_op >> i == 0
-             && (tmode = mode_for_size (i, MODE_INT, 1)) != BLKmode)
+             && (tmode = mode_for_size (i, MODE_INT, 1)) != BLKmode
+             && (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (tmode),
+                                        GET_MODE_BITSIZE (GET_MODE (op0)))
+                 || (REG_P (XEXP (op0, 0))
+                     && reg_truncated_to_mode (tmode, XEXP (op0, 0)))))
            {
              op0 = gen_lowpart (tmode, XEXP (op0, 0));
              continue;
@@ -10395,7 +10602,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
      those bits.
 
      3. SUBREG_REG (op0) is a memory and LOAD_EXTEND_OP is defined and not
-     NIL.  In that case we know those bits are zeros or ones.  We must
+     UNKNOWN.  In that case we know those bits are zeros or ones.  We must
      also be sure that they are the same as the upper bits of op1.
 
      We can never remove a SUBREG for a non-equality comparison because
@@ -10414,7 +10621,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
        {
          /* For paradoxical subregs, allow case 1 as above.  Case 3 isn't
             implemented.  */
-          if (GET_CODE (SUBREG_REG (op0)) == REG)
+         if (REG_P (SUBREG_REG (op0)))
            {
              op0 = SUBREG_REG (op0);
              op1 = gen_lowpart (GET_MODE (op0), op1);
@@ -10518,36 +10725,45 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
   return code;
 }
 \f
-/* Like jump.c' reversed_comparison_code, but use combine infrastructure for
-   searching backward.  */
-static enum rtx_code
-combine_reversed_comparison_code (rtx exp)
+/* Utility function for record_value_for_reg.  Count number of
+   rtxs in X.  */
+static int
+count_rtxs (rtx x)
 {
-  enum rtx_code code1 = reversed_comparison_code (exp, NULL);
-  rtx x;
-
-  if (code1 != UNKNOWN
-      || GET_MODE_CLASS (GET_MODE (XEXP (exp, 0))) != MODE_CC)
-    return code1;
-  /* Otherwise try and find where the condition codes were last set and
-     use that.  */
-  x = get_last_value (XEXP (exp, 0));
-  if (!x || GET_CODE (x) != COMPARE)
-    return UNKNOWN;
-  return reversed_comparison_code_parts (GET_CODE (exp),
-                                        XEXP (x, 0), XEXP (x, 1), NULL);
-}
+  enum rtx_code code = GET_CODE (x);
+  const char *fmt;
+  int i, ret = 1;
 
-/* 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 (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 simplify_gen_relational (reversed_code, mode, VOIDmode, op0, op1);
+  if (GET_RTX_CLASS (code) == '2'
+      || GET_RTX_CLASS (code) == 'c')
+    {
+      rtx x0 = XEXP (x, 0);
+      rtx x1 = XEXP (x, 1);
+
+      if (x0 == x1)
+       return 1 + 2 * count_rtxs (x0);
+
+      if ((GET_RTX_CLASS (GET_CODE (x1)) == '2'
+          || GET_RTX_CLASS (GET_CODE (x1)) == 'c')
+         && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
+       return 2 + 2 * count_rtxs (x0)
+              + count_rtxs (x == XEXP (x1, 0)
+                            ? XEXP (x1, 1) : XEXP (x1, 0));
+
+      if ((GET_RTX_CLASS (GET_CODE (x0)) == '2'
+          || GET_RTX_CLASS (GET_CODE (x0)) == 'c')
+         && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
+       return 2 + 2 * count_rtxs (x1)
+              + count_rtxs (x == XEXP (x0, 0)
+                            ? XEXP (x0, 1) : XEXP (x0, 0));
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    if (fmt[i] == 'e')
+      ret += count_rtxs (XEXP (x, i));
+
+  return ret;
 }
 \f
 /* Utility function for following routine.  Called when X is part of a value
@@ -10652,6 +10868,13 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
              && GET_CODE (XEXP (tem, 0)) == CLOBBER
              && GET_CODE (XEXP (tem, 1)) == CLOBBER)
            tem = XEXP (tem, 0);
+         else if (count_occurrences (value, reg, 1) >= 2)
+           {
+             /* If there are two or more occurrences of REG in VALUE,
+                prevent the value from growing too much.  */
+             if (count_rtxs (tem) > MAX_LAST_VALUE_RTL)
+               tem = gen_rtx_CLOBBER (GET_MODE (tem), const0_rtx);
+           }
 
          value = replace_rtx (copy_rtx (value), reg, tem);
        }
@@ -10671,6 +10894,7 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
       reg_stat[i].last_set_nonzero_bits = 0;
       reg_stat[i].last_set_sign_bit_copies = 0;
       reg_stat[i].last_death = 0;
+      reg_stat[i].truncated_to_mode = 0;
     }
 
   /* Mark registers that are being referenced in this value.  */
@@ -10687,7 +10911,7 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
   for (i = regno; i < endregno; i++)
     {
       reg_stat[i].last_set_label = label_tick;
-      if (value && reg_stat[i].last_set_table_tick == label_tick)
+      if (!insn || (value && reg_stat[i].last_set_table_tick == label_tick))
        reg_stat[i].last_set_invalid = 1;
       else
        reg_stat[i].last_set_invalid = 0;
@@ -10736,7 +10960,14 @@ record_dead_and_set_regs_1 (rtx dest, rtx setter, void *data)
   if (GET_CODE (dest) == SUBREG)
     dest = SUBREG_REG (dest);
 
-  if (GET_CODE (dest) == REG)
+  if (!record_dead_insn)
+    {
+      if (REG_P (dest))
+       record_value_for_reg (dest, NULL_RTX, NULL_RTX);
+      return;
+    }
+
+  if (REG_P (dest))
     {
       /* If we are setting the whole register, we know its value.  Otherwise
         show that we don't know the value.  We can handle SUBREG in
@@ -10754,7 +10985,7 @@ record_dead_and_set_regs_1 (rtx dest, rtx setter, void *data)
       else
        record_value_for_reg (dest, record_dead_insn, NULL_RTX);
     }
-  else if (GET_CODE (dest) == MEM
+  else if (MEM_P (dest)
           /* Ignore pushes, they clobber nothing.  */
           && ! push_operand (dest, GET_MODE (dest)))
     mem_last_set = INSN_CUID (record_dead_insn);
@@ -10779,7 +11010,7 @@ record_dead_and_set_regs (rtx insn)
   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
     {
       if (REG_NOTE_KIND (link) == REG_DEAD
-         && GET_CODE (XEXP (link, 0)) == REG)
+         && REG_P (XEXP (link, 0)))
        {
          unsigned int regno = REGNO (XEXP (link, 0));
          unsigned int endregno
@@ -10794,7 +11025,7 @@ record_dead_and_set_regs (rtx insn)
        record_value_for_reg (XEXP (link, 0), insn, NULL_RTX);
     }
 
-  if (GET_CODE (insn) == CALL_INSN)
+  if (CALL_P (insn))
     {
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
@@ -10804,19 +11035,19 @@ record_dead_and_set_regs (rtx insn)
            reg_stat[i].last_set_nonzero_bits = 0;
            reg_stat[i].last_set_sign_bit_copies = 0;
            reg_stat[i].last_death = 0;
+           reg_stat[i].truncated_to_mode = 0;
          }
 
       last_call_cuid = mem_last_set = INSN_CUID (insn);
 
-      /* Don't bother recording what this insn does.  It might set the
-        return value register, but we can't combine into a call
-        pattern anyway, so there's no point trying (and it may cause
-        a crash, if e.g. we wind up asking for last_set_value of a
-        SUBREG of the return value register).  */
-      return;
+      /* We can't combine into a call pattern.  Remember, though, that
+        the return value register is set at this CUID.  We could
+        still replace a register with the return value from the
+        wrong subroutine call!  */
+      note_stores (PATTERN (insn), record_dead_and_set_regs_1, NULL_RTX);
     }
-
-  note_stores (PATTERN (insn), record_dead_and_set_regs_1, insn);
+  else
+    note_stores (PATTERN (insn), record_dead_and_set_regs_1, insn);
 }
 
 /* If a SUBREG has the promoted bit set, it is in fact a property of the
@@ -10843,7 +11074,7 @@ record_promoted_value (rtx insn, rtx subreg)
       insn = XEXP (links, 0);
       set = single_set (insn);
 
-      if (! set || GET_CODE (SET_DEST (set)) != REG
+      if (! set || !REG_P (SET_DEST (set))
          || REGNO (SET_DEST (set)) != regno
          || GET_MODE (SET_DEST (set)) != GET_MODE (SUBREG_REG (subreg)))
        {
@@ -10857,7 +11088,7 @@ record_promoted_value (rtx insn, rtx subreg)
            reg_stat[regno].last_set_nonzero_bits &= GET_MODE_MASK (mode);
        }
 
-      if (GET_CODE (SET_SRC (set)) == REG)
+      if (REG_P (SET_SRC (set)))
        {
          regno = REGNO (SET_SRC (set));
          links = LOG_LINKS (insn);
@@ -10867,15 +11098,81 @@ record_promoted_value (rtx insn, rtx subreg)
     }
 }
 
-/* Scan X for promoted SUBREGs.  For each one found,
-   note what it implies to the registers used in it.  */
+/* Check if X, a register, is known to contain a value already
+   truncated to MODE.  In this case we can use a subreg to refer to
+   the truncated value even though in the generic case we would need
+   an explicit truncation.  */
+
+static bool
+reg_truncated_to_mode (enum machine_mode mode, rtx x)
+{
+  enum machine_mode truncated = reg_stat[REGNO (x)].truncated_to_mode;
+
+  if (truncated == 0 || reg_stat[REGNO (x)].truncation_label != label_tick)
+    return false;
+  if (GET_MODE_SIZE (truncated) <= GET_MODE_SIZE (mode))
+    return true;
+  if (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+                            GET_MODE_BITSIZE (truncated)))
+    return true;
+  return false;
+}
+
+/* X is a REG or a SUBREG.  If X is some sort of a truncation record
+   it.  For non-TRULY_NOOP_TRUNCATION targets we might be able to turn
+   a truncate into a subreg using this information.  */
+
+static void
+record_truncated_value (rtx x)
+{
+  enum machine_mode truncated_mode;
+
+  if (GET_CODE (x) == SUBREG && REG_P (SUBREG_REG (x)))
+    {
+      enum machine_mode original_mode = GET_MODE (SUBREG_REG (x));
+      truncated_mode = GET_MODE (x);
+
+      if (GET_MODE_SIZE (original_mode) <= GET_MODE_SIZE (truncated_mode))
+       return;
+
+      if (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (truncated_mode),
+                                GET_MODE_BITSIZE (original_mode)))
+       return;
+
+      x = SUBREG_REG (x);
+    }
+  /* ??? For hard-regs we now record everything.  We might be able to
+     optimize this using last_set_mode.  */
+  else if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
+    truncated_mode = GET_MODE (x);
+  else
+    return;
+
+  if (reg_stat[REGNO (x)].truncated_to_mode == 0
+      || reg_stat[REGNO (x)].truncation_label < label_tick
+      || (GET_MODE_SIZE (truncated_mode)
+         < GET_MODE_SIZE (reg_stat[REGNO (x)].truncated_to_mode)))
+    {
+      reg_stat[REGNO (x)].truncated_to_mode = truncated_mode;
+      reg_stat[REGNO (x)].truncation_label = label_tick;
+    }
+}
+
+/* Scan X for promoted SUBREGs and truncated REGs.  For each one
+   found, note what it implies to the registers used in it.  */
 
 static void
-check_promoted_subreg (rtx insn, rtx x)
+check_conversions (rtx insn, rtx x)
 {
-  if (GET_CODE (x) == SUBREG && SUBREG_PROMOTED_VAR_P (x)
-      && GET_CODE (SUBREG_REG (x)) == REG)
-    record_promoted_value (insn, x);
+  if (GET_CODE (x) == SUBREG || REG_P (x))
+    {
+      if (GET_CODE (x) == SUBREG
+         && SUBREG_PROMOTED_VAR_P (x)
+         && REG_P (SUBREG_REG (x)))
+       record_promoted_value (insn, x);
+
+      record_truncated_value (x);
+    }
   else
     {
       const char *format = GET_RTX_FORMAT (GET_CODE (x));
@@ -10885,13 +11182,13 @@ check_promoted_subreg (rtx insn, rtx x)
        switch (format[i])
          {
          case 'e':
-           check_promoted_subreg (insn, XEXP (x, i));
+           check_conversions (insn, XEXP (x, i));
            break;
          case 'V':
          case 'E':
            if (XVEC (x, i) != 0)
              for (j = 0; j < XVECLEN (x, i); j++)
-               check_promoted_subreg (insn, XVECEXP (x, i, j));
+               check_conversions (insn, XVECEXP (x, i, j));
            break;
          }
     }
@@ -10915,7 +11212,7 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
   int len = GET_RTX_LENGTH (GET_CODE (x));
   int i;
 
-  if (GET_CODE (x) == REG)
+  if (REG_P (x))
     {
       unsigned int regno = REGNO (x);
       unsigned int endregno
@@ -10930,7 +11227,8 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
            || (! (regno >= FIRST_PSEUDO_REGISTER
                   && REG_N_SETS (regno) == 1
                   && (! REGNO_REG_SET_P
-                      (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, regno)))
+                      (ENTRY_BLOCK_PTR->next_bb->il.rtl->global_live_at_start,
+                       regno)))
                && reg_stat[j].last_set_label > tick))
          {
            if (replace)
@@ -10943,7 +11241,7 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
   /* If this is a memory reference, make sure that there were
      no stores after it that might have clobbered the value.  We don't
      have alias info, so we assume any store invalidates it.  */
-  else if (GET_CODE (x) == MEM && ! RTX_UNCHANGING_P (x)
+  else if (MEM_P (x) && !MEM_READONLY_P (x)
           && INSN_CUID (insn) <= mem_last_set)
     {
       if (replace)
@@ -11019,7 +11317,7 @@ get_last_value (rtx x)
       && (value = get_last_value (SUBREG_REG (x))) != 0)
     return gen_lowpart (GET_MODE (x), value);
 
-  if (GET_CODE (x) != REG)
+  if (!REG_P (x))
     return 0;
 
   regno = REGNO (x);
@@ -11040,7 +11338,8 @@ get_last_value (rtx x)
          && (regno < FIRST_PSEUDO_REGISTER
              || REG_N_SETS (regno) != 1
              || (REGNO_REG_SET_P
-                 (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, regno)))))
+                 (ENTRY_BLOCK_PTR->next_bb->il.rtl->global_live_at_start,
+                  regno)))))
     return 0;
 
   /* If the value was set in a later insn than the ones we are processing,
@@ -11130,7 +11429,7 @@ reg_dead_at_p_1 (rtx dest, rtx x, void *data ATTRIBUTE_UNUSED)
 {
   unsigned int regno, endregno;
 
-  if (GET_CODE (dest) != REG)
+  if (!REG_P (dest))
     return;
 
   regno = REGNO (dest);
@@ -11164,17 +11463,19 @@ reg_dead_at_p (rtx reg, rtx insn)
 
   reg_dead_flag = 0;
 
-  /* Check that reg isn't mentioned in NEWPAT_USED_REGS.  */
+  /* Check that reg isn't mentioned in NEWPAT_USED_REGS.  For fixed registers
+     we allow the machine description to decide whether use-and-clobber
+     patterns are OK.  */
   if (reg_dead_regno < FIRST_PSEUDO_REGISTER)
     {
       for (i = reg_dead_regno; i < reg_dead_endregno; i++)
-       if (TEST_HARD_REG_BIT (newpat_used_regs, i))
+       if (!fixed_regs[i] && TEST_HARD_REG_BIT (newpat_used_regs, i))
          return 0;
     }
 
   /* Scan backwards until we find a REG_DEAD note, SET, CLOBBER, label, or
      beginning of function.  */
-  for (; insn && GET_CODE (insn) != CODE_LABEL && GET_CODE (insn) != BARRIER;
+  for (; insn && !LABEL_P (insn) && !BARRIER_P (insn);
        insn = prev_nonnote_insn (insn))
     {
       note_stores (PATTERN (insn), reg_dead_at_p_1, NULL);
@@ -11199,7 +11500,7 @@ reg_dead_at_p (rtx reg, rtx insn)
     }
 
   for (i = reg_dead_regno; i < reg_dead_endregno; i++)
-    if (REGNO_REG_SET_P (block->global_live_at_start, i))
+    if (REGNO_REG_SET_P (block->il.rtl->global_live_at_start, i))
       return 0;
 
   return 1;
@@ -11237,7 +11538,7 @@ mark_used_regs_combine (rtx x)
     case CLOBBER:
       /* If we are clobbering a MEM, mark any hard registers inside the
         address as used.  */
-      if (GET_CODE (XEXP (x, 0)) == MEM)
+      if (MEM_P (XEXP (x, 0)))
        mark_used_regs_combine (XEXP (XEXP (x, 0), 0));
       return;
 
@@ -11274,11 +11575,10 @@ mark_used_regs_combine (rtx x)
 
        while (GET_CODE (testreg) == SUBREG
               || GET_CODE (testreg) == ZERO_EXTRACT
-              || GET_CODE (testreg) == SIGN_EXTRACT
               || GET_CODE (testreg) == STRICT_LOW_PART)
          testreg = XEXP (testreg, 0);
 
-       if (GET_CODE (testreg) == MEM)
+       if (MEM_P (testreg))
          mark_used_regs_combine (XEXP (testreg, 0));
 
        mark_used_regs_combine (SET_SRC (x));
@@ -11477,7 +11777,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
         For a REG (the only other possibility), the entire value is
         being replaced so the old value is not used in this insn.  */
 
-      if (GET_CODE (dest) == MEM)
+      if (MEM_P (dest))
        move_deaths (XEXP (dest, 0), maybe_kill_insn, from_cuid,
                     to_insn, pnotes);
       return;
@@ -11527,7 +11827,7 @@ reg_bitfield_target_p (rtx x, rtx body)
       if (GET_CODE (target) == SUBREG)
        target = SUBREG_REG (target);
 
-      if (GET_CODE (target) != REG)
+      if (!REG_P (target))
        return 0;
 
       tregno = REGNO (target), regno = REGNO (x);
@@ -11552,11 +11852,16 @@ reg_bitfield_target_p (rtx x, rtx 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 (rtx notes, rtx from_insn, rtx i3, rtx i2)
+distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
+                 rtx elim_i1)
 {
   rtx note, next_note;
   rtx tem;
@@ -11565,12 +11870,6 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
     {
       rtx place = 0, place2 = 0;
 
-      /* If this NOTE references a pseudo register, ensure it references
-        the latest copy of that register.  */
-      if (XEXP (note, 0) && GET_CODE (XEXP (note, 0)) == REG
-         && REGNO (XEXP (note, 0)) >= FIRST_PSEUDO_REGISTER)
-       XEXP (note, 0) = regno_reg_rtx[REGNO (XEXP (note, 0))];
-
       next_note = XEXP (note, 1);
       switch (REG_NOTE_KIND (note))
        {
@@ -11586,29 +11885,25 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
          /* 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.  */
-         place = i3;
-         break;
-
        case REG_NON_LOCAL_GOTO:
-         if (GET_CODE (i3) == JUMP_INSN)
+         if (JUMP_P (i3))
            place = i3;
-         else if (i2 && GET_CODE (i2) == JUMP_INSN)
-           place = i2;
          else
-           abort ();
+           {
+             gcc_assert (i2 && JUMP_P (i2));
+             place = i2;
+           }
          break;
 
        case REG_EH_REGION:
          /* These notes must remain with the call or trapping instruction.  */
-         if (GET_CODE (i3) == CALL_INSN)
+         if (CALL_P (i3))
            place = i3;
-         else if (i2 && GET_CODE (i2) == CALL_INSN)
+         else if (i2 && CALL_P (i2))
            place = i2;
-         else if (flag_non_call_exceptions)
+         else
            {
+             gcc_assert (flag_non_call_exceptions);
              if (may_trap_p (i3))
                place = i3;
              else if (i2 && may_trap_p (i2))
@@ -11617,21 +11912,19 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                 can now prove that the instructions can't trap.  Drop the
                 note in this case.  */
            }
-         else
-           abort ();
          break;
 
-       case REG_ALWAYS_RETURN:
        case REG_NORETURN:
        case REG_SETJMP:
          /* These notes must remain with the call.  It should not be
             possible for both I2 and I3 to be a call.  */
-         if (GET_CODE (i3) == CALL_INSN)
+         if (CALL_P (i3))
            place = i3;
-         else if (i2 && GET_CODE (i2) == CALL_INSN)
-           place = i2;
          else
-           abort ();
+           {
+             gcc_assert (i2 && CALL_P (i2));
+             place = i2;
+           }
          break;
 
        case REG_UNUSED:
@@ -11657,7 +11950,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
              if (from_insn != i3)
                break;
 
-             if (! (GET_CODE (XEXP (note, 0)) == REG
+             if (! (REG_P (XEXP (note, 0))
                     ? find_regno_note (i3, REG_UNUSED, REGNO (XEXP (note, 0)))
                     : find_reg_note (i3, REG_UNUSED, XEXP (note, 0))))
                place = i3;
@@ -11666,7 +11959,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
             now dies here, so we must put a REG_DEAD note here unless there
             is one already.  */
          else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3))
-                  && ! (GET_CODE (XEXP (note, 0)) == REG
+                  && ! (REG_P (XEXP (note, 0))
                         ? find_regno_note (i3, REG_DEAD,
                                            REGNO (XEXP (note, 0)))
                         : find_reg_note (i3, REG_DEAD, XEXP (note, 0))))
@@ -11734,22 +12027,34 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                place = i2;
            }
 
-         /* Don't attach REG_LABEL note to a JUMP_INSN which has
-            JUMP_LABEL already.  Instead, decrement LABEL_NUSES.  */
-         if (place && GET_CODE (place) == JUMP_INSN && JUMP_LABEL (place))
+         /* Don't attach REG_LABEL note to a JUMP_INSN.  Add
+            a JUMP_LABEL instead or decrement LABEL_NUSES.  */
+         if (place && JUMP_P (place))
            {
-             if (JUMP_LABEL (place) != XEXP (note, 0))
-               abort ();
-             if (GET_CODE (JUMP_LABEL (place)) == CODE_LABEL)
-               LABEL_NUSES (JUMP_LABEL (place))--;
+             rtx label = JUMP_LABEL (place);
+
+             if (!label)
+               JUMP_LABEL (place) = XEXP (note, 0);
+             else
+               {
+                 gcc_assert (label == XEXP (note, 0));
+                 if (LABEL_P (label))
+                   LABEL_NUSES (label)--;
+               }
              place = 0;
            }
-         if (place2 && GET_CODE (place2) == JUMP_INSN && JUMP_LABEL (place2))
+         if (place2 && JUMP_P (place2))
            {
-             if (JUMP_LABEL (place2) != XEXP (note, 0))
-               abort ();
-             if (GET_CODE (JUMP_LABEL (place2)) == CODE_LABEL)
-               LABEL_NUSES (JUMP_LABEL (place2))--;
+             rtx label = JUMP_LABEL (place2);
+
+             if (!label)
+               JUMP_LABEL (place2) = XEXP (note, 0);
+             else
+               {
+                 gcc_assert (label == XEXP (note, 0));
+                 if (LABEL_P (label))
+                   LABEL_NUSES (label)--;
+               }
              place2 = 0;
            }
          break;
@@ -11765,7 +12070,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
          /* If the insn previously containing this note still exists,
             put it back where it was.  Otherwise move it to the previous
             insn.  Adjust the corresponding REG_LIBCALL note.  */
-         if (GET_CODE (from_insn) != NOTE)
+         if (!NOTE_P (from_insn))
            place = from_insn;
          else
            {
@@ -11785,7 +12090,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
 
        case REG_LIBCALL:
          /* This is handled similarly to REG_RETVAL.  */
-         if (GET_CODE (from_insn) != NOTE)
+         if (!NOTE_P (from_insn))
            place = from_insn;
          else
            {
@@ -11804,7 +12109,15 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
          break;
 
        case REG_DEAD:
-         /* If the register is used as an input in I3, it dies there.
+         /* If we replaced the right hand side of FROM_INSN with a
+            REG_EQUAL note, the original use of the dying register
+            will not have been combined into I3 and I2.  In such cases,
+            FROM_INSN is guaranteed to be the first of the combined
+            instructions, so we simply need to search back before
+            FROM_INSN for the previous use or set of this register,
+            then alter the notes there appropriately.
+
+            If the register is used as an input in I3, it dies there.
             Similarly for I2, if it is nonzero and adjacent to I3.
 
             If the register is not used as an input in either I3 or I2
@@ -11819,20 +12132,31 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
             use of A and put the death note there.  */
 
          if (from_insn
-             && GET_CODE (from_insn) == CALL_INSN
-             && find_reg_fusage (from_insn, USE, XEXP (note, 0)))
-           place = from_insn;
-         else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3)))
-           place = i3;
-         else if (i2 != 0 && next_nonnote_insn (i2) == i3
-                  && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
-           place = i2;
+             && from_insn == replaced_rhs_insn
+             && !reg_overlap_mentioned_p (XEXP (note, 0), replaced_rhs_value))
+           tem = from_insn;
+         else
+           {
+             if (from_insn
+                 && CALL_P (from_insn)
+                 && find_reg_fusage (from_insn, USE, XEXP (note, 0)))
+               place = from_insn;
+             else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3)))
+               place = i3;
+             else if (i2 != 0 && next_nonnote_insn (i2) == i3
+                      && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
+               place = i2;
+             else if (rtx_equal_p (XEXP (note, 0), elim_i2)
+                      || rtx_equal_p (XEXP (note, 0), elim_i1))
+               break;
+             tem = i3;
+           }
 
          if (place == 0)
            {
              basic_block bb = this_basic_block;
 
-             for (tem = PREV_INSN (i3); place == 0; tem = PREV_INSN (tem))
+             for (tem = PREV_INSN (tem); place == 0; tem = PREV_INSN (tem))
                {
                  if (! INSN_P (tem))
                    {
@@ -11841,10 +12165,15 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                      continue;
                    }
 
-                 /* If the register is being set at TEM, see if that is all
-                    TEM is doing.  If so, delete TEM.  Otherwise, make this
-                    into a REG_UNUSED note instead.  */
-                 if (reg_set_p (XEXP (note, 0), PATTERN (tem)))
+                 /* If TEM is a (reaching) definition of the use to which the
+                    note was attached, see if that is all TEM is doing.  If so,
+                    delete TEM.  Otherwise, make this into a REG_UNUSED note
+                    instead.  Don't delete sets to global register vars.  */
+                 if ((!from_insn
+                      || INSN_CUID (tem) < INSN_CUID (from_insn))
+                     && (REGNO (XEXP (note, 0)) >= FIRST_PSEUDO_REGISTER
+                         || !global_regs[REGNO (XEXP (note, 0))])
+                     && reg_set_p (XEXP (note, 0), PATTERN (tem)))
                    {
                      rtx set = single_set (tem);
                      rtx inner_dest = 0;
@@ -11886,12 +12215,11 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                          PATTERN (tem) = pc_rtx;
                          REG_NOTES (tem) = NULL;
 
-                         distribute_notes (old_notes, tem, tem, NULL_RTX);
+                         distribute_notes (old_notes, tem, tem, NULL_RTX,
+                                           NULL_RTX, NULL_RTX);
                          distribute_links (LOG_LINKS (tem));
 
-                         PUT_CODE (tem, NOTE);
-                         NOTE_LINE_NUMBER (tem) = NOTE_INSN_DELETED;
-                         NOTE_SOURCE_FILE (tem) = 0;
+                         SET_INSN_DELETED (tem);
 
 #ifdef HAVE_cc0
                          /* Delete the setter too.  */
@@ -11902,13 +12230,11 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                              REG_NOTES (cc0_setter) = NULL;
 
                              distribute_notes (old_notes, cc0_setter,
-                                               cc0_setter, NULL_RTX);
+                                               cc0_setter, NULL_RTX,
+                                               NULL_RTX, NULL_RTX);
                              distribute_links (LOG_LINKS (cc0_setter));
 
-                             PUT_CODE (cc0_setter, NOTE);
-                             NOTE_LINE_NUMBER (cc0_setter)
-                               = NOTE_INSN_DELETED;
-                             NOTE_SOURCE_FILE (cc0_setter) = 0;
+                             SET_INSN_DELETED (cc0_setter);
                            }
 #endif
                        }
@@ -11929,7 +12255,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                        }
                    }
                  else if (reg_referenced_p (XEXP (note, 0), PATTERN (tem))
-                          || (GET_CODE (tem) == CALL_INSN
+                          || (CALL_P (tem)
                               && find_reg_fusage (tem, USE, XEXP (note, 0))))
                    {
                      place = tem;
@@ -11963,14 +12289,14 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                 was dead, there's nothing left to do.  Otherwise, we'll
                 need to do a global life update after combine.  */
              if (REG_NOTE_KIND (note) == REG_DEAD && place == 0
-                 && REGNO_REG_SET_P (bb->global_live_at_start,
+                 && REGNO_REG_SET_P (bb->il.rtl->global_live_at_start,
                                      REGNO (XEXP (note, 0))))
                SET_BIT (refresh_blocks, this_basic_block->index);
            }
 
          /* If the register is set or already dead at PLACE, we needn't do
             anything with this note if it is still a REG_DEAD note.
-            We can here if it is set at all, not if is it totally replace,
+            We check here if it is set at all, not if is it totally replaced,
             which is what `dead_or_set_p' checks, so also check for it being
             set partially.  */
 
@@ -12040,7 +12366,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                                = 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)
@@ -12080,7 +12406,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
        default:
          /* Any other notes should not be present at this point in the
             compilation.  */
-         abort ();
+         gcc_unreachable ();
        }
 
       if (place)
@@ -12090,14 +12416,14 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
        }
       else if ((REG_NOTE_KIND (note) == REG_DEAD
                || REG_NOTE_KIND (note) == REG_UNUSED)
-              && GET_CODE (XEXP (note, 0)) == REG)
+              && REG_P (XEXP (note, 0)))
        REG_N_DEATHS (REGNO (XEXP (note, 0)))--;
 
       if (place2)
        {
          if ((REG_NOTE_KIND (note) == REG_DEAD
               || REG_NOTE_KIND (note) == REG_UNUSED)
-             && GET_CODE (XEXP (note, 0)) == REG)
+             && REG_P (XEXP (note, 0)))
            REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
 
          REG_NOTES (place2) = gen_rtx_fmt_ee (GET_CODE (note),
@@ -12136,13 +12462,12 @@ distribute_links (rtx links)
         replace I3, I2, and I1 by I3 and I2.  But in that case the
         destination of I2 also remains unchanged.  */
 
-      if (GET_CODE (XEXP (link, 0)) == NOTE
+      if (NOTE_P (XEXP (link, 0))
          || (set = single_set (XEXP (link, 0))) == 0)
        continue;
 
       reg = SET_DEST (set);
       while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT
-            || GET_CODE (reg) == SIGN_EXTRACT
             || GET_CODE (reg) == STRICT_LOW_PART)
        reg = XEXP (reg, 0);
 
@@ -12165,7 +12490,7 @@ distribute_links (rtx links)
              place = insn;
            break;
          }
-       else if (GET_CODE (insn) == CALL_INSN
+       else if (CALL_P (insn)
                 && find_reg_fusage (insn, USE, reg))
          {
            place = insn;
@@ -12211,7 +12536,7 @@ unmentioned_reg_p_1 (rtx *loc, void *expr)
   rtx x = *loc;
 
   if (x != NULL_RTX
-      && (GET_CODE (x) == REG || GET_CODE (x) == MEM)
+      && (REG_P (x) || MEM_P (x))
       && ! reg_mentioned_p (x, (rtx) expr))
     return 1;
   return 0;
@@ -12233,11 +12558,10 @@ static int
 insn_cuid (rtx insn)
 {
   while (insn != 0 && INSN_UID (insn) > max_uid_cuid
-        && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == USE)
+        && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == USE)
     insn = NEXT_INSN (insn);
 
-  if (INSN_UID (insn) > max_uid_cuid)
-    abort ();
+  gcc_assert (INSN_UID (insn) <= max_uid_cuid);
 
   return INSN_CUID (insn);
 }
@@ -12245,7 +12569,7 @@ insn_cuid (rtx insn)
 void
 dump_combine_stats (FILE *file)
 {
-  fnotice
+  fprintf
     (file,
      ";; Combiner statistics: %d attempts, %d substitutions (%d requiring new space),\n;; %d successes.\n\n",
      combine_attempts, combine_merges, combine_extras, combine_successes);
@@ -12254,8 +12578,56 @@ dump_combine_stats (FILE *file)
 void
 dump_combine_total_stats (FILE *file)
 {
-  fnotice
+  fprintf
     (file,
      "\n;; Combiner totals: %d attempts, %d substitutions (%d requiring new space),\n;; %d successes.\n",
      total_attempts, total_merges, total_extras, total_successes);
 }
+\f
+
+static bool
+gate_handle_combine (void)
+{
+  return (optimize > 0);
+}
+
+/* Try combining insns through substitution.  */
+static unsigned int
+rest_of_handle_combine (void)
+{
+  int rebuild_jump_labels_after_combine
+    = combine_instructions (get_insns (), max_reg_num ());
+
+  /* Combining insns may have turned an indirect jump into a
+     direct jump.  Rebuild the JUMP_LABEL fields of jumping
+     instructions.  */
+  if (rebuild_jump_labels_after_combine)
+    {
+      timevar_push (TV_JUMP);
+      rebuild_jump_labels (get_insns ());
+      timevar_pop (TV_JUMP);
+
+      delete_dead_jumptables ();
+      cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE);
+    }
+  return 0;
+}
+
+struct tree_opt_pass pass_combine =
+{
+  "combine",                            /* name */
+  gate_handle_combine,                  /* gate */
+  rest_of_handle_combine,               /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_COMBINE,                           /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func |
+  TODO_ggc_collect,                     /* todo_flags_finish */
+  'c'                                   /* letter */
+};
+