OSDN Git Service

2007-08-05 Andrew Pinski <andrew_pinski@playstation.sony.com>
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 1361b10..3fe9a16 100644 (file)
@@ -1,12 +1,13 @@
 /* Optimize by combining instructions for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 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, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* This module is essentially the "combiner" phase of the U. of Arizona
    Portable Optimizer, but redone to work on our list-structured
@@ -49,8 +49,9 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
    we install it, delete the earlier insns, and update the data flow
    information (LOG_LINKS and REG_NOTES) for what we did.
 
-   There are a few exceptions where the dataflow information created by
-   flow.c aren't completely updated:
+   There are a few exceptions where the dataflow information isn't
+   completely updated (however this is only a local issue since it is
+   regenerated before the next pass that uses it):
 
    - reg_live_length is not updated
    - reg_n_refs is not adjusted in the rare case when a register is
@@ -102,6 +103,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "params.h"
 #include "timevar.h"
 #include "tree-pass.h"
+#include "df.h"
 
 /* Number of attempts to combine instructions in this function.  */
 
@@ -123,33 +125,24 @@ static int combine_successes;
 
 static int total_attempts, total_merges, total_extras, total_successes;
 
-\f
-/* Vector mapping INSN_UIDs to cuids.
-   The cuids are like uids but increase monotonically always.
-   Combine always uses cuids so that it can compare them.
-   But actually renumbering the uids, which we used to do,
-   proves to be a bad idea because it makes it hard to compare
-   the dumps produced by earlier passes with those from later passes.  */
-
-static int *uid_cuid;
-static int max_uid_cuid;
-
-/* Get the cuid of an insn.  */
+/* combine_instructions may try to replace the right hand side of the
+   second instruction with the value of an associated REG_EQUAL note
+   before throwing it at try_combine.  That is problematic when there
+   is a REG_DEAD note for a register used in the old right hand side
+   and can cause distribute_notes to do wrong things.  This is the
+   second instruction if it has been so modified, null otherwise.  */
 
-#define INSN_CUID(INSN) \
-(INSN_UID (INSN) > max_uid_cuid ? insn_cuid (INSN) : uid_cuid[INSN_UID (INSN)])
+static rtx i2mod;
 
-/* In case BITS_PER_WORD == HOST_BITS_PER_WIDE_INT, shifting by
-   BITS_PER_WORD would invoke undefined behavior.  Work around it.  */
+/* When I2MOD is nonnull, this is a copy of the old right hand side.  */
 
-#define UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD(val) \
-  (((unsigned HOST_WIDE_INT) (val) << (BITS_PER_WORD - 1)) << 1)
+static rtx i2mod_old_rhs;
 
-/* Maximum register number, which is the size of the tables below.  */
+/* When I2MOD is nonnull, this is a copy of the new right hand side.  */
 
-static unsigned int combine_max_regno;
-
-struct reg_stat {
+static rtx i2mod_new_rhs;
+\f
+typedef struct reg_stat_struct {
   /* Record last point of death of (hard or pseudo) register n.  */
   rtx                          last_death;
 
@@ -167,7 +160,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:
 
@@ -220,7 +213,7 @@ struct reg_stat {
 
   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
@@ -243,19 +236,35 @@ struct reg_stat {
   unsigned char                        sign_bit_copies;
 
   unsigned HOST_WIDE_INT       nonzero_bits;
-};
 
-static struct reg_stat *reg_stat;
+  /* 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.  */
 
-/* Record the cuid of the last insn that invalidated memory
+  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;
+} reg_stat_type;
+
+DEF_VEC_O(reg_stat_type);
+DEF_VEC_ALLOC_O(reg_stat_type,heap);
+
+static VEC(reg_stat_type,heap) *reg_stat;
+
+/* Record the luid of the last insn that invalidated memory
    (anything that writes memory, and subroutine calls, but not pushes).  */
 
 static int mem_last_set;
 
-/* Record the cuid of the last CALL_INSN
+/* Record the luid of the last CALL_INSN
    so we can tell whether a potential combination crosses any calls.  */
 
-static int last_call_cuid;
+static int last_call_luid;
 
 /* When `subst' is called, this is the insn that is being modified
    (by combining in a previous insn).  The PATTERN of this insn
@@ -265,14 +274,14 @@ static int last_call_cuid;
 
 static rtx subst_insn;
 
-/* This is the lowest CUID that `subst' is currently dealing with.
+/* This is the lowest LUID that `subst' is currently dealing with.
    get_last_value will not return a value if the register was set at or
-   after this CUID.  If not for this mechanism, we could get confused if
+   after this LUID.  If not for this mechanism, we could get confused if
    I2 or I1 in try_combine were an insn that used the old value of a register
    to obtain a new value.  In that case, we might erroneously get the
    new value of the register when we wanted the old one.  */
 
-static int subst_low_cuid;
+static int subst_low_luid;
 
 /* This contains any hard registers that are used in newpat; reg_dead_at_p
    must consider all these registers to be always live.  */
@@ -288,24 +297,32 @@ static rtx added_links_insn;
 /* Basic block in which we are performing combines.  */
 static basic_block this_basic_block;
 
-/* A bitmap indicating which blocks had registers go dead at entry.
-   After combine, we'll need to re-do global life analysis with
-   those blocks as starting points.  */
-static sbitmap refresh_blocks;
 \f
+/* Length of the currently allocated uid_insn_cost array.  */
+
+static int max_uid_known;
+
 /* 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.  */
+/* The following array records the LOG_LINKS for every insn in the
+   instruction stream as an INSN_LIST rtx.  */
 
-static int last_insn_cost;
+static rtx *uid_log_links;
 
-/* Incremented for each label.  */
+#define INSN_COST(INSN)                (uid_insn_cost[INSN_UID (INSN)])
+#define LOG_LINKS(INSN)                (uid_log_links[INSN_UID (INSN)])
+
+/* Incremented for each basic block.  */
 
 static int label_tick;
 
+/* Reset to label_tick for each label.  */
+
+static int label_tick_ebb_start;
+
 /* Mode used to compute significance in reg_stat[].nonzero_bits.  It is the
    largest integer mode that can fit in HOST_BITS_PER_WIDE_INT.  */
 
@@ -321,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.
@@ -352,18 +368,18 @@ static struct undobuf undobuf;
 
 static int n_occurrences;
 
-static rtx reg_nonzero_bits_for_combine (rtx, enum machine_mode, rtx,
+static rtx reg_nonzero_bits_for_combine (const_rtx, enum machine_mode, const_rtx,
                                         enum machine_mode,
                                         unsigned HOST_WIDE_INT,
                                         unsigned HOST_WIDE_INT *);
-static rtx reg_num_sign_bit_copies_for_combine (rtx, enum machine_mode, rtx,
+static rtx reg_num_sign_bit_copies_for_combine (const_rtx, enum machine_mode, const_rtx,
                                                enum machine_mode,
                                                unsigned int, unsigned int *);
 static void do_SUBST (rtx *, rtx);
 static void do_SUBST_INT (int *, int);
 static void init_reg_last (void);
-static void setup_incoming_promotions (void);
-static void set_nonzero_bits_and_sign_copies (rtx, rtx, void *);
+static void setup_incoming_promotions (rtx);
+static void set_nonzero_bits_and_sign_copies (rtx, const_rtx, void *);
 static int cant_combine_insn_p (rtx);
 static int can_combine_p (rtx, rtx, rtx, rtx, rtx *, rtx *);
 static int combinable_i3pat (rtx, rtx *, rtx, rtx, int, rtx *);
@@ -378,7 +394,7 @@ static rtx simplify_if_then_else (rtx);
 static rtx simplify_set (rtx);
 static rtx simplify_logical (rtx);
 static rtx expand_compound_operation (rtx);
-static rtx expand_field_assignment (rtx);
+static const_rtx expand_field_assignment (const_rtx);
 static rtx make_extraction (enum machine_mode, rtx, HOST_WIDE_INT,
                            rtx, unsigned HOST_WIDE_INT, int, int, int);
 static rtx extract_left_shift (rtx, int);
@@ -408,23 +424,25 @@ static rtx gen_lowpart_for_combine (enum machine_mode, rtx);
 static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *);
 static void update_table_tick (rtx);
 static void record_value_for_reg (rtx, rtx, rtx);
-static void check_promoted_subreg (rtx, rtx);
-static void record_dead_and_set_regs_1 (rtx, rtx, void *);
+static void check_conversions (rtx, rtx);
+static void record_dead_and_set_regs_1 (rtx, const_rtx, void *);
 static void record_dead_and_set_regs (rtx);
 static int get_last_value_validate (rtx *, rtx, int, int);
-static rtx get_last_value (rtx);
-static int use_crosses_set_p (rtx, int);
-static void reg_dead_at_p_1 (rtx, rtx, void *);
+static rtx get_last_value (const_rtx);
+static int use_crosses_set_p (const_rtx, int);
+static void reg_dead_at_p_1 (rtx, const_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, 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 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, const_rtx);
+static rtx gen_lowpart_or_truncate (enum machine_mode, rtx);
 \f
 
 /* It is not safe to use ordinary gen_lowpart in combine.
@@ -442,9 +460,191 @@ static bool unmentioned_reg_p (rtx, rtx);
 #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
+/* Try to split PATTERN found in INSN.  This returns NULL_RTX if
+   PATTERN can not be split.  Otherwise, it returns an insn sequence.
+   This is a wrapper around split_insns which ensures that the
+   reg_stat vector is made larger if the splitter creates a new
+   register.  */
+
+static rtx
+combine_split_insns (rtx pattern, rtx insn)
+{
+  rtx ret;
+  unsigned int nregs;
+
+  ret = split_insns (pattern, insn);
+  nregs = max_reg_num ();
+  if (nregs > VEC_length (reg_stat_type, reg_stat))
+    VEC_safe_grow_cleared (reg_stat_type, heap, reg_stat, nregs);
+  return ret;
+}
+
+/* This is used by find_single_use to locate an rtx in LOC that
+   contains exactly one use of DEST, which is typically either a REG
+   or CC0.  It returns a pointer to the innermost rtx expression
+   containing DEST.  Appearances of DEST that are being used to
+   totally replace it are not counted.  */
+
+static rtx *
+find_single_use_1 (rtx dest, rtx *loc)
+{
+  rtx x = *loc;
+  enum rtx_code code = GET_CODE (x);
+  rtx *result = NULL;
+  rtx *this_result;
+  int i;
+  const char *fmt;
+
+  switch (code)
+    {
+    case CONST_INT:
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+    case CONST_DOUBLE:
+    case CONST_VECTOR:
+    case CLOBBER:
+      return 0;
+
+    case SET:
+      /* If the destination is anything other than CC0, PC, a REG or a SUBREG
+        of a REG that occupies all of the REG, the insn uses DEST if
+        it is mentioned in the destination or the source.  Otherwise, we
+        need just check the source.  */
+      if (GET_CODE (SET_DEST (x)) != CC0
+         && GET_CODE (SET_DEST (x)) != PC
+         && !REG_P (SET_DEST (x))
+         && ! (GET_CODE (SET_DEST (x)) == SUBREG
+               && REG_P (SUBREG_REG (SET_DEST (x)))
+               && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x))))
+                     + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
+                   == ((GET_MODE_SIZE (GET_MODE (SET_DEST (x)))
+                        + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))))
+       break;
+
+      return find_single_use_1 (dest, &SET_SRC (x));
+
+    case MEM:
+    case SUBREG:
+      return find_single_use_1 (dest, &XEXP (x, 0));
+
+    default:
+      break;
+    }
+
+  /* If it wasn't one of the common cases above, check each expression and
+     vector of this code.  Look for a unique usage of DEST.  */
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       {
+         if (dest == XEXP (x, i)
+             || (REG_P (dest) && REG_P (XEXP (x, i))
+                 && REGNO (dest) == REGNO (XEXP (x, i))))
+           this_result = loc;
+         else
+           this_result = find_single_use_1 (dest, &XEXP (x, i));
+
+         if (result == NULL)
+           result = this_result;
+         else if (this_result)
+           /* Duplicate usage.  */
+           return NULL;
+       }
+      else if (fmt[i] == 'E')
+       {
+         int j;
+
+         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+           {
+             if (XVECEXP (x, i, j) == dest
+                 || (REG_P (dest)
+                     && REG_P (XVECEXP (x, i, j))
+                     && REGNO (XVECEXP (x, i, j)) == REGNO (dest)))
+               this_result = loc;
+             else
+               this_result = find_single_use_1 (dest, &XVECEXP (x, i, j));
+
+             if (result == NULL)
+               result = this_result;
+             else if (this_result)
+               return NULL;
+           }
+       }
+    }
+
+  return result;
+}
+
+
+/* See if DEST, produced in INSN, is used only a single time in the
+   sequel.  If so, return a pointer to the innermost rtx expression in which
+   it is used.
+
+   If PLOC is nonzero, *PLOC is set to the insn containing the single use.
+
+   If DEST is cc0_rtx, we look only at the next insn.  In that case, we don't
+   care about REG_DEAD notes or LOG_LINKS.
+
+   Otherwise, we find the single use by finding an insn that has a
+   LOG_LINKS pointing at INSN and has a REG_DEAD note for DEST.  If DEST is
+   only referenced once in that insn, we know that it must be the first
+   and last insn referencing DEST.  */
+
+static rtx *
+find_single_use (rtx dest, rtx insn, rtx *ploc)
+{
+  rtx next;
+  rtx *result;
+  rtx link;
+
+#ifdef HAVE_cc0
+  if (dest == cc0_rtx)
+    {
+      next = NEXT_INSN (insn);
+      if (next == 0
+         || (!NONJUMP_INSN_P (next) && !JUMP_P (next)))
+       return 0;
+
+      result = find_single_use_1 (dest, &PATTERN (next));
+      if (result && ploc)
+       *ploc = next;
+      return result;
+    }
+#endif
+
+  if (!REG_P (dest))
+    return 0;
+
+  for (next = next_nonnote_insn (insn);
+       next != 0 && !LABEL_P (next);
+       next = next_nonnote_insn (next))
+    if (INSN_P (next) && dead_or_set_p (next, dest))
+      {
+       for (link = LOG_LINKS (next); link; link = XEXP (link, 1))
+         if (XEXP (link, 0) == insn)
+           break;
+
+       if (link)
+         {
+           result = find_single_use_1 (dest, &PATTERN (next));
+           if (ploc)
+             *ploc = next;
+           return result;
+         }
+      }
+
+  return 0;
+}
+\f
 /* Substitute NEWVAL, an rtx expression, into INTO, a place in some
    insn.  The substitution can be undone by undo_all.  If INTO is already
    set to NEWVAL, do not record this change.  Because computing NEWVAL might
@@ -488,9 +688,9 @@ do_SUBST (rtx *into, rtx newval)
   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;
@@ -516,9 +716,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;
@@ -527,31 +727,60 @@ 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.  */
+   patterns NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to
+   insn_rtx_cost that the original instruction sequence I1, I2, I3 and
+   undobuf.other_insn.  Note that I1 and/or NEWI2PAT may be NULL_RTX. 
+   NEWOTHERPAT and undobuf.other_insn may also both 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)
+combine_validate_cost (rtx i1, rtx i2, rtx i3, rtx newpat, rtx newi2pat,
+                      rtx newotherpat)
 {
   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;
+  i2_cost = INSN_COST (i2);
+  i3_cost = INSN_COST (i3);
 
   if (i1)
     {
-      i1_cost = INSN_UID (i1) <= last_insn_cost
-               ? uid_insn_cost[INSN_UID (i1)] : 0;
+      i1_cost = INSN_COST (i1);
       old_cost = (i1_cost > 0 && i2_cost > 0 && i3_cost > 0)
                 ? i1_cost + i2_cost + i3_cost : 0;
     }
@@ -579,9 +808,8 @@ combine_validate_cost (rtx i1, rtx i2, rtx i3, rtx newpat, rtx newi2pat)
     {
       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));
+      old_other_cost = INSN_COST (undobuf.other_insn);
+      new_other_cost = insn_rtx_cost (newotherpat);
       if (old_other_cost > 0 && new_other_cost > 0)
        {
          old_cost += old_other_cost;
@@ -628,54 +856,201 @@ combine_validate_cost (rtx i1, rtx i2, rtx i3, rtx newpat, rtx newi2pat)
     }
 
   /* 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;
+  INSN_COST (i2) = new_i2_cost;
+  INSN_COST (i3) = new_i3_cost;
   if (i1)
-    uid_insn_cost[INSN_UID (i1)] = 0;
+    INSN_COST (i1) = 0;
 
   return true;
 }
+
+
+/* Delete any insns that copy a register to itself.  */
+
+static void
+delete_noop_moves (void)
+{
+  rtx insn, next;
+  basic_block bb;
+
+  FOR_EACH_BB (bb)
+    {
+      for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); insn = next)
+       {
+         next = NEXT_INSN (insn);
+         if (INSN_P (insn) && noop_move_p (insn))
+           {
+             rtx note;
+
+             /* If we're about to remove the first insn of a libcall
+                then move the libcall note to the next real insn and
+                update the retval note.  */
+             if ((note = find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+                      && XEXP (note, 0) != insn)
+               {
+                 rtx new_libcall_insn = next_real_insn (insn);
+                 rtx retval_note = find_reg_note (XEXP (note, 0),
+                                                  REG_RETVAL, NULL_RTX);
+                 REG_NOTES (new_libcall_insn)
+                   = gen_rtx_INSN_LIST (REG_LIBCALL, XEXP (note, 0),
+                                        REG_NOTES (new_libcall_insn));
+                 XEXP (retval_note, 0) = new_libcall_insn;
+               }
+
+             if (dump_file)
+               fprintf (dump_file, "deleting noop move %d\n", INSN_UID (insn));
+
+             delete_insn_and_edges (insn);
+           }
+       }
+    }
+}
+
+\f
+/* Fill in log links field for all insns.  */
+
+static void
+create_log_links (void)
+{
+  basic_block bb;
+  rtx *next_use, insn;
+  struct df_ref **def_vec, **use_vec;
+
+  next_use = XCNEWVEC (rtx, max_reg_num ());
+
+  /* Pass through each block from the end, recording the uses of each
+     register and establishing log links when def is encountered.
+     Note that we do not clear next_use array in order to save time,
+     so we have to test whether the use is in the same basic block as def.
+              
+     There are a few cases below when we do not consider the definition or
+     usage -- these are taken from original flow.c did. Don't ask me why it is
+     done this way; I don't know and if it works, I don't want to know.  */
+
+  FOR_EACH_BB (bb)
+    {
+      FOR_BB_INSNS_REVERSE (bb, insn)
+        {
+          if (!INSN_P (insn))
+            continue;
+
+         /* Log links are created only once.  */
+         gcc_assert (!LOG_LINKS (insn));
+
+          for (def_vec = DF_INSN_DEFS (insn); *def_vec; def_vec++)
+            {
+             struct df_ref *def = *def_vec;
+              int regno = DF_REF_REGNO (def);
+              rtx use_insn;
+
+              if (!next_use[regno])
+                continue;
+
+              /* Do not consider if it is pre/post modification in MEM.  */
+              if (DF_REF_FLAGS (def) & DF_REF_PRE_POST_MODIFY)
+                continue;
+
+              /* Do not make the log link for frame pointer.  */
+              if ((regno == FRAME_POINTER_REGNUM
+                   && (! reload_completed || frame_pointer_needed))
+#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+                  || (regno == HARD_FRAME_POINTER_REGNUM
+                      && (! reload_completed || frame_pointer_needed))
+#endif
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+                  || (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
+#endif
+                  )
+                continue;
+
+              use_insn = next_use[regno];
+              if (BLOCK_FOR_INSN (use_insn) == bb)
+                {
+                  /* flow.c claimed:
+
+                     We don't build a LOG_LINK for hard registers contained
+                     in ASM_OPERANDs.  If these registers get replaced,
+                     we might wind up changing the semantics of the insn,
+                     even if reload can make what appear to be valid
+                     assignments later.  */
+                  if (regno >= FIRST_PSEUDO_REGISTER
+                      || asm_noperands (PATTERN (use_insn)) < 0)
+                    LOG_LINKS (use_insn) =
+                      alloc_INSN_LIST (insn, LOG_LINKS (use_insn));
+                }
+              next_use[regno] = NULL_RTX;
+            }
+
+          for (use_vec = DF_INSN_USES (insn); *use_vec; use_vec++)
+            {
+             struct df_ref *use = *use_vec;
+             int regno = DF_REF_REGNO (use);
+
+              /* Do not consider the usage of the stack pointer
+                by function call.  */
+              if (DF_REF_FLAGS (use) & DF_REF_CALL_STACK_USAGE)
+                continue;
+
+              next_use[regno] = insn;
+            }
+        }
+    }
+
+  free (next_use);
+}
+
+/* Clear LOG_LINKS fields of insns.  */
+
+static void
+clear_log_links (void)
+{
+  rtx insn;
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    if (INSN_P (insn))
+      free_INSN_LIST_list (&LOG_LINKS (insn));
+}
+
+
+
 \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;
 #ifdef HAVE_cc0
   rtx prev;
 #endif
-  int i;
-  unsigned int j = 0;
   rtx links, nextlinks;
-  sbitmap_iterator sbi;
+  rtx first;
 
   int new_direct_jump_p = 0;
 
+  for (first = f; first && !INSN_P (first); )
+    first = NEXT_INSN (first);
+  if (!first)
+    return 0;
+
   combine_attempts = 0;
   combine_merges = 0;
   combine_extras = 0;
   combine_successes = 0;
 
-  combine_max_regno = nregs;
-
   rtl_hooks = combine_rtl_hooks;
 
-  reg_stat = xcalloc (nregs, sizeof (struct reg_stat));
+  VEC_safe_grow_cleared (reg_stat_type, heap, reg_stat, nregs);
 
   init_recog_no_volatile ();
 
-  /* Compute maximum uid value so uid_cuid can be allocated.  */
-
-  for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
-    if (INSN_UID (insn) > i)
-      i = INSN_UID (insn);
-
-  uid_cuid = xmalloc ((i + 1) * sizeof (int));
-  max_uid_cuid = i;
+  /* Allocate array for insn info.  */
+  max_uid_known = get_max_uid ();
+  uid_log_links = XCNEWVEC (rtx, max_uid_known + 1);
+  uid_insn_cost = XCNEWVEC (int, max_uid_known + 1);
 
   nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
 
@@ -684,85 +1059,74 @@ combine_instructions (rtx f, unsigned int nregs)
 
   nonzero_sign_valid = 0;
 
-  /* Compute the mapping from uids to cuids.
-     Cuids are numbers assigned to insns, like uids,
-     except that cuids increase monotonically through the code.
-
-     Scan all SETs and see if we can deduce anything about what
+  /* Scan all SETs and see if we can deduce anything about what
      bits are known to be zero for some registers and how many copies
      of the sign bit are known to exist for those registers.
 
      Also set any known values so that we can use it while searching
      for what bits are known to be set.  */
 
-  label_tick = 1;
-
-  setup_incoming_promotions ();
+  label_tick = label_tick_ebb_start = 1;
 
-  refresh_blocks = sbitmap_alloc (last_basic_block);
-  sbitmap_zero (refresh_blocks);
+  setup_incoming_promotions (first);
 
-  /* Allocate array of current insn_rtx_costs.  */
-  uid_insn_cost = xcalloc (max_uid_cuid + 1, sizeof (int));
-  last_insn_cost = max_uid_cuid;
-
-  for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
+  create_log_links ();
+  FOR_EACH_BB (this_basic_block)
     {
-      uid_cuid[INSN_UID (insn)] = ++i;
-      subst_low_cuid = i;
-      subst_insn = insn;
+      last_call_luid = 0;
+      mem_last_set = -1;
+      label_tick++;
+      FOR_BB_INSNS (this_basic_block, insn)
+        if (INSN_P (insn) && BLOCK_FOR_INSN (insn))
+         {
+            subst_low_luid = DF_INSN_LUID (insn);
+            subst_insn = insn;
 
-      if (INSN_P (insn))
-       {
-         note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies,
-                      NULL);
-         record_dead_and_set_regs (insn);
+           note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies,
+                        insn);
+           record_dead_and_set_regs (insn);
 
 #ifdef AUTO_INC_DEC
-         for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
-           if (REG_NOTE_KIND (links) == REG_INC)
-             set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX,
-                                               NULL);
+           for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
+             if (REG_NOTE_KIND (links) == REG_INC)
+               set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX,
+                                                 insn);
 #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 (LABEL_P (insn))
-       label_tick++;
+           /* Record the current insn_rtx_cost of this instruction.  */
+           if (NONJUMP_INSN_P (insn))
+             INSN_COST (insn) = insn_rtx_cost (PATTERN (insn));
+           if (dump_file)
+             fprintf(dump_file, "insn_cost %d: %d\n",
+                   INSN_UID (insn), INSN_COST (insn));
+         }
+       else if (LABEL_P (insn))
+         label_tick_ebb_start = label_tick;
     }
 
   nonzero_sign_valid = 1;
 
   /* Now scan all the insns in forward order.  */
 
-  label_tick = 1;
-  last_call_cuid = 0;
-  mem_last_set = 0;
+  label_tick = label_tick_ebb_start = 1;
   init_reg_last ();
-  setup_incoming_promotions ();
+  setup_incoming_promotions (first);
 
   FOR_EACH_BB (this_basic_block)
     {
+      last_call_luid = 0;
+      mem_last_set = -1;
+      label_tick++;
       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 (LABEL_P (insn))
-           label_tick++;
-
-         else if (INSN_P (insn))
+         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.  */
 
@@ -881,8 +1245,12 @@ combine_instructions (rtx f, unsigned int nregs)
                         be deleted or recognized by try_combine.  */
                      rtx orig = SET_SRC (set);
                      SET_SRC (set) = note;
-                     next = try_combine (insn, temp, NULL_RTX,
+                     i2mod = temp;
+                     i2mod_old_rhs = copy_rtx (orig);
+                     i2mod_new_rhs = copy_rtx (note);
+                     next = try_combine (insn, i2mod, NULL_RTX,
                                          &new_direct_jump_p);
+                     i2mod = NULL_RTX;
                      if (next)
                        goto retry;
                      SET_SRC (set) = orig;
@@ -895,24 +1263,20 @@ combine_instructions (rtx f, unsigned int nregs)
            retry:
              ;
            }
+         else if (LABEL_P (insn))
+           label_tick_ebb_start = label_tick;
        }
     }
-  clear_bb_flags ();
 
-  EXECUTE_IF_SET_IN_SBITMAP (refresh_blocks, 0, j, sbi)
-    BASIC_BLOCK (j)->flags |= BB_DIRTY;
+  clear_log_links ();
+  clear_bb_flags ();
   new_direct_jump_p |= purge_all_dead_edges ();
   delete_noop_moves ();
 
-  update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
-                                   PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
-                                   | PROP_KILL_DEAD_CODE);
-
   /* Clean up.  */
-  sbitmap_free (refresh_blocks);
+  free (uid_log_links);
   free (uid_insn_cost);
-  free (reg_stat);
-  free (uid_cuid);
+  VEC_free (reg_stat_type, heap, reg_stat);
 
   {
     struct undo *undo, *next;
@@ -944,36 +1308,44 @@ static void
 init_reg_last (void)
 {
   unsigned int i;
-  for (i = 0; i < combine_max_regno; i++)
-    memset (reg_stat + i, 0, offsetof (struct reg_stat, sign_bit_copies));
+  reg_stat_type *p;
+
+  for (i = 0; VEC_iterate (reg_stat_type, reg_stat, i, p); ++i)
+    memset (p, 0, offsetof (reg_stat_type, sign_bit_copies));
 }
 \f
 /* Set up any promoted values for incoming argument registers.  */
 
 static void
-setup_incoming_promotions (void)
+setup_incoming_promotions (rtx first)
 {
-  unsigned int regno;
-  rtx reg;
-  enum machine_mode mode;
-  int unsignedp;
-  rtx first = get_insns ();
+  tree arg;
+
+  if (!targetm.calls.promote_function_args (TREE_TYPE (cfun->decl)))
+    return;
 
-  if (targetm.calls.promote_function_args (TREE_TYPE (cfun->decl)))
+  for (arg = DECL_ARGUMENTS (current_function_decl); arg;
+       arg = TREE_CHAIN (arg))
     {
-      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-       /* Check whether this register can hold an incoming pointer
-          argument.  FUNCTION_ARG_REGNO_P tests outgoing register
-          numbers, so translate if necessary due to register windows.  */
-       if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (regno))
-           && (reg = promoted_input_arg (regno, &mode, &unsignedp)) != 0)
-         {
-           record_value_for_reg
-             (reg, first, gen_rtx_fmt_e ((unsignedp ? ZERO_EXTEND
-                                          : SIGN_EXTEND),
-                                         GET_MODE (reg),
-                                         gen_rtx_CLOBBER (mode, const0_rtx)));
-         }
+      rtx reg = DECL_INCOMING_RTL (arg);
+
+      if (!REG_P (reg))
+       continue;
+
+      if (TYPE_MODE (DECL_ARG_TYPE (arg)) == TYPE_MODE (TREE_TYPE (arg)))
+       {
+         enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg));
+         int uns = TYPE_UNSIGNED (TREE_TYPE (arg));
+
+         mode = promote_mode (TREE_TYPE (arg), mode, &uns, 1);
+         if (mode == GET_MODE (reg) && mode != DECL_MODE (arg))
+           {
+             rtx x;
+             x = gen_rtx_CLOBBER (DECL_MODE (arg), const0_rtx);
+             x = gen_rtx_fmt_e ((uns ? ZERO_EXTEND : SIGN_EXTEND), mode, x);
+             record_value_for_reg (reg, first, x);
+           }
+       }
     }
 }
 \f
@@ -989,9 +1361,9 @@ setup_incoming_promotions (void)
    by any set of X.  */
 
 static void
-set_nonzero_bits_and_sign_copies (rtx x, rtx set,
-                                 void *data ATTRIBUTE_UNUSED)
+set_nonzero_bits_and_sign_copies (rtx x, const_rtx set, void *data)
 {
+  rtx insn = (rtx) data;
   unsigned int num;
 
   if (REG_P (x)
@@ -999,16 +1371,51 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set,
       /* 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->il.rtl->global_live_at_start, REGNO (x))
+           (DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), REGNO (x))
       && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
     {
+      reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
+
       if (set == 0 || GET_CODE (set) == CLOBBER)
        {
-         reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x));
-         reg_stat[REGNO (x)].sign_bit_copies = 1;
+         rsp->nonzero_bits = GET_MODE_MASK (GET_MODE (x));
+         rsp->sign_bit_copies = 1;
          return;
        }
 
+      /* If this register is being initialized using itself, and the
+        register is uninitialized in this basic block, and there are
+        no LOG_LINKS which set the register, then part of the
+        register is uninitialized.  In that case we can't assume
+        anything about the number of nonzero bits.
+
+        ??? We could do better if we checked this in
+        reg_{nonzero_bits,num_sign_bit_copies}_for_combine.  Then we
+        could avoid making assumptions about the insn which initially
+        sets the register, while still using the information in other
+        insns.  We would have to be careful to check every insn
+        involved in the combination.  */
+
+      if (insn
+         && reg_referenced_p (x, PATTERN (insn))
+         && !REGNO_REG_SET_P (DF_LR_IN (BLOCK_FOR_INSN (insn)),
+                              REGNO (x)))
+       {
+         rtx link;
+
+         for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
+           {
+             if (dead_or_set_p (XEXP (link, 0), x))
+               break;
+           }
+         if (!link)
+           {
+             rsp->nonzero_bits = GET_MODE_MASK (GET_MODE (x));
+             rsp->sign_bit_copies = 1;
+             return;
+           }
+       }
+
       /* If this is a complex assignment, see if we can convert it into a
         simple assignment.  */
       set = expand_field_assignment (set);
@@ -1046,18 +1453,17 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set,
 #endif
 
          /* Don't call nonzero_bits if it cannot change anything.  */
-         if (reg_stat[REGNO (x)].nonzero_bits != ~(unsigned HOST_WIDE_INT) 0)
-           reg_stat[REGNO (x)].nonzero_bits
-             |= nonzero_bits (src, nonzero_bits_mode);
+         if (rsp->nonzero_bits != ~(unsigned HOST_WIDE_INT) 0)
+           rsp->nonzero_bits |= nonzero_bits (src, nonzero_bits_mode);
          num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x));
-         if (reg_stat[REGNO (x)].sign_bit_copies == 0
-             || reg_stat[REGNO (x)].sign_bit_copies > num)
-           reg_stat[REGNO (x)].sign_bit_copies = num;
+         if (rsp->sign_bit_copies == 0
+             || rsp->sign_bit_copies > num)
+           rsp->sign_bit_copies = num;
        }
       else
        {
-         reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x));
-         reg_stat[REGNO (x)].sign_bit_copies = 1;
+         rsp->nonzero_bits = GET_MODE_MASK (GET_MODE (x));
+         rsp->sign_bit_copies = 1;
        }
     }
 }
@@ -1077,7 +1483,8 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
               rtx *pdest, rtx *psrc)
 {
   int i;
-  rtx set = 0, src, dest;
+  const_rtx set = 0;
+  rtx src, dest;
   rtx p;
 #ifdef AUTO_INC_DEC
   rtx link;
@@ -1237,7 +1644,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
       || (! all_adjacent
          && (((!MEM_P (src)
                || ! find_reg_note (insn, REG_EQUIV, src))
-              && use_crosses_set_p (src, INSN_CUID (insn)))
+              && use_crosses_set_p (src, DF_INSN_LUID (insn)))
              || (GET_CODE (src) == ASM_OPERANDS && MEM_VOLATILE_P (src))
              || GET_CODE (src) == UNSPEC_VOLATILE))
       /* If there is a REG_NO_CONFLICT note for DEST in I3 or SUCC, we get
@@ -1249,7 +1656,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
         and it is a pain to update that information.
         Exception: if source is a constant, moving it later can't hurt.
         Accept that special case, because it helps -fforce-addr a lot.  */
-      || (INSN_CUID (insn) < last_call_cuid && ! CONSTANT_P (src)))
+      || (DF_INSN_LUID (insn) < last_call_luid && ! CONSTANT_P (src)))
     return 0;
 
   /* DEST must either be a REG or CC0.  */
@@ -1286,7 +1693,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
     for (i = XVECLEN (PATTERN (i3), 0) - 1; i >= 0; i--)
       if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER)
        {
-          /* Don't substitute for a register intended as a clobberable
+         /* 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))
@@ -1313,10 +1720,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;
     }
 
@@ -1387,12 +1794,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
@@ -1586,7 +1993,7 @@ struct likely_spilled_retval_info
 /* 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)
+likely_spilled_retval_1 (rtx x, const_rtx set, void *data)
 {
   struct likely_spilled_retval_info *info = data;
   unsigned regno, nregs;
@@ -1605,7 +2012,7 @@ likely_spilled_retval_1 (rtx x, rtx set, void *data)
     new_mask >>= info->regno - regno;
   else
     new_mask <<= regno - info->regno;
-  info->mask &= new_mask;
+  info->mask &= ~new_mask;
 }
 
 /* Return nonzero iff part of the return value is live during INSN, and
@@ -1641,7 +2048,8 @@ likely_spilled_retval_p (rtx insn)
   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);
+    if (INSN_P (p))
+      note_stores (PATTERN (p), likely_spilled_retval_1, &info);
   mask = info.mask;
 
   /* Check if any of the (probably) live return value registers is
@@ -1664,23 +2072,15 @@ likely_spilled_retval_p (rtx insn)
 static void
 adjust_for_new_dest (rtx insn)
 {
-  rtx *loc;
-
   /* For notes, be conservative and simply remove them.  */
-  loc = &REG_NOTES (insn);
-  while (*loc)
-    {
-      enum reg_note kind = REG_NOTE_KIND (*loc);
-      if (kind == REG_EQUAL || kind == REG_EQUIV)
-       *loc = XEXP (*loc, 1);
-      else
-       loc = &XEXP (*loc, 1);
-    }
+  remove_reg_equal_equiv_notes (insn);
 
   /* The new insn will have a destination that was previously the destination
      of an insn just above it.  Call distribute_links to make a LOG_LINK from
      the next use of that destination.  */
   distribute_links (gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX));
+
+  df_insn_rescan (insn);
 }
 
 /* Return TRUE if combine can reuse reg X in mode MODE.
@@ -1706,6 +2106,27 @@ can_change_dest_mode (rtx x, int added_sets, enum machine_mode mode)
          && !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.
@@ -1743,8 +2164,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   rtx i3dest_killed = 0;
   /* SET_DEST and SET_SRC of I2 and I1.  */
   rtx i2dest, i2src, i1dest = 0, i1src = 0;
-  /* PATTERN (I2), or a copy of it in certain cases.  */
-  rtx i2pat;
+  /* PATTERN (I1) and PATTERN (I2), or a copy of it in certain cases.  */
+  rtx i1pat = 0, i2pat = 0;
   /* 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;
@@ -1760,6 +2181,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   int maxreg;
   rtx temp;
   rtx link;
+  rtx other_pat = 0;
+  rtx new_other_notes;
   int i;
 
   /* Exit early if one of the insns involved can't be used for
@@ -1787,7 +2210,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
   /* If I1 and I2 both feed I3, they can be in any order.  To simplify the
      code below, set I1 to be the earlier of the two insns.  */
-  if (i1 && INSN_CUID (i1) > INSN_CUID (i2))
+  if (i1 && DF_INSN_LUID (i1) > DF_INSN_LUID (i2))
     temp = i1, i1 = i2, i2 = temp;
 
   added_links_insn = 0;
@@ -1852,7 +2275,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
              combine_merges++;
 
              subst_insn = i3;
-             subst_low_cuid = INSN_CUID (i2);
+             subst_low_luid = DF_INSN_LUID (i2);
 
              added_sets_2 = added_sets_1 = 0;
              i2dest = SET_SRC (PATTERN (i3));
@@ -1870,74 +2293,140 @@ 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)
-      && REG_P (SET_DEST (temp))
-      && 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.  */
-         gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD);
-
-         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
+         && (GET_MODE_BITSIZE (GET_MODE (SET_DEST (temp)))
+             <= HOST_BITS_PER_WIDE_INT * 2))
        {
-         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.  */
-       gcc_unreachable ();
+         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);
-      i2dest_killed = dead_or_set_p (i2, i2dest);
+         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);
+           }
 
-      SUBST (SET_SRC (temp),
-            immed_double_const (lo, hi, GET_MODE (SET_DEST (temp))));
+         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;
+
+         combine_merges++;
+         subst_insn = i3;
+         subst_low_luid = DF_INSN_LUID (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
@@ -1947,7 +2436,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.)
 
@@ -1973,14 +2462,13 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
       if (i == 1)
        {
          /* We make I1 with the same INSN_UID as I2.  This gives it
-            the same INSN_CUID for value tracking.  Our fake I1 will
+            the same DF_INSN_LUID for value tracking.  Our fake I1 will
             never appear in the insn stream so giving it the same INSN_UID
             as I2 will not cause a problem.  */
 
          i1 = gen_rtx_INSN (VOIDmode, INSN_UID (i2), NULL_RTX, i2,
                             BLOCK_FOR_INSN (i2), INSN_LOCATOR (i2),
-                            XVECEXP (PATTERN (i2), 0, 1), -1, NULL_RTX,
-                            NULL_RTX);
+                            XVECEXP (PATTERN (i2), 0, 1), -1, NULL_RTX);
 
          SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 0));
          SUBST (XEXP (SET_SRC (PATTERN (i2)), 0),
@@ -2078,12 +2566,21 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
      rtx.  If I2 is a PARALLEL, we just need the piece that assigns I2SRC to
      I2DEST.  */
 
-  i2pat = (GET_CODE (PATTERN (i2)) == PARALLEL
-          ? gen_rtx_SET (VOIDmode, i2dest, i2src)
-          : PATTERN (i2));
-
   if (added_sets_2)
-    i2pat = copy_rtx (i2pat);
+    {
+      if (GET_CODE (PATTERN (i2)) == PARALLEL)
+       i2pat = gen_rtx_SET (VOIDmode, i2dest, copy_rtx (i2src));
+      else
+       i2pat = copy_rtx (PATTERN (i2));
+    }
+
+  if (added_sets_1)
+    {
+      if (GET_CODE (PATTERN (i1)) == PARALLEL)
+       i1pat = gen_rtx_SET (VOIDmode, i1dest, copy_rtx (i1src));
+      else
+       i1pat = copy_rtx (PATTERN (i1));
+    }
 
   combine_merges++;
 
@@ -2137,10 +2634,15 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
                                   compare_mode))
            {
              unsigned int regno = REGNO (SET_DEST (newpat));
-             rtx new_dest = gen_rtx_REG (compare_mode, regno);
+             rtx new_dest;
 
-             if (regno >= FIRST_PSEUDO_REGISTER)
-               SUBST (regno_reg_rtx[regno], 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);
@@ -2180,12 +2682,12 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
             simplifications.  */
          if (i1)
            {
-             subst_low_cuid = INSN_CUID (i1);
+             subst_low_luid = DF_INSN_LUID (i1);
              i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0);
            }
          else
            {
-             subst_low_cuid = INSN_CUID (i2);
+             subst_low_luid = DF_INSN_LUID (i2);
              i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);
            }
        }
@@ -2196,7 +2698,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
         need to make a unique copy of I2SRC each time we substitute it
         to avoid self-referential rtl.  */
 
-      subst_low_cuid = INSN_CUID (i2);
+      subst_low_luid = DF_INSN_LUID (i2);
       newpat = subst (PATTERN (i3), i2dest, i2src, 0,
                      ! i1_feeds_i3 && i1dest_in_i1src);
       substed_i2 = 1;
@@ -2222,7 +2724,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
        }
 
       n_occurrences = 0;
-      subst_low_cuid = INSN_CUID (i1);
+      subst_low_luid = DF_INSN_LUID (i1);
       newpat = subst (newpat, i1dest, i1src, 0, 0);
       substed_i1 = 1;
     }
@@ -2273,9 +2775,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
        }
 
       if (added_sets_1)
-       XVECEXP (newpat, 0, --total_sets)
-         = (GET_CODE (PATTERN (i1)) == PARALLEL
-            ? gen_rtx_SET (VOIDmode, i1dest, i1src) : PATTERN (i1));
+       XVECEXP (newpat, 0, --total_sets) = i1pat;
 
       if (added_sets_2)
        {
@@ -2388,14 +2888,13 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   if (i1 && insn_code_number < 0 && GET_CODE (newpat) == SET
       && asm_noperands (newpat) < 0)
     {
-      rtx m_split, *split;
-      rtx ni2dest = i2dest;
+      rtx parallel, m_split, *split;
 
       /* 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,
         convert I2DEST to the mode of the source of NEWPAT if we can.  */
 
-      m_split = split_insns (newpat, i3);
+      m_split = combine_split_insns (newpat, i3);
 
       /* We can only use I2DEST as a scratch reg if it doesn't overlap any
         inputs of NEWPAT.  */
@@ -2404,43 +2903,64 @@ 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))
-       {
-         enum machine_mode new_mode = GET_MODE (SET_DEST (newpat));
-         /* If I2DEST is a hard register or the only use of a pseudo,
-            we can change its mode.  */
-         if (new_mode != GET_MODE (i2dest)
-             && new_mode != VOIDmode
-             && can_change_dest_mode (i2dest, added_sets_2, new_mode))
-           ni2dest = gen_rtx_REG (GET_MODE (SET_DEST (newpat)),
-                                  REGNO (i2dest));
-
-         m_split = split_insns (gen_rtx_PARALLEL
-                                (VOIDmode,
-                                 gen_rtvec (2, newpat,
-                                            gen_rtx_CLOBBER (VOIDmode,
-                                                             ni2dest))),
-                                i3);
-         /* If the split with the mode-changed register didn't work, try
-            the original register.  */
-         if (! m_split && ni2dest != i2dest)
-           {
-             ni2dest = i2dest;
-             m_split = split_insns (gen_rtx_PARALLEL
-                                    (VOIDmode,
-                                     gen_rtvec (2, newpat,
-                                                gen_rtx_CLOBBER (VOIDmode,
-                                                                 i2dest))),
-                                    i3);
+      if (m_split == 0 && ! reg_overlap_mentioned_p (i2dest, newpat))
+       {
+         enum machine_mode new_mode = GET_MODE (SET_DEST (newpat));
+
+         /* First try to split using the original register as a
+            scratch register.  */
+         parallel = gen_rtx_PARALLEL (VOIDmode,
+                                      gen_rtvec (2, newpat,
+                                                 gen_rtx_CLOBBER (VOIDmode,
+                                                                  i2dest)));
+         m_split = combine_split_insns (parallel, i3);
+
+         /* 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))
+           {
+             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)];
+               }
+
+             parallel = (gen_rtx_PARALLEL
+                         (VOIDmode,
+                          gen_rtvec (2, newpat,
+                                     gen_rtx_CLOBBER (VOIDmode,
+                                                      ni2dest))));
+             m_split = combine_split_insns (parallel, 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);
+       {
+         parallel = gen_rtx_PARALLEL (VOIDmode, newpat_vec_with_clobbers);
+         m_split = combine_split_insns (parallel, i3);
+       }
 
       if (m_split && NEXT_INSN (m_split) == NULL_RTX)
        {
@@ -2451,7 +2971,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
        }
       else if (m_split && NEXT_INSN (NEXT_INSN (m_split)) == NULL_RTX
               && (next_real_insn (i2) == i3
-                  || ! use_crosses_set_p (PATTERN (m_split), INSN_CUID (i2))))
+                  || ! use_crosses_set_p (PATTERN (m_split), DF_INSN_LUID (i2))))
        {
          rtx i2set, i3set;
          rtx newi3pat = PATTERN (NEXT_INSN (m_split));
@@ -2460,13 +2980,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
@@ -2502,7 +3015,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
              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))++;
+               INC_REG_N_SETS (REGNO (new_i2_dest), 1);
            }
        }
 
@@ -2522,7 +3035,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
              || can_change_dest_mode (i2dest, added_sets_2,
                                       GET_MODE (*split)))
          && (next_real_insn (i2) == i3
-             || ! use_crosses_set_p (*split, INSN_CUID (i2)))
+             || ! use_crosses_set_p (*split, DF_INSN_LUID (i2)))
          /* We can't overwrite I2DEST if its value is still used by
             NEWPAT.  */
          && ! reg_referenced_p (i2dest, newpat))
@@ -2537,10 +3050,13 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
             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
@@ -2689,23 +3205,27 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
           && rtx_equal_p (SET_SRC (XVECEXP (newpat, 0, 1)),
                           XEXP (SET_SRC (XVECEXP (newpat, 0, 0)), 0))
           && ! use_crosses_set_p (SET_SRC (XVECEXP (newpat, 0, 1)),
-                                  INSN_CUID (i2))
+                                  DF_INSN_LUID (i2))
           && 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)),
                 (REG_P (temp)
-                 && reg_stat[REGNO (temp)].nonzero_bits != 0
+                 && VEC_index (reg_stat_type, reg_stat,
+                               REGNO (temp))->nonzero_bits != 0
                  && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
                  && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
-                 && (reg_stat[REGNO (temp)].nonzero_bits
+                 && (VEC_index (reg_stat_type, reg_stat,
+                                REGNO (temp))->nonzero_bits
                      != GET_MODE_MASK (word_mode))))
           && ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG
                 && (temp = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))),
                     (REG_P (temp)
-                     && reg_stat[REGNO (temp)].nonzero_bits != 0
+                     && VEC_index (reg_stat_type, reg_stat,
+                                   REGNO (temp))->nonzero_bits != 0
                      && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD
                      && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT
-                     && (reg_stat[REGNO (temp)].nonzero_bits
+                     && (VEC_index (reg_stat_type, reg_stat,
+                                    REGNO (temp))->nonzero_bits
                          != GET_MODE_MASK (word_mode)))))
           && ! reg_overlap_mentioned_p (SET_DEST (XVECEXP (newpat, 0, 1)),
                                         SET_SRC (XVECEXP (newpat, 0, 1)))
@@ -2743,16 +3263,20 @@ 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
           && ! 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
+                                  DF_INSN_LUID (i2))
           && ! 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
@@ -2789,12 +3313,9 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   /* If we had to change another insn, make sure it is valid also.  */
   if (undobuf.other_insn)
     {
-      rtx other_pat = PATTERN (undobuf.other_insn);
-      rtx new_other_notes;
-      rtx note, next;
-
       CLEAR_HARD_REG_SET (newpat_used_regs);
 
+      other_pat = PATTERN (undobuf.other_insn);
       other_code_number = recog_for_combine (&other_pat, undobuf.other_insn,
                                             &new_other_notes);
 
@@ -2803,33 +3324,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
          undo_all ();
          return 0;
        }
-
-      PATTERN (undobuf.other_insn) = other_pat;
-
-      /* If any of the notes in OTHER_INSN were REG_UNUSED, ensure that they
-        are still valid.  Then add any non-duplicate notes added by
-        recog_for_combine.  */
-      for (note = REG_NOTES (undobuf.other_insn); note; note = next)
-       {
-         next = XEXP (note, 1);
-
-         if (REG_NOTE_KIND (note) == REG_UNUSED
-             && ! reg_set_p (XEXP (note, 0), PATTERN (undobuf.other_insn)))
-           {
-             if (REG_P (XEXP (note, 0)))
-               REG_N_DEATHS (REGNO (XEXP (note, 0)))--;
-
-             remove_note (undobuf.other_insn, note);
-           }
-       }
-
-      for (note = new_other_notes; note; note = XEXP (note, 1))
-       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, 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.  */
@@ -2844,16 +3340,38 @@ 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;
-    }
+  /* 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, other_pat))
+    {
+      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 (undobuf.other_insn)
+    {
+      rtx note, next;
+
+      PATTERN (undobuf.other_insn) = other_pat;
+
+      /* If any of the notes in OTHER_INSN were REG_UNUSED, ensure that they
+        are still valid.  Then add any non-duplicate notes added by
+        recog_for_combine.  */
+      for (note = REG_NOTES (undobuf.other_insn); note; note = next)
+       {
+         next = XEXP (note, 1);
+
+         if (REG_NOTE_KIND (note) == REG_UNUSED
+             && ! reg_set_p (XEXP (note, 0), PATTERN (undobuf.other_insn)))
+           remove_note (undobuf.other_insn, note);
+       }
 
-  /* We now know that we can do this combination.  Merge the insns and
-     update the status of registers and LOG_LINKS.  */
+      distribute_notes (new_other_notes, undobuf.other_insn,
+                       undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
+    }
 
   if (swap_i2i3)
     {
@@ -2862,12 +3380,12 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
       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.  */
+        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.
+        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.
@@ -2976,7 +3494,8 @@ 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
+         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,
@@ -3029,11 +3548,11 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
     if (newi2pat)
       {
-       move_deaths (newi2pat, NULL_RTX, INSN_CUID (i1), i2, &midnotes);
-       move_deaths (newpat, newi2pat, INSN_CUID (i1), i3, &midnotes);
+       move_deaths (newi2pat, NULL_RTX, DF_INSN_LUID (i1), i2, &midnotes);
+       move_deaths (newpat, newi2pat, DF_INSN_LUID (i1), i3, &midnotes);
       }
     else
-      move_deaths (newpat, NULL_RTX, i1 ? INSN_CUID (i1) : INSN_CUID (i2),
+      move_deaths (newpat, NULL_RTX, i1 ? DF_INSN_LUID (i1) : DF_INSN_LUID (i2),
                   i3, &midnotes);
 
     /* Distribute all the LOG_LINKS and REG_NOTES from I1, I2, and I3.  */
@@ -3052,26 +3571,13 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
     /* 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,
-       so we always pass it as i3.  We have not counted the notes in
-       reg_n_deaths yet, so we need to do so now.  */
+       so we always pass it as i3.  */
 
     if (newi2pat && new_i2_notes)
-      {
-       for (temp = new_i2_notes; temp; temp = XEXP (temp, 1))
-         if (REG_P (XEXP (temp, 0)))
-           REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
-
-       distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
-      }
-
+      distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
+    
     if (new_i3_notes)
-      {
-       for (temp = new_i3_notes; temp; temp = XEXP (temp, 1))
-         if (REG_P (XEXP (temp, 0)))
-           REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
-
-       distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
-      }
+      distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
 
     /* If I3DEST was used in I3SRC, it really died in I3.  We may need to
        put a REG_DEAD note for it somewhere.  If NEWI2PAT exists and sets
@@ -3082,9 +3588,6 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
     if (i3dest_killed)
       {
-       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),
@@ -3098,9 +3601,6 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
     if (i2dest_in_i2src)
       {
-       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, NULL_RTX);
@@ -3112,9 +3612,6 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
     if (i1dest_in_i1src)
       {
-       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, NULL_RTX);
@@ -3155,7 +3652,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
            && ! i2dest_in_i2src)
          {
            regno = REGNO (i2dest);
-           REG_N_SETS (regno)--;
+           INC_REG_N_SETS (regno, -1);
          }
       }
 
@@ -3173,7 +3670,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
        regno = REGNO (i1dest);
        if (! added_sets_1 && ! i1dest_in_i1src)
-         REG_N_SETS (regno)--;
+         INC_REG_N_SETS (regno, -1);
       }
 
     /* Update reg_stat[].nonzero_bits et al for any changes that may have
@@ -3219,13 +3716,53 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
        && SET_DEST (newpat) == pc_rtx)
       *new_direct_jump_p = 1;
   }
+  
+  if (undobuf.other_insn != NULL_RTX)
+    {
+      if (dump_file)
+       {
+         fprintf (dump_file, "modifying other_insn ");
+         dump_insn_slim (dump_file, undobuf.other_insn);
+       }
+      df_insn_rescan (undobuf.other_insn);
+    }
+
+  if (i1 && !(NOTE_P(i1) && (NOTE_KIND (i1) == NOTE_INSN_DELETED)))
+    {
+      if (dump_file)
+       {
+         fprintf (dump_file, "modifying insn i1 ");
+         dump_insn_slim (dump_file, i1);
+       }
+      df_insn_rescan (i1);
+    }
+
+  if (i2 && !(NOTE_P(i2) && (NOTE_KIND (i2) == NOTE_INSN_DELETED)))
+    {
+      if (dump_file)
+       {
+         fprintf (dump_file, "modifying insn i2 ");
+         dump_insn_slim (dump_file, i2);
+       }
+      df_insn_rescan (i2);
+    }
 
+  if (i3 && !(NOTE_P(i3) && (NOTE_KIND (i3) == NOTE_INSN_DELETED)))
+    {
+      if (dump_file)
+       {
+         fprintf (dump_file, "modifying insn i3 ");
+         dump_insn_slim (dump_file, i3);
+       }
+      df_insn_rescan (i3);
+    }
+  
   combine_successes++;
   undo_commit ();
 
   if (added_links_insn
-      && (newi2pat == 0 || INSN_CUID (added_links_insn) < INSN_CUID (i2))
-      && INSN_CUID (added_links_insn) < INSN_CUID (i3))
+      && (newi2pat == 0 || DF_INSN_LUID (added_links_insn) < DF_INSN_LUID (i2))
+      && DF_INSN_LUID (added_links_insn) < DF_INSN_LUID (i3))
     return added_links_insn;
   else
     return newi2pat ? i2 : i3;
@@ -3241,10 +3778,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;
@@ -3269,7 +3816,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
@@ -3326,8 +3872,9 @@ find_split_point (rtx *loc, rtx insn)
          && ! memory_address_p (GET_MODE (x), XEXP (x, 0)))
        {
          rtx reg = regno_reg_rtx[FIRST_PSEUDO_REGISTER];
-         rtx seq = split_insns (gen_rtx_SET (VOIDmode, reg, XEXP (x, 0)),
-                                subst_insn);
+         rtx seq = combine_split_insns (gen_rtx_SET (VOIDmode, reg,
+                                                     XEXP (x, 0)),
+                                        subst_insn);
 
          /* This should have produced two insns, each of which sets our
             placeholder.  If the source of the second is a valid address,
@@ -3442,7 +3989,7 @@ find_split_point (rtx *loc, rtx insn)
              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),
                                          or_mask));
            }
@@ -3716,15 +4263,15 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
       return (unique_copy && n_occurrences > 1 ? copy_rtx (to) : to);
     }
 
-  /* If X and FROM are the same register but different modes, they will
-     not have been seen as equal above.  However, flow.c will make a
-     LOG_LINKS entry for that case.  If we do nothing, we will try to
-     rerecognize our original insn and, when it succeeds, we will
-     delete the feeding insn, which is incorrect.
+  /* If X and FROM are the same register but different modes, they
+     will not have been seen as equal above.  However, the log links code
+     will make a LOG_LINKS entry for that case.  If we do nothing, we
+     will try to rerecognize our original insn and, when it succeeds,
+     we will delete the feeding insn, which is incorrect.
 
      So force this insn not to match in this (rare) case.  */
   if (! in_dest && code == REG && REG_P (from)
-      && REGNO (x) == REGNO (from))
+      && reg_overlap_mentioned_p (x, from))
     return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
 
   /* If this is an object, we are done unless it is a MEM or LO_SUM, both
@@ -3995,7 +4542,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)))))))
     {
@@ -4039,7 +4586,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);
 
@@ -4058,7 +4605,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,
@@ -4202,7 +4749,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,
@@ -4234,7 +4781,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
@@ -4697,11 +5244,17 @@ simplify_if_then_else (rtx x)
 
       if (true_code == EQ && true_val == const0_rtx
          && exact_log2 (nzb = nonzero_bits (from, GET_MODE (from))) >= 0)
-       false_code = EQ, false_val = GEN_INT (nzb);
+       {
+         false_code = EQ;
+         false_val = GEN_INT (trunc_int_for_mode (nzb, GET_MODE (from)));
+       }
       else if (true_code == EQ && true_val == const0_rtx
               && (num_sign_bit_copies (from, GET_MODE (from))
                   == GET_MODE_BITSIZE (GET_MODE (from))))
-       false_code = EQ, false_val = constm1_rtx;
+       {
+         false_code = EQ;
+         false_val = constm1_rtx;
+       }
 
       /* Now simplify an arm if we know the value of the register in the
         branch and it is used in the arm.  Be careful due to the potential
@@ -5024,13 +5577,13 @@ simplify_set (rtx x)
       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);
@@ -5073,10 +5626,15 @@ simplify_set (rtx x)
          if (can_change_dest_mode (dest, 0, compare_mode))
            {
              unsigned int regno = REGNO (dest);
-             rtx new_dest = gen_rtx_REG (compare_mode, regno);
+             rtx new_dest;
 
-             if (regno >= FIRST_PSEUDO_REGISTER)
-               SUBST (regno_reg_rtx[regno], 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);
@@ -5148,14 +5706,14 @@ simplify_set (rtx x)
        }
       else if (GET_MODE (op0) == compare_mode && op1 == const0_rtx)
        {
-         SUBST(SET_SRC (x), op0);
+         SUBST (SET_SRC (x), op0);
          src = SET_SRC (x);
-        }
-      else
+       }
+      /* Otherwise, update the COMPARE if needed.  */
+      else if (XEXP (src, 0) != op0 || XEXP (src, 1) != op1)
        {
-         /* Otherwise, update the COMPARE if needed.  */
-         SUBST (XEXP (src, 0), op0);
-         SUBST (XEXP (src, 1), op1);
+         SUBST (SET_SRC (x), gen_rtx_COMPARE (compare_mode, op0, op1));
+         src = SET_SRC (x);
        }
     }
   else
@@ -5186,7 +5744,7 @@ 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
       && ! (REG_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER
@@ -5476,11 +6034,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;
@@ -5517,8 +6073,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
@@ -5536,9 +6092,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))
@@ -5578,14 +6134,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,
@@ -5612,8 +6170,8 @@ expand_compound_operation (rtx x)
    We half-heartedly support variable positions, but do not at all
    support variable lengths.  */
 
-static rtx
-expand_field_assignment (rtx x)
+static const_rtx
+expand_field_assignment (const_rtx x)
 {
   rtx inner;
   rtx pos;                     /* Always counts from low bit.  */
@@ -5638,11 +6196,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)
            {
@@ -5740,13 +6297,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.
 
@@ -5773,23 +6323,16 @@ 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.
@@ -5828,16 +6371,16 @@ 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
           && !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
               || (REG_P (inner)
                   && have_insn_for (STRICT_LOW_PART, tmode))))
@@ -5961,15 +6504,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 && MEM_P (inner)
+  /* 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;
@@ -6009,15 +6551,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 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;
 
@@ -6043,15 +6601,16 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
         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)
-      && ((MEM_P (inner)
-          && (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;
 
@@ -6062,28 +6621,20 @@ 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.
-        Be careful not to go beyond the original object and maintain the
-        natural alignment of the memory.  */ 
-      if (pos_rtx == 0)
-       {
-         enum machine_mode bfmode = smallest_mode_for_size (len, MODE_INT);
-         offset += (pos / GET_MODE_BITSIZE (bfmode)) * GET_MODE_SIZE (bfmode);
-         pos %= GET_MODE_BITSIZE (bfmode);
-       }
+      /* 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
@@ -6096,6 +6647,9 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
              || 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
@@ -6436,12 +6990,12 @@ make_compound_operation (rtx x, enum rtx_code in_code)
          {
            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;
          }
 
@@ -6570,9 +7124,9 @@ canon_reg_for_combine (rtx x, rtx reg)
       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 (fmt[i] == 'e')
+         {
+           rtx op = canon_reg_for_combine (XEXP (x, i), reg);
            if (op != XEXP (x, i))
              {
                if (!copied)
@@ -6581,15 +7135,15 @@ canon_reg_for_combine (rtx x, rtx reg)
                    x = copy_rtx (x);
                  }
                XEXP (x, i) = op;
-              }
-          }
-        else if (fmt[i] == 'E')
-          {
-            int j;
-            for (j = 0; j < XVECLEN (x, i); j++)
+             }
+         }
+       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))
+               rtx op = canon_reg_for_combine (XVECEXP (x, i, j), reg);
+               if (op != XVECEXP (x, i, j))
                  {
                    if (!copied)
                      {
@@ -6597,7 +7151,7 @@ canon_reg_for_combine (rtx x, rtx reg)
                        x = copy_rtx (x);
                      }
                    XVECEXP (x, i, j) = op;
-                 }
+                 }
              }
          }
 
@@ -6607,6 +7161,22 @@ canon_reg_for_combine (rtx x, rtx reg)
   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
@@ -6669,7 +7239,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
@@ -6677,7 +7247,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);
@@ -6698,15 +7268,6 @@ 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, next_select);
-      break;
-
     case SIGN_EXTEND:
     case ZERO_EXTEND:
     case ZERO_EXTRACT:
@@ -6872,11 +7433,11 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       /* For most binary operations, just propagate into the operation and
         change the mode if we have an operation of that mode.  */
 
-      op0 = gen_lowpart (op_mode,
-                        force_to_mode (XEXP (x, 0), mode, mask,
-                                       next_select));
-      op1 = gen_lowpart (op_mode,
-                        force_to_mode (XEXP (x, 1), mode, mask,
+      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))
@@ -6909,9 +7470,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, 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));
@@ -7016,7 +7577,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
 
          if ((mask & ~nonzero) == 0)
            {
-             x = simplify_shift_const (x, LSHIFTRT, GET_MODE (x),
+             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);
@@ -7115,9 +7676,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,
-                                       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;
@@ -7140,11 +7701,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), force_to_mode (XEXP (x, 1), mode,
-                                                      mask, next_select)));
+            gen_lowpart_or_truncate (GET_MODE (x),
+                                     force_to_mode (XEXP (x, 1), mode,
+                                                    mask, next_select)));
       SUBST (XEXP (x, 2),
-            gen_lowpart (GET_MODE (x), force_to_mode (XEXP (x, 2), mode,
-                                                      mask, next_select)));
+            gen_lowpart_or_truncate (GET_MODE (x),
+                                     force_to_mode (XEXP (x, 2), mode,
+                                                    mask, next_select)));
       break;
 
     default:
@@ -7152,7 +7715,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
@@ -7219,7 +7782,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
            {
@@ -7496,7 +8059,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)
@@ -7798,7 +8361,12 @@ apply_distributive_law (rtx x)
          || (GET_MODE_SIZE (GET_MODE (lhs))
              > GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs))))
          || VECTOR_MODE_P (GET_MODE (lhs))
-         || GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs))) > UNITS_PER_WORD)
+         || 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)),
@@ -7856,7 +8424,7 @@ 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.
@@ -8022,8 +8590,7 @@ simplify_and_const_int_1 (enum machine_mode mode, rtx varop,
     return NULL_RTX;
 
   /* Otherwise, return an AND.  */
-  constop = trunc_int_for_mode (constop, mode);
-  return simplify_gen_binary (AND, mode, varop, GEN_INT (constop));
+  return simplify_gen_binary (AND, mode, varop, gen_int_mode (constop, mode));
 }
 
 
@@ -8042,7 +8609,8 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
     return tem;
 
   if (!x)
-    x = simplify_gen_binary (AND, GET_MODE (varop), varop, GEN_INT (constop));
+    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;
@@ -8055,32 +8623,35 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
    a shift, AND, or zero_extract, we can do better.  */
 
 static rtx
-reg_nonzero_bits_for_combine (rtx x, enum machine_mode mode,
-                             rtx known_x ATTRIBUTE_UNUSED,
+reg_nonzero_bits_for_combine (const_rtx x, enum machine_mode mode,
+                             const_rtx known_x ATTRIBUTE_UNUSED,
                              enum machine_mode known_mode ATTRIBUTE_UNUSED,
                              unsigned HOST_WIDE_INT known_ret ATTRIBUTE_UNUSED,
                              unsigned HOST_WIDE_INT *nonzero)
 {
   rtx tem;
+  reg_stat_type *rsp;
 
   /* If X is a register whose nonzero bits value is current, use it.
      Otherwise, if X is a register whose value we can find, use that
      value.  Otherwise, use the previously-computed global nonzero bits
      for this register.  */
 
-  if (reg_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
+  rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
+  if (rsp->last_set_value != 0
+      && (rsp->last_set_mode == mode
+         || (GET_MODE_CLASS (rsp->last_set_mode) == MODE_INT
              && GET_MODE_CLASS (mode) == MODE_INT))
-      && (reg_stat[REGNO (x)].last_set_label == label_tick
+      && ((rsp->last_set_label >= label_tick_ebb_start
+          && rsp->last_set_label < label_tick)
+         || (rsp->last_set_label == label_tick
+              && DF_INSN_LUID (rsp->last_set) < subst_low_luid)
          || (REGNO (x) >= FIRST_PSEUDO_REGISTER
              && REG_N_SETS (REGNO (x)) == 1
-             && ! 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)
+             && !REGNO_REG_SET_P
+                 (DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), REGNO (x)))))
     {
-      *nonzero &= reg_stat[REGNO (x)].last_set_nonzero_bits;
+      *nonzero &= rsp->last_set_nonzero_bits;
       return NULL;
     }
 
@@ -8090,13 +8661,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
@@ -8110,13 +8681,13 @@ reg_nonzero_bits_for_combine (rtx x, enum machine_mode mode,
 #endif
       return tem;
     }
-  else if (nonzero_sign_valid && reg_stat[REGNO (x)].nonzero_bits)
+  else if (nonzero_sign_valid && rsp->nonzero_bits)
     {
-      unsigned HOST_WIDE_INT mask = reg_stat[REGNO (x)].nonzero_bits;
+      unsigned HOST_WIDE_INT mask = rsp->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;
     }
 
@@ -8129,26 +8700,29 @@ reg_nonzero_bits_for_combine (rtx x, enum machine_mode mode,
    be between 1 and the number of bits in MODE.  */
 
 static rtx
-reg_num_sign_bit_copies_for_combine (rtx x, enum machine_mode mode,
-                                    rtx known_x ATTRIBUTE_UNUSED,
+reg_num_sign_bit_copies_for_combine (const_rtx x, enum machine_mode mode,
+                                    const_rtx known_x ATTRIBUTE_UNUSED,
                                     enum machine_mode known_mode
                                     ATTRIBUTE_UNUSED,
                                     unsigned int known_ret ATTRIBUTE_UNUSED,
                                     unsigned int *result)
 {
   rtx tem;
-
-  if (reg_stat[REGNO (x)].last_set_value != 0
-      && reg_stat[REGNO (x)].last_set_mode == mode
-      && (reg_stat[REGNO (x)].last_set_label == label_tick
-          || (REGNO (x) >= FIRST_PSEUDO_REGISTER
+  reg_stat_type *rsp;
+
+  rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
+  if (rsp->last_set_value != 0
+      && rsp->last_set_mode == mode
+      && ((rsp->last_set_label >= label_tick_ebb_start
+          && rsp->last_set_label < label_tick)
+         || (rsp->last_set_label == label_tick
+              && DF_INSN_LUID (rsp->last_set) < subst_low_luid)
+         || (REGNO (x) >= FIRST_PSEUDO_REGISTER
              && REG_N_SETS (REGNO (x)) == 1
-             && ! 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)
+             && !REGNO_REG_SET_P
+                 (DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), REGNO (x)))))
     {
-      *result = reg_stat[REGNO (x)].last_set_sign_bit_copies;
+      *result = rsp->last_set_sign_bit_copies;
       return NULL;
     }
 
@@ -8156,10 +8730,10 @@ reg_num_sign_bit_copies_for_combine (rtx x, enum machine_mode mode,
   if (tem != 0)
     return tem;
 
-  if (nonzero_sign_valid && reg_stat[REGNO (x)].sign_bit_copies != 0
+  if (nonzero_sign_valid && rsp->sign_bit_copies != 0
       && GET_MODE_BITSIZE (GET_MODE (x)) == GET_MODE_BITSIZE (mode))
-    *result = reg_stat[REGNO (x)].sign_bit_copies;
-      
+    *result = rsp->sign_bit_copies;
+
   return NULL;
 }
 \f
@@ -8175,7 +8749,7 @@ reg_num_sign_bit_copies_for_combine (rtx x, enum machine_mode mode,
    implies that it must be called from a define_split.  */
 
 unsigned int
-extended_count (rtx x, enum machine_mode mode, int unsignedp)
+extended_count (const_rtx x, enum machine_mode mode, int unsignedp)
 {
   if (nonzero_sign_valid == 0)
     return 0;
@@ -8448,14 +9022,14 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
              == 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))
@@ -8493,33 +9067,6 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
            }
          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
@@ -8594,7 +9141,8 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
              && 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));
@@ -8789,8 +9337,8 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
                   && 0 > trunc_int_for_mode (INTVAL (XEXP (varop, 1)),
                                              shift_mode))
              && (new = simplify_const_binary_operation (code, result_mode,
-                                                        XEXP (varop, 1),
-                                                        GEN_INT (count))) != 0
+                                                        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))
@@ -8805,7 +9353,7 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
             for some (ashiftrt (xor)).  */
          if (GET_CODE (XEXP (varop, 1)) == CONST_INT
             && !(code == ASHIFTRT && GET_CODE (varop) == XOR
-                 && 0 > trunc_int_for_mode (INTVAL (XEXP (varop, 1)),
+                 && 0 > trunc_int_for_mode (INTVAL (XEXP (varop, 1)),
                                             shift_mode)))
            {
              rtx lhs = simplify_shift_const (NULL_RTX, code, shift_mode,
@@ -8818,7 +9366,7 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
              varop = apply_distributive_law (varop);
 
              count = 0;
-             continue; 
+             continue;
            }
          break;
 
@@ -8917,8 +9465,8 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
          if (code == ASHIFT
              && GET_CODE (XEXP (varop, 1)) == CONST_INT
              && (new = simplify_const_binary_operation (ASHIFT, result_mode,
-                                                        XEXP (varop, 1),
-                                                        GEN_INT (count))) != 0
+                                                        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))
@@ -8936,8 +9484,8 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
              && 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
+                                                        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))
@@ -9051,7 +9599,7 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
                                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.  */
@@ -9066,9 +9614,12 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
       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
@@ -9142,6 +9693,14 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
   REG_NOTES (insn) = 0;
 
   insn_code_number = recog (pat, insn, &num_clobbers_to_add);
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      if (insn_code_number < 0)
+       fputs ("Failed to match this instruction:\n", dump_file);
+      else
+       fputs ("Successfully matched this instruction:\n", dump_file);
+      print_rtl_single (dump_file, pat);
+    }
 
   /* If it isn't, there is the possibility that we previously had an insn
      that clobbered some register as a side effect, but the combined
@@ -9168,6 +9727,14 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
 
       PATTERN (insn) = pat;
       insn_code_number = recog (pat, insn, &num_clobbers_to_add);
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         if (insn_code_number < 0)
+           fputs ("Failed to match this instruction:\n", dump_file);
+         else
+           fputs ("Successfully matched this instruction:\n", dump_file);
+         print_rtl_single (dump_file, pat);
+       }
     }
   PATTERN (insn) = old_pat;
   REG_NOTES (insn) = old_notes;
@@ -9200,8 +9767,12 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
          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,
-                                    XEXP (XVECEXP (newpat, 0, i), 0), notes);
+         if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) != SCRATCH) 
+           {
+             gcc_assert (REG_P (XEXP (XVECEXP (newpat, 0, i), 0)));
+             notes = gen_rtx_EXPR_LIST (REG_UNUSED,
+                                        XEXP (XVECEXP (newpat, 0, i), 0), notes);
+           }
        }
       pat = newpat;
     }
@@ -9269,11 +9840,6 @@ gen_lowpart_for_combine (enum machine_mode omode, rtx x)
 
   result = gen_lowpart_common (omode, x);
 
-#ifdef CANNOT_CHANGE_MODE_CLASS
-  if (result != 0 && GET_CODE (result) == SUBREG)
-    record_subregs_of_mode (result);
-#endif
-
   if (result)
     return result;
 
@@ -9874,7 +10440,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              && ! unsigned_comparison_p
              && (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
              && ((unsigned HOST_WIDE_INT) const_op
-                 < (((unsigned HOST_WIDE_INT) 1 
+                 < (((unsigned HOST_WIDE_INT) 1
                      << (GET_MODE_BITSIZE (mode) - 1))))
              && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
            {
@@ -9915,7 +10481,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              HOST_WIDE_INT c1 = -INTVAL (XEXP (SUBREG_REG (op0), 1));
 
              if ((c1 > 0
-                  && (unsigned HOST_WIDE_INT) c1
+                  && (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
@@ -9938,7 +10504,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
                {
                  op0 = SUBREG_REG (op0);
                  continue;
-               }
+               }
            }
 
          /* If the inner mode is narrower and we are extracting the low part,
@@ -10046,7 +10612,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
@@ -10108,8 +10674,8 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
            {
              op0 = simplify_and_const_int
                (NULL_RTX, mode, gen_rtx_LSHIFTRT (mode,
-                                                  XEXP (op0, 1),
-                                                  XEXP (XEXP (op0, 0), 1)),
+                                                  XEXP (op0, 1),
+                                                  XEXP (XEXP (op0, 0), 1)),
                 (HOST_WIDE_INT) 1);
              continue;
            }
@@ -10155,14 +10721,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;
@@ -10442,7 +11021,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 (REG_P (SUBREG_REG (op0)))
+         if (REG_P (SUBREG_REG (op0)))
            {
              op0 = SUBREG_REG (op0);
              op1 = gen_lowpart (GET_MODE (op0), op1);
@@ -10601,13 +11180,14 @@ update_table_tick (rtx x)
   if (code == REG)
     {
       unsigned int regno = REGNO (x);
-      unsigned int endregno
-       = regno + (regno < FIRST_PSEUDO_REGISTER
-                  ? hard_regno_nregs[regno][GET_MODE (x)] : 1);
+      unsigned int endregno = END_REGNO (x);
       unsigned int r;
 
       for (r = regno; r < endregno; r++)
-       reg_stat[r].last_set_table_tick = label_tick;
+       {
+         reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, r);
+         rsp->last_set_table_tick = label_tick;
+       }
 
       return;
     }
@@ -10663,10 +11243,9 @@ static void
 record_value_for_reg (rtx reg, rtx insn, rtx value)
 {
   unsigned int regno = REGNO (reg);
-  unsigned int endregno
-    = regno + (regno < FIRST_PSEUDO_REGISTER
-              ? hard_regno_nregs[regno][GET_MODE (reg)] : 1);
+  unsigned int endregno = END_REGNO (reg);
   unsigned int i;
+  reg_stat_type *rsp;
 
   /* If VALUE contains REG and we have a previous value for REG, substitute
      the previous value.  */
@@ -10676,7 +11255,7 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
 
       /* Set things up so get_last_value is allowed to see anything set up to
         our insn.  */
-      subst_low_cuid = INSN_CUID (insn);
+      subst_low_luid = DF_INSN_LUID (insn);
       tem = get_last_value (reg);
 
       /* If TEM is simply a binary operation with two CLOBBERs as operands,
@@ -10707,14 +11286,17 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
      register.  */
   for (i = regno; i < endregno; i++)
     {
+      rsp = VEC_index (reg_stat_type, reg_stat, i);
+
       if (insn)
-       reg_stat[i].last_set = insn;
+       rsp->last_set = insn;
 
-      reg_stat[i].last_set_value = 0;
-      reg_stat[i].last_set_mode = 0;
-      reg_stat[i].last_set_nonzero_bits = 0;
-      reg_stat[i].last_set_sign_bit_copies = 0;
-      reg_stat[i].last_death = 0;
+      rsp->last_set_value = 0;
+      rsp->last_set_mode = 0;
+      rsp->last_set_nonzero_bits = 0;
+      rsp->last_set_sign_bit_copies = 0;
+      rsp->last_death = 0;
+      rsp->truncated_to_mode = 0;
     }
 
   /* Mark registers that are being referenced in this value.  */
@@ -10730,40 +11312,43 @@ 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)
-       reg_stat[i].last_set_invalid = 1;
+      rsp = VEC_index (reg_stat_type, reg_stat, i);
+      rsp->last_set_label = label_tick;
+      if (!insn
+         || (value && rsp->last_set_table_tick >= label_tick_ebb_start))
+       rsp->last_set_invalid = 1;
       else
-       reg_stat[i].last_set_invalid = 0;
+       rsp->last_set_invalid = 0;
     }
 
   /* The value being assigned might refer to X (like in "x++;").  In that
      case, we must replace it with (clobber (const_int 0)) to prevent
      infinite loops.  */
+  rsp = VEC_index (reg_stat_type, reg_stat, regno);
   if (value && ! get_last_value_validate (&value, insn,
-                                         reg_stat[regno].last_set_label, 0))
+                                         rsp->last_set_label, 0))
     {
       value = copy_rtx (value);
       if (! get_last_value_validate (&value, insn,
-                                    reg_stat[regno].last_set_label, 1))
+                                    rsp->last_set_label, 1))
        value = 0;
     }
 
   /* For the main register being modified, update the value, the mode, the
      nonzero bits, and the number of sign bit copies.  */
 
-  reg_stat[regno].last_set_value = value;
+  rsp->last_set_value = value;
 
   if (value)
     {
       enum machine_mode mode = GET_MODE (reg);
-      subst_low_cuid = INSN_CUID (insn);
-      reg_stat[regno].last_set_mode = mode;
+      subst_low_luid = DF_INSN_LUID (insn);
+      rsp->last_set_mode = mode;
       if (GET_MODE_CLASS (mode) == MODE_INT
          && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
        mode = nonzero_bits_mode;
-      reg_stat[regno].last_set_nonzero_bits = nonzero_bits (value, mode);
-      reg_stat[regno].last_set_sign_bit_copies
+      rsp->last_set_nonzero_bits = nonzero_bits (value, mode);
+      rsp->last_set_sign_bit_copies
        = num_sign_bit_copies (value, GET_MODE (reg));
     }
 }
@@ -10773,13 +11358,20 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
    set is occurring.  */
 
 static void
-record_dead_and_set_regs_1 (rtx dest, rtx setter, void *data)
+record_dead_and_set_regs_1 (rtx dest, const_rtx setter, void *data)
 {
   rtx record_dead_insn = (rtx) data;
 
   if (GET_CODE (dest) == SUBREG)
     dest = SUBREG_REG (dest);
 
+  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
@@ -10801,7 +11393,7 @@ record_dead_and_set_regs_1 (rtx dest, rtx setter, void *data)
   else if (MEM_P (dest)
           /* Ignore pushes, they clobber nothing.  */
           && ! push_operand (dest, GET_MODE (dest)))
-    mem_last_set = INSN_CUID (record_dead_insn);
+    mem_last_set = DF_INSN_LUID (record_dead_insn);
 }
 
 /* Update the records of when each REG was most recently set or killed
@@ -10811,7 +11403,7 @@ record_dead_and_set_regs_1 (rtx dest, rtx setter, void *data)
    We update reg_stat[], in particular fields last_set, last_set_value,
    last_set_mode, last_set_nonzero_bits, last_set_sign_bit_copies,
    last_death, and also the similar information mem_last_set (which insn
-   most recently modified memory) and last_call_cuid (which insn was the
+   most recently modified memory) and last_call_luid (which insn was the
    most recent subroutine call).  */
 
 static void
@@ -10826,13 +11418,15 @@ record_dead_and_set_regs (rtx insn)
          && REG_P (XEXP (link, 0)))
        {
          unsigned int regno = REGNO (XEXP (link, 0));
-         unsigned int endregno
-           = regno + (regno < FIRST_PSEUDO_REGISTER
-                      ? hard_regno_nregs[regno][GET_MODE (XEXP (link, 0))]
-                      : 1);
+         unsigned int endregno = END_REGNO (XEXP (link, 0));
 
          for (i = regno; i < endregno; i++)
-           reg_stat[i].last_death = insn;
+           {
+             reg_stat_type *rsp;
+
+             rsp = VEC_index (reg_stat_type, reg_stat, i);
+             rsp->last_death = insn;
+           }
        }
       else if (REG_NOTE_KIND (link) == REG_INC)
        record_value_for_reg (XEXP (link, 0), insn, NULL_RTX);
@@ -10843,24 +11437,29 @@ record_dead_and_set_regs (rtx insn)
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
          {
-           reg_stat[i].last_set_value = 0;
-           reg_stat[i].last_set_mode = 0;
-           reg_stat[i].last_set_nonzero_bits = 0;
-           reg_stat[i].last_set_sign_bit_copies = 0;
-           reg_stat[i].last_death = 0;
+           reg_stat_type *rsp;
+
+           rsp = VEC_index (reg_stat_type, reg_stat, i);
+           rsp->last_set_invalid = 1;
+           rsp->last_set = insn;
+           rsp->last_set_value = 0;
+           rsp->last_set_mode = 0;
+           rsp->last_set_nonzero_bits = 0;
+           rsp->last_set_sign_bit_copies = 0;
+           rsp->last_death = 0;
+           rsp->truncated_to_mode = 0;
          }
 
-      last_call_cuid = mem_last_set = INSN_CUID (insn);
+      last_call_luid = mem_last_set = DF_INSN_LUID (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 LUID.  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
@@ -10884,6 +11483,8 @@ record_promoted_value (rtx insn, rtx subreg)
 
   for (links = LOG_LINKS (insn); links;)
     {
+      reg_stat_type *rsp;
+
       insn = XEXP (links, 0);
       set = single_set (insn);
 
@@ -10895,10 +11496,11 @@ record_promoted_value (rtx insn, rtx subreg)
          continue;
        }
 
-      if (reg_stat[regno].last_set == insn)
+      rsp = VEC_index (reg_stat_type, reg_stat, regno);
+      if (rsp->last_set == insn)
        {
          if (SUBREG_PROMOTED_UNSIGNED_P (subreg) > 0)
-           reg_stat[regno].last_set_nonzero_bits &= GET_MODE_MASK (mode);
+           rsp->last_set_nonzero_bits &= GET_MODE_MASK (mode);
        }
 
       if (REG_P (SET_SRC (set)))
@@ -10911,15 +11513,85 @@ 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, const_rtx x)
+{
+  reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
+  enum machine_mode truncated = rsp->truncated_to_mode;
+
+  if (truncated == 0
+      || rsp->truncation_label < label_tick_ebb_start)
+    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;
+  reg_stat_type *rsp;
+
+  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;
+
+  rsp = VEC_index (reg_stat_type, reg_stat, REGNO (x));
+  if (rsp->truncated_to_mode == 0
+      || rsp->truncation_label < label_tick_ebb_start
+      || (GET_MODE_SIZE (truncated_mode)
+         < GET_MODE_SIZE (rsp->truncated_to_mode)))
+    {
+      rsp->truncated_to_mode = truncated_mode;
+      rsp->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)
-      && REG_P (SUBREG_REG (x)))
-    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));
@@ -10929,13 +11601,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;
          }
     }
@@ -10962,26 +11634,26 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
   if (REG_P (x))
     {
       unsigned int regno = REGNO (x);
-      unsigned int endregno
-       = regno + (regno < FIRST_PSEUDO_REGISTER
-                  ? hard_regno_nregs[regno][GET_MODE (x)] : 1);
+      unsigned int endregno = END_REGNO (x);
       unsigned int j;
 
       for (j = regno; j < endregno; j++)
-       if (reg_stat[j].last_set_invalid
-           /* If this is a pseudo-register that was only set once and not
-              live at the beginning of the function, it is always valid.  */
-           || (! (regno >= FIRST_PSEUDO_REGISTER
-                  && REG_N_SETS (regno) == 1
-                  && (! REGNO_REG_SET_P
-                      (ENTRY_BLOCK_PTR->next_bb->il.rtl->global_live_at_start,
-                       regno)))
-               && reg_stat[j].last_set_label > tick))
+       {
+         reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, j);
+         if (rsp->last_set_invalid
+             /* If this is a pseudo-register that was only set once and not
+                live at the beginning of the function, it is always valid.  */
+             || (! (regno >= FIRST_PSEUDO_REGISTER
+                    && REG_N_SETS (regno) == 1
+                    && (!REGNO_REG_SET_P
+                        (DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), regno)))
+                 && rsp->last_set_label > tick))
          {
            if (replace)
              *loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
            return replace;
          }
+       }
 
       return 1;
     }
@@ -10989,7 +11661,7 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
      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 (MEM_P (x) && !MEM_READONLY_P (x)
-          && INSN_CUID (insn) <= mem_last_set)
+          && DF_INSN_LUID (insn) <= mem_last_set)
     {
       if (replace)
        *loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
@@ -11049,10 +11721,11 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
    is known longer known reliably.  */
 
 static rtx
-get_last_value (rtx x)
+get_last_value (const_rtx x)
 {
   unsigned int regno;
   rtx value;
+  reg_stat_type *rsp;
 
   /* If this is a non-paradoxical SUBREG, get the value of its operand and
      then convert it to the desired mode.  If this is a paradoxical SUBREG,
@@ -11068,7 +11741,8 @@ get_last_value (rtx x)
     return 0;
 
   regno = REGNO (x);
-  value = reg_stat[regno].last_set_value;
+  rsp = VEC_index (reg_stat_type, reg_stat, regno);
+  value = rsp->last_set_value;
 
   /* If we don't have a value, or if it isn't for this basic block and
      it's either a hard register, set more than once, or it's a live
@@ -11081,40 +11755,40 @@ get_last_value (rtx x)
      block.  */
 
   if (value == 0
-      || (reg_stat[regno].last_set_label != label_tick
+      || (rsp->last_set_label < label_tick_ebb_start
          && (regno < FIRST_PSEUDO_REGISTER
              || REG_N_SETS (regno) != 1
-             || (REGNO_REG_SET_P
-                 (ENTRY_BLOCK_PTR->next_bb->il.rtl->global_live_at_start,
-                  regno)))))
+             || REGNO_REG_SET_P
+                (DF_LR_IN (ENTRY_BLOCK_PTR->next_bb), regno))))
     return 0;
 
   /* If the value was set in a later insn than the ones we are processing,
      we can't use it even if the register was only set once.  */
-  if (INSN_CUID (reg_stat[regno].last_set) >= subst_low_cuid)
+  if (rsp->last_set_label == label_tick
+      && DF_INSN_LUID (rsp->last_set) >= subst_low_luid)
     return 0;
 
   /* If the value has all its registers valid, return it.  */
-  if (get_last_value_validate (&value, reg_stat[regno].last_set,
-                              reg_stat[regno].last_set_label, 0))
+  if (get_last_value_validate (&value, rsp->last_set,
+                              rsp->last_set_label, 0))
     return value;
 
   /* Otherwise, make a copy and replace any invalid register with
      (clobber (const_int 0)).  If that fails for some reason, return 0.  */
 
   value = copy_rtx (value);
-  if (get_last_value_validate (&value, reg_stat[regno].last_set,
-                              reg_stat[regno].last_set_label, 1))
+  if (get_last_value_validate (&value, rsp->last_set,
+                              rsp->last_set_label, 1))
     return value;
 
   return 0;
 }
 \f
 /* Return nonzero if expression X refers to a REG or to memory
-   that is set in an instruction more recent than FROM_CUID.  */
+   that is set in an instruction more recent than FROM_LUID.  */
 
 static int
-use_crosses_set_p (rtx x, int from_cuid)
+use_crosses_set_p (const_rtx x, int from_luid)
 {
   const char *fmt;
   int i;
@@ -11123,8 +11797,7 @@ use_crosses_set_p (rtx x, int from_cuid)
   if (code == REG)
     {
       unsigned int regno = REGNO (x);
-      unsigned endreg = regno + (regno < FIRST_PSEUDO_REGISTER
-                                ? hard_regno_nregs[regno][GET_MODE (x)] : 1);
+      unsigned endreg = END_REGNO (x);
 
 #ifdef PUSH_ROUNDING
       /* Don't allow uses of the stack pointer to be moved,
@@ -11133,13 +11806,17 @@ use_crosses_set_p (rtx x, int from_cuid)
        return 1;
 #endif
       for (; regno < endreg; regno++)
-       if (reg_stat[regno].last_set
-           && INSN_CUID (reg_stat[regno].last_set) > from_cuid)
-         return 1;
+       {
+         reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, regno);
+         if (rsp->last_set
+             && rsp->last_set_label == label_tick
+             && DF_INSN_LUID (rsp->last_set) > from_luid)
+           return 1;
+       }
       return 0;
     }
 
-  if (code == MEM && mem_last_set > from_cuid)
+  if (code == MEM && mem_last_set > from_luid)
     return 1;
 
   fmt = GET_RTX_FORMAT (code);
@@ -11150,11 +11827,11 @@ use_crosses_set_p (rtx x, int from_cuid)
        {
          int j;
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-           if (use_crosses_set_p (XVECEXP (x, i, j), from_cuid))
+           if (use_crosses_set_p (XVECEXP (x, i, j), from_luid))
              return 1;
        }
       else if (fmt[i] == 'e'
-              && use_crosses_set_p (XEXP (x, i), from_cuid))
+              && use_crosses_set_p (XEXP (x, i), from_luid))
        return 1;
     }
   return 0;
@@ -11172,7 +11849,7 @@ static int reg_dead_flag;
    reg_dead_flag to 1 if X is a CLOBBER and to -1 it is a SET.  */
 
 static void
-reg_dead_at_p_1 (rtx dest, rtx x, void *data ATTRIBUTE_UNUSED)
+reg_dead_at_p_1 (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED)
 {
   unsigned int regno, endregno;
 
@@ -11180,9 +11857,7 @@ reg_dead_at_p_1 (rtx dest, rtx x, void *data ATTRIBUTE_UNUSED)
     return;
 
   regno = REGNO (dest);
-  endregno = regno + (regno < FIRST_PSEUDO_REGISTER
-                     ? hard_regno_nregs[regno][GET_MODE (dest)] : 1);
-
+  endregno = END_REGNO (dest);
   if (reg_dead_endregno > regno && reg_dead_regno < endregno)
     reg_dead_flag = (GET_CODE (x) == CLOBBER) ? 1 : -1;
 }
@@ -11203,10 +11878,7 @@ reg_dead_at_p (rtx reg, rtx insn)
 
   /* Set variables for reg_dead_at_p_1.  */
   reg_dead_regno = REGNO (reg);
-  reg_dead_endregno = reg_dead_regno + (reg_dead_regno < FIRST_PSEUDO_REGISTER
-                                       ? hard_regno_nregs[reg_dead_regno]
-                                                         [GET_MODE (reg)]
-                                       : 1);
+  reg_dead_endregno = END_REGNO (reg);
 
   reg_dead_flag = 0;
 
@@ -11247,14 +11919,13 @@ reg_dead_at_p (rtx reg, rtx insn)
     }
 
   for (i = reg_dead_regno; i < reg_dead_endregno; i++)
-    if (REGNO_REG_SET_P (block->il.rtl->global_live_at_start, i))
+    if (REGNO_REG_SET_P (df_get_live_in (block), i))
       return 0;
 
   return 1;
 }
 \f
-/* Note hard registers in X that are used.  This code is similar to
-   that in flow.c, but much simpler since we don't care about pseudos.  */
+/* Note hard registers in X that are used.  */
 
 static void
 mark_used_regs_combine (rtx x)
@@ -11295,8 +11966,6 @@ mark_used_regs_combine (rtx x)
         If so, mark all of them just like the first.  */
       if (regno < FIRST_PSEUDO_REGISTER)
        {
-         unsigned int endregno, r;
-
          /* None of this applies to the stack, frame or arg pointers.  */
          if (regno == STACK_POINTER_REGNUM
 #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
@@ -11308,9 +11977,7 @@ mark_used_regs_combine (rtx x)
              || regno == FRAME_POINTER_REGNUM)
            return;
 
-         endregno = regno + hard_regno_nregs[regno][GET_MODE (x)];
-         for (r = regno; r < endregno; r++)
-           SET_HARD_REG_BIT (newpat_used_regs, r);
+         add_to_hard_reg_set (&newpat_used_regs, GET_MODE (x), regno);
        }
       return;
 
@@ -11366,16 +12033,13 @@ remove_death (unsigned int regno, rtx insn)
   rtx note = find_regno_note (insn, REG_DEAD, regno);
 
   if (note)
-    {
-      REG_N_DEATHS (regno)--;
-      remove_note (insn, note);
-    }
+    remove_note (insn, note);
 
   return note;
 }
 
 /* For each register (hardware or pseudo) used within expression X, if its
-   death is in an instruction with cuid between FROM_CUID (inclusive) and
+   death is in an instruction with luid between FROM_LUID (inclusive) and
    TO_INSN (exclusive), put a REG_DEAD note for that register in the
    list headed by PNOTES.
 
@@ -11385,7 +12049,7 @@ remove_death (unsigned int regno, rtx insn)
    notes will then be distributed as needed.  */
 
 static void
-move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
+move_deaths (rtx x, rtx maybe_kill_insn, int from_luid, rtx to_insn,
             rtx *pnotes)
 {
   const char *fmt;
@@ -11395,29 +12059,16 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
   if (code == REG)
     {
       unsigned int regno = REGNO (x);
-      rtx where_dead = reg_stat[regno].last_death;
-      rtx before_dead, after_dead;
+      rtx where_dead = VEC_index (reg_stat_type, reg_stat, regno)->last_death;
 
       /* Don't move the register if it gets killed in between from and to.  */
       if (maybe_kill_insn && reg_set_p (x, maybe_kill_insn)
          && ! reg_referenced_p (x, maybe_kill_insn))
        return;
 
-      /* WHERE_DEAD could be a USE insn made by combine, so first we
-        make sure that we have insns with valid INSN_CUID values.  */
-      before_dead = where_dead;
-      while (before_dead && INSN_UID (before_dead) > max_uid_cuid)
-       before_dead = PREV_INSN (before_dead);
-
-      after_dead = where_dead;
-      while (after_dead && INSN_UID (after_dead) > max_uid_cuid)
-       after_dead = NEXT_INSN (after_dead);
-
-      if (before_dead && after_dead
-         && INSN_CUID (before_dead) >= from_cuid
-         && (INSN_CUID (after_dead) < INSN_CUID (to_insn)
-             || (where_dead != after_dead
-                 && INSN_CUID (after_dead) == INSN_CUID (to_insn))))
+      if (where_dead
+         && DF_INSN_LUID (where_dead) >= from_luid
+         && DF_INSN_LUID (where_dead) < DF_INSN_LUID (to_insn))
        {
          rtx note = remove_death (regno, where_dead);
 
@@ -11435,11 +12086,8 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
                  > GET_MODE_SIZE (GET_MODE (x))))
            {
              unsigned int deadregno = REGNO (XEXP (note, 0));
-             unsigned int deadend
-               = (deadregno + hard_regno_nregs[deadregno]
-                                              [GET_MODE (XEXP (note, 0))]);
-             unsigned int ourend
-               = regno + hard_regno_nregs[regno][GET_MODE (x)];
+             unsigned int deadend = END_HARD_REGNO (XEXP (note, 0));
+             unsigned int ourend = END_HARD_REGNO (x);
              unsigned int i;
 
              for (i = deadregno; i < deadend; i++)
@@ -11462,8 +12110,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
                   && regno < FIRST_PSEUDO_REGISTER
                   && hard_regno_nregs[regno][GET_MODE (x)] > 1)
            {
-             unsigned int ourend
-               = regno + hard_regno_nregs[regno][GET_MODE (x)];
+             unsigned int ourend = END_HARD_REGNO (x);
              unsigned int i, offset;
              rtx oldnotes = 0;
 
@@ -11474,7 +12121,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
 
              for (i = regno + offset; i < ourend; i++)
                move_deaths (regno_reg_rtx[i],
-                            maybe_kill_insn, from_cuid, to_insn, &oldnotes);
+                            maybe_kill_insn, from_luid, to_insn, &oldnotes);
            }
 
          if (note != 0 && GET_MODE (XEXP (note, 0)) == GET_MODE (x))
@@ -11484,8 +12131,6 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
            }
          else
            *pnotes = gen_rtx_EXPR_LIST (REG_DEAD, x, *pnotes);
-
-         REG_N_DEATHS (regno)++;
        }
 
       return;
@@ -11495,7 +12140,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
     {
       rtx dest = SET_DEST (x);
 
-      move_deaths (SET_SRC (x), maybe_kill_insn, from_cuid, to_insn, pnotes);
+      move_deaths (SET_SRC (x), maybe_kill_insn, from_luid, to_insn, pnotes);
 
       /* In the case of a ZERO_EXTRACT, a STRICT_LOW_PART, or a SUBREG
         that accesses one word of a multi-word item, some
@@ -11511,7 +12156,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
                  == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
                       + UNITS_PER_WORD - 1) / UNITS_PER_WORD))))
        {
-         move_deaths (dest, maybe_kill_insn, from_cuid, to_insn, pnotes);
+         move_deaths (dest, maybe_kill_insn, from_luid, to_insn, pnotes);
          return;
        }
 
@@ -11525,7 +12170,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
         being replaced so the old value is not used in this insn.  */
 
       if (MEM_P (dest))
-       move_deaths (XEXP (dest, 0), maybe_kill_insn, from_cuid,
+       move_deaths (XEXP (dest, 0), maybe_kill_insn, from_luid,
                     to_insn, pnotes);
       return;
     }
@@ -11542,11 +12187,11 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn,
        {
          int j;
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-           move_deaths (XVECEXP (x, i, j), maybe_kill_insn, from_cuid,
+           move_deaths (XVECEXP (x, i, j), maybe_kill_insn, from_luid,
                         to_insn, pnotes);
        }
       else if (fmt[i] == 'e')
-       move_deaths (XEXP (x, i), maybe_kill_insn, from_cuid, to_insn, pnotes);
+       move_deaths (XEXP (x, i), maybe_kill_insn, from_luid, to_insn, pnotes);
     }
 }
 \f
@@ -11581,8 +12226,8 @@ reg_bitfield_target_p (rtx x, rtx body)
       if (tregno >= FIRST_PSEUDO_REGISTER || regno >= FIRST_PSEUDO_REGISTER)
        return target == x;
 
-      endtregno = tregno + hard_regno_nregs[tregno][GET_MODE (target)];
-      endregno = regno + hard_regno_nregs[regno][GET_MODE (x)];
+      endtregno = end_hard_regno (GET_MODE (target), tregno);
+      endregno = end_hard_regno (GET_MODE (x), regno);
 
       return endregno > tregno && regno < endtregno;
     }
@@ -11617,12 +12262,6 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_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) && REG_P (XEXP (note, 0))
-         && 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))
        {
@@ -11785,7 +12424,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
          if (place && JUMP_P (place))
            {
              rtx label = JUMP_LABEL (place);
-             
+
              if (!label)
                JUMP_LABEL (place) = XEXP (note, 0);
              else
@@ -11799,7 +12438,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
          if (place2 && JUMP_P (place2))
            {
              rtx label = JUMP_LABEL (place2);
-             
+
              if (!label)
                JUMP_LABEL (place2) = XEXP (note, 0);
              else
@@ -11819,6 +12458,15 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
             to simply delete it.  */
          break;
 
+       case REG_LIBCALL_ID:
+         /* If the insn previously containing this note still exists,
+            put it back where it was.  Otherwise move it to the previous
+            insn.  */
+         if (!NOTE_P (from_insn))
+           place = from_insn;
+         else
+           place = prev_real_insn (from_insn);
+         break;
        case REG_RETVAL:
          /* If the insn previously containing this note still exists,
             put it back where it was.  Otherwise move it to the previous
@@ -11862,7 +12510,15 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_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
@@ -11877,29 +12533,34 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
             use of A and put the death note there.  */
 
          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;
-
-         if (place == 0
-             && (rtx_equal_p (XEXP (note, 0), elim_i2)
-                 || rtx_equal_p (XEXP (note, 0), elim_i1)))
-           break;
+             && from_insn == i2mod
+             && !reg_overlap_mentioned_p (XEXP (note, 0), i2mod_new_rhs))
+           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)
+                       && !(i2mod
+                            && reg_overlap_mentioned_p (XEXP (note, 0),
+                                                        i2mod_old_rhs)))
+                      || rtx_equal_p (XEXP (note, 0), elim_i1))
+               break;
+             tem = i3;
+           }
 
          if (place == 0)
            {
              basic_block bb = this_basic_block;
 
-             /* You might think you could search back from FROM_INSN
-                rather than from I3, but combine tries to split invalid
-                combined instructions.  This can result in the old I2
-                or I1 moving later in the insn sequence.  */
-             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))
                    {
@@ -11999,22 +12660,6 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
                           || (CALL_P (tem)
                               && find_reg_fusage (tem, USE, XEXP (note, 0))))
                    {
-                     /* This may not be the correct place for the death
-                        note if FROM_INSN is before TEM, and the reg is
-                        set between FROM_INSN and TEM.  The reg might
-                        die two or more times.  An existing death note
-                        means we are looking at the wrong live range.  */
-                     if (from_insn
-                         && INSN_CUID (from_insn) < INSN_CUID (tem)
-                         && find_regno_note (tem, REG_DEAD,
-                                             REGNO (XEXP (note, 0))))
-                       {
-                         tem = from_insn;
-                         if (tem == BB_HEAD (bb))
-                           break;
-                         continue;
-                       }
-
                      place = tem;
 
                      /* If we are doing a 3->2 combination, and we have a
@@ -12023,10 +12668,9 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
                         i2 but does not die in i2, and place is between i2
                         and i3, then we may need to move a link from place to
                         i2.  */
-                     if (i2 && INSN_UID (place) <= max_uid_cuid
-                         && INSN_CUID (place) > INSN_CUID (i2)
+                     if (i2 && DF_INSN_LUID (place) > DF_INSN_LUID (i2)
                          && from_insn
-                         && INSN_CUID (from_insn) > INSN_CUID (i2)
+                         && DF_INSN_LUID (from_insn) > DF_INSN_LUID (i2)
                          && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
                        {
                          rtx links = LOG_LINKS (place);
@@ -12040,15 +12684,6 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
                    break;
                }
 
-             /* We haven't found an insn for the death note and it
-                is still a REG_DEAD note, but we have hit the beginning
-                of the block.  If the existing life info says the reg
-                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->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
@@ -12060,12 +12695,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
          if (place && REG_NOTE_KIND (note) == REG_DEAD)
            {
              unsigned int regno = REGNO (XEXP (note, 0));
-
-             /* Similarly, if the instruction on which we want to place
-                the note is a noop, we'll need do a global live update
-                after we remove them in delete_noop_moves.  */
-             if (noop_move_p (place))
-               SET_BIT (refresh_blocks, this_basic_block->index);
+             reg_stat_type *rsp = VEC_index (reg_stat_type, reg_stat, regno);
 
              if (dead_or_set_p (place, XEXP (note, 0))
                  || reg_bitfield_target_p (XEXP (note, 0), PATTERN (place)))
@@ -12073,12 +12703,12 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
                  /* Unless the register previously died in PLACE, clear
                     last_death.  [I no longer understand why this is
                     being done.] */
-                 if (reg_stat[regno].last_death != place)
-                   reg_stat[regno].last_death = 0;
+                 if (rsp->last_death != place)
+                   rsp->last_death = 0;
                  place = 0;
                }
              else
-               reg_stat[regno].last_death = place;
+               rsp->last_death = place;
 
              /* If this is a death note for a hard reg that is occupying
                 multiple registers, ensure that we are still using all
@@ -12092,9 +12722,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
              if (place && regno < FIRST_PSEUDO_REGISTER
                  && hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))] > 1)
                {
-                 unsigned int endregno
-                   = regno + hard_regno_nregs[regno]
-                                             [GET_MODE (XEXP (note, 0))];
+                 unsigned int endregno = END_HARD_REGNO (XEXP (note, 0));
                  int all_used = 1;
                  unsigned int i;
 
@@ -12134,11 +12762,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
                                if (! INSN_P (tem))
                                  {
                                    if (tem == BB_HEAD (bb))
-                                     {
-                                       SET_BIT (refresh_blocks,
-                                                this_basic_block->index);
-                                       break;
-                                     }
+                                     break;
                                    continue;
                                  }
                                if (dead_or_set_p (tem, piece)
@@ -12171,23 +12795,11 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
          XEXP (note, 1) = REG_NOTES (place);
          REG_NOTES (place) = note;
        }
-      else if ((REG_NOTE_KIND (note) == REG_DEAD
-               || REG_NOTE_KIND (note) == REG_UNUSED)
-              && 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)
-             && REG_P (XEXP (note, 0)))
-           REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
-
-         REG_NOTES (place2) = gen_rtx_fmt_ee (GET_CODE (note),
-                                              REG_NOTE_KIND (note),
-                                              XEXP (note, 0),
-                                              REG_NOTES (place2));
-       }
+       REG_NOTES (place2) 
+         = gen_rtx_fmt_ee (GET_CODE (note), REG_NOTE_KIND (note),
+                           XEXP (note, 0), REG_NOTES (place2));
     }
 }
 \f
@@ -12275,7 +12887,7 @@ distribute_links (rtx links)
              /* Set added_links_insn to the earliest insn we added a
                 link to.  */
              if (added_links_insn == 0
-                 || INSN_CUID (added_links_insn) > INSN_CUID (place))
+                 || DF_INSN_LUID (added_links_insn) > DF_INSN_LUID (place))
                added_links_insn = place;
            }
        }
@@ -12309,20 +12921,6 @@ unmentioned_reg_p (rtx equiv, rtx expr)
   return for_each_rtx (&equiv, unmentioned_reg_p_1, expr);
 }
 \f
-/* Compute INSN_CUID for INSN, which is an insn made by combine.  */
-
-static int
-insn_cuid (rtx insn)
-{
-  while (insn != 0 && INSN_UID (insn) > max_uid_cuid
-        && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == USE)
-    insn = NEXT_INSN (insn);
-
-  gcc_assert (INSN_UID (insn) <= max_uid_cuid);
-
-  return INSN_CUID (insn);
-}
-\f
 void
 dump_combine_stats (FILE *file)
 {
@@ -12341,7 +12939,6 @@ dump_combine_total_stats (FILE *file)
      total_attempts, total_merges, total_extras, total_successes);
 }
 \f
-
 static bool
 gate_handle_combine (void)
 {
@@ -12349,10 +12946,18 @@ gate_handle_combine (void)
 }
 
 /* Try combining insns through substitution.  */
-static void
+static unsigned int
 rest_of_handle_combine (void)
 {
-  int rebuild_jump_labels_after_combine
+  int rebuild_jump_labels_after_combine;
+
+  df_set_flags (DF_LR_RUN_DCE + DF_DEFER_INSN_RESCAN);
+  df_note_add_problem ();
+  df_analyze ();
+
+  regstat_init_n_sets_and_refs ();
+
+  rebuild_jump_labels_after_combine
     = combine_instructions (get_insns (), max_reg_num ());
 
   /* Combining insns may have turned an indirect jump into a
@@ -12362,11 +12967,12 @@ rest_of_handle_combine (void)
     {
       timevar_push (TV_JUMP);
       rebuild_jump_labels (get_insns ());
+      cleanup_cfg (0);
       timevar_pop (TV_JUMP);
-
-      delete_dead_jumptables ();
-      cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE);
     }
+
+  regstat_free_n_sets_and_refs ();
+  return 0;
 }
 
 struct tree_opt_pass pass_combine =
@@ -12383,6 +12989,7 @@ struct tree_opt_pass pass_combine =
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   TODO_dump_func |
+  TODO_df_finish |
   TODO_ggc_collect,                     /* todo_flags_finish */
   'c'                                   /* letter */
 };