OSDN Git Service

2011-05-04 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 1f8e970..0e6d65f 100644 (file)
@@ -1,7 +1,7 @@
 /* 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, 2006, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+   2011 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -93,7 +93,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "insn-attr.h"
 #include "recog.h"
 #include "diagnostic-core.h"
-#include "toplev.h"
 #include "target.h"
 #include "optabs.h"
 #include "insn-codes.h"
@@ -105,6 +104,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "df.h"
 #include "cgraph.h"
+#include "obstack.h"
 
 /* Number of attempts to combine instructions in this function.  */
 
@@ -310,13 +310,38 @@ static int max_uid_known;
 static int *uid_insn_cost;
 
 /* The following array records the LOG_LINKS for every insn in the
-   instruction stream as an INSN_LIST rtx.  */
+   instruction stream as struct insn_link pointers.  */
 
-static rtx *uid_log_links;
+struct insn_link {
+  rtx insn;
+  struct insn_link *next;
+};
+
+static struct insn_link **uid_log_links;
 
 #define INSN_COST(INSN)                (uid_insn_cost[INSN_UID (INSN)])
 #define LOG_LINKS(INSN)                (uid_log_links[INSN_UID (INSN)])
 
+#define FOR_EACH_LOG_LINK(L, INSN)                             \
+  for ((L) = LOG_LINKS (INSN); (L); (L) = (L)->next)
+
+/* Links for LOG_LINKS are allocated from this obstack.  */
+
+static struct obstack insn_link_obstack;
+
+/* Allocate a link.  */
+
+static inline struct insn_link *
+alloc_insn_link (rtx insn, struct insn_link *next)
+{
+  struct insn_link *l
+    = (struct insn_link *) obstack_alloc (&insn_link_obstack,
+                                         sizeof (struct insn_link));
+  l->insn = insn;
+  l->next = next;
+  return l;
+}
+
 /* Incremented for each basic block.  */
 
 static int label_tick;
@@ -388,12 +413,12 @@ static int cant_combine_insn_p (rtx);
 static int can_combine_p (rtx, rtx, rtx, rtx, rtx, rtx, rtx *, rtx *);
 static int combinable_i3pat (rtx, rtx *, rtx, rtx, rtx, int, int, rtx *);
 static int contains_muldiv (rtx);
-static rtx try_combine (rtx, rtx, rtx, rtx, int *);
+static rtx try_combine (rtx, rtx, rtx, rtx, int *, rtx);
 static void undo_all (void);
 static void undo_commit (void);
 static rtx *find_split_point (rtx *, rtx, bool);
-static rtx subst (rtx, rtx, rtx, int, int);
-static rtx combine_simplify_rtx (rtx, enum machine_mode, int);
+static rtx subst (rtx, rtx, rtx, int, int, int);
+static rtx combine_simplify_rtx (rtx, enum machine_mode, int, int);
 static rtx simplify_if_then_else (rtx);
 static rtx simplify_set (rtx);
 static rtx simplify_logical (rtx);
@@ -439,7 +464,7 @@ 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, rtx);
-static void distribute_links (rtx);
+static void distribute_links (struct insn_link *);
 static void mark_used_regs_combine (rtx);
 static void record_promoted_value (rtx, rtx);
 static int unmentioned_reg_p_1 (rtx *, void *);
@@ -610,7 +635,7 @@ find_single_use (rtx dest, rtx insn, rtx *ploc)
   basic_block bb;
   rtx next;
   rtx *result;
-  rtx link;
+  struct insn_link *link;
 
 #ifdef HAVE_cc0
   if (dest == cc0_rtx)
@@ -636,8 +661,8 @@ find_single_use (rtx dest, rtx insn, rtx *ploc)
        next = NEXT_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)
+       FOR_EACH_LOG_LINK (link, next)
+         if (link->insn == insn)
            break;
 
        if (link)
@@ -764,14 +789,13 @@ do_SUBST_MODE (rtx *into, enum machine_mode newval)
 
 #define SUBST_MODE(INTO, NEWVAL)  do_SUBST_MODE(&(INTO), (NEWVAL))
 \f
-/* Subroutine of try_combine.  Determine whether the combine replacement
-   patterns NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to
-   insn_rtx_cost that the original instruction sequence I0, 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.  */
+/* Subroutine of try_combine.  Determine whether the replacement patterns
+   NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to insn_rtx_cost
+   than the original sequence I0, I1, I2, I3 and undobuf.other_insn.  Note
+   that I0, I1 and/or NEWI2PAT may be NULL_RTX.  Similarly, NEWOTHERPAT and
+   undobuf.other_insn may also both be NULL_RTX.  Return false if the cost
+   of all the instructions can be estimated and the replacements are more
+   expensive than the original sequence.  */
 
 static bool
 combine_validate_cost (rtx i0, rtx i1, rtx i2, rtx i3, rtx newpat,
@@ -836,10 +860,9 @@ combine_validate_cost (rtx i0, rtx i1, rtx i2, rtx i3, rtx newpat,
        old_cost = 0;
     }
 
-  /* Disallow this recombination if both new_cost and old_cost are
-     greater than zero, and new_cost is greater than old cost.  */
-  if (old_cost > 0
-      && new_cost > old_cost)
+  /* Disallow this combination if both new_cost and old_cost are greater than
+     zero, and new_cost is greater than old cost.  */
+  if (old_cost > 0 && new_cost > old_cost)
     {
       if (dump_file)
        {
@@ -885,7 +908,11 @@ combine_validate_cost (rtx i0, rtx i1, rtx i2, rtx i3, rtx newpat,
   INSN_COST (i2) = new_i2_cost;
   INSN_COST (i3) = new_i3_cost;
   if (i1)
-    INSN_COST (i1) = 0;
+    {
+      INSN_COST (i1) = 0;
+      if (i0)
+       INSN_COST (i0) = 0;
+    }
 
   return true;
 }
@@ -962,7 +989,7 @@ create_log_links (void)
               /* 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
+#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
                   || (regno == HARD_FRAME_POINTER_REGNUM
                       && (! reload_completed || frame_pointer_needed))
 #endif
@@ -986,15 +1013,14 @@ create_log_links (void)
                       || asm_noperands (PATTERN (use_insn)) < 0)
                    {
                      /* Don't add duplicate links between instructions.  */
-                     rtx links;
-                     for (links = LOG_LINKS (use_insn); links;
-                          links = XEXP (links, 1))
-                       if (insn == XEXP (links, 0))
+                     struct insn_link *links;
+                     FOR_EACH_LOG_LINK (links, use_insn)
+                       if (insn == links->insn)
                          break;
 
                      if (!links)
-                       LOG_LINKS (use_insn) =
-                         alloc_INSN_LIST (insn, LOG_LINKS (use_insn));
+                       LOG_LINKS (use_insn)
+                         = alloc_insn_link (insn, LOG_LINKS (use_insn));
                    }
                 }
               next_use[regno] = NULL_RTX;
@@ -1018,30 +1044,24 @@ create_log_links (void)
   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));
-}
-
 /* Walk the LOG_LINKS of insn B to see if we find a reference to A.  Return
    true if we found a LOG_LINK that proves that A feeds B.  This only works
    if there are no instructions between A and B which could have a link
-   depending on A, since in that case we would not record a link for B.  */
+   depending on A, since in that case we would not record a link for B.
+   We also check the implicit dependency created by a cc0 setter/user
+   pair.  */
 
 static bool
 insn_a_feeds_b (rtx a, rtx b)
 {
-  rtx links;
-  for (links = LOG_LINKS (b); links; links = XEXP (links, 1))
-    if (XEXP (links, 0) == a)
+  struct insn_link *links;
+  FOR_EACH_LOG_LINK (links, b)
+    if (links->insn == a)
       return true;
+#ifdef HAVE_cc0
+  if (sets_cc0_p (a))
+    return true;
+#endif
   return false;
 }
 \f
@@ -1057,7 +1077,7 @@ combine_instructions (rtx f, unsigned int nregs)
 #ifdef HAVE_cc0
   rtx prev;
 #endif
-  rtx links, nextlinks;
+  struct insn_link *links, *nextlinks;
   rtx first;
   basic_block last_bb;
 
@@ -1081,8 +1101,9 @@ combine_instructions (rtx f, unsigned int nregs)
 
   /* Allocate array for insn info.  */
   max_uid_known = get_max_uid ();
-  uid_log_links = XCNEWVEC (rtx, max_uid_known + 1);
+  uid_log_links = XCNEWVEC (struct insn_link *, max_uid_known + 1);
   uid_insn_cost = XCNEWVEC (int, max_uid_known + 1);
+  gcc_obstack_init (&insn_link_obstack);
 
   nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
 
@@ -1120,6 +1141,10 @@ combine_instructions (rtx f, unsigned int nregs)
       FOR_BB_INSNS (this_basic_block, insn)
         if (INSN_P (insn) && BLOCK_FOR_INSN (insn))
          {
+#ifdef AUTO_INC_DEC
+            rtx links;
+#endif
+
             subst_low_luid = DF_INSN_LUID (insn);
             subst_insn = insn;
 
@@ -1154,6 +1179,7 @@ combine_instructions (rtx f, unsigned int nregs)
 
   FOR_EACH_BB (this_basic_block)
     {
+      rtx last_combined_insn = NULL_RTX;
       optimize_this_for_speed_p = optimize_bb_for_speed_p (this_basic_block);
       last_call_luid = 0;
       mem_last_set = -1;
@@ -1172,6 +1198,15 @@ combine_instructions (rtx f, unsigned int nregs)
          next = 0;
          if (NONDEBUG_INSN_P (insn))
            {
+             while (last_combined_insn
+                    && INSN_DELETED_P (last_combined_insn))
+               last_combined_insn = PREV_INSN (last_combined_insn);
+             if (last_combined_insn == NULL_RTX
+                 || BARRIER_P (last_combined_insn)
+                 || BLOCK_FOR_INSN (last_combined_insn) != this_basic_block
+                 || DF_INSN_LUID (last_combined_insn) <= DF_INSN_LUID (insn))
+               last_combined_insn = insn;
+
              /* See if we know about function return values before this
                 insn based upon SUBREG flags.  */
              check_promoted_subreg (insn, PATTERN (insn));
@@ -1183,28 +1218,27 @@ combine_instructions (rtx f, unsigned int nregs)
 
              /* Try this insn with each insn it links back to.  */
 
-             for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
-               if ((next = try_combine (insn, XEXP (links, 0), NULL_RTX,
-                                        NULL_RTX, &new_direct_jump_p)) != 0)
+             FOR_EACH_LOG_LINK (links, insn)
+               if ((next = try_combine (insn, links->insn, NULL_RTX,
+                                        NULL_RTX, &new_direct_jump_p,
+                                        last_combined_insn)) != 0)
                  goto retry;
 
              /* Try each sequence of three linked insns ending with this one.  */
 
-             for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
+             FOR_EACH_LOG_LINK (links, insn)
                {
-                 rtx link = XEXP (links, 0);
+                 rtx link = links->insn;
 
                  /* If the linked insn has been replaced by a note, then there
                     is no point in pursuing this chain any further.  */
                  if (NOTE_P (link))
                    continue;
 
-                 for (nextlinks = LOG_LINKS (link);
-                      nextlinks;
-                      nextlinks = XEXP (nextlinks, 1))
-                   if ((next = try_combine (insn, link, XEXP (nextlinks, 0),
-                                            NULL_RTX,
-                                            &new_direct_jump_p)) != 0)
+                 FOR_EACH_LOG_LINK (nextlinks, link)
+                   if ((next = try_combine (insn, link, nextlinks->insn,
+                                            NULL_RTX, &new_direct_jump_p,
+                                            last_combined_insn)) != 0)
                      goto retry;
                }
 
@@ -1222,14 +1256,14 @@ combine_instructions (rtx f, unsigned int nregs)
                  && sets_cc0_p (PATTERN (prev)))
                {
                  if ((next = try_combine (insn, prev, NULL_RTX, NULL_RTX,
-                                          &new_direct_jump_p)) != 0)
+                                          &new_direct_jump_p,
+                                          last_combined_insn)) != 0)
                    goto retry;
 
-                 for (nextlinks = LOG_LINKS (prev); nextlinks;
-                      nextlinks = XEXP (nextlinks, 1))
-                   if ((next = try_combine (insn, prev, XEXP (nextlinks, 0),
-                                            NULL_RTX,
-                                            &new_direct_jump_p)) != 0)
+                 FOR_EACH_LOG_LINK (nextlinks, prev)
+                   if ((next = try_combine (insn, prev, nextlinks->insn,
+                                            NULL_RTX, &new_direct_jump_p,
+                                            last_combined_insn)) != 0)
                      goto retry;
                }
 
@@ -1242,102 +1276,104 @@ combine_instructions (rtx f, unsigned int nregs)
                  && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (insn))))
                {
                  if ((next = try_combine (insn, prev, NULL_RTX, NULL_RTX,
-                                          &new_direct_jump_p)) != 0)
+                                          &new_direct_jump_p,
+                                          last_combined_insn)) != 0)
                    goto retry;
 
-                 for (nextlinks = LOG_LINKS (prev); nextlinks;
-                      nextlinks = XEXP (nextlinks, 1))
-                   if ((next = try_combine (insn, prev, XEXP (nextlinks, 0),
-                                            NULL_RTX,
-                                            &new_direct_jump_p)) != 0)
+                 FOR_EACH_LOG_LINK (nextlinks, prev)
+                   if ((next = try_combine (insn, prev, nextlinks->insn,
+                                            NULL_RTX, &new_direct_jump_p,
+                                            last_combined_insn)) != 0)
                      goto retry;
                }
 
              /* Finally, see if any of the insns that this insn links to
                 explicitly references CC0.  If so, try this insn, that insn,
                 and its predecessor if it sets CC0.  */
-             for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
-               if (NONJUMP_INSN_P (XEXP (links, 0))
-                   && GET_CODE (PATTERN (XEXP (links, 0))) == SET
-                   && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (XEXP (links, 0))))
-                   && (prev = prev_nonnote_insn (XEXP (links, 0))) != 0
+             FOR_EACH_LOG_LINK (links, insn)
+               if (NONJUMP_INSN_P (links->insn)
+                   && GET_CODE (PATTERN (links->insn)) == SET
+                   && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (links->insn)))
+                   && (prev = prev_nonnote_insn (links->insn)) != 0
                    && NONJUMP_INSN_P (prev)
                    && sets_cc0_p (PATTERN (prev))
-                   && (next = try_combine (insn, XEXP (links, 0),
-                                           prev, NULL_RTX,
-                                           &new_direct_jump_p)) != 0)
+                   && (next = try_combine (insn, links->insn,
+                                           prev, NULL_RTX, &new_direct_jump_p,
+                                           last_combined_insn)) != 0)
                  goto retry;
 #endif
 
              /* Try combining an insn with two different insns whose results it
                 uses.  */
-             for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
-               for (nextlinks = XEXP (links, 1); nextlinks;
-                    nextlinks = XEXP (nextlinks, 1))
-                 if ((next = try_combine (insn, XEXP (links, 0),
-                                          XEXP (nextlinks, 0), NULL_RTX,
-                                          &new_direct_jump_p)) != 0)
+             FOR_EACH_LOG_LINK (links, insn)
+               for (nextlinks = links->next; nextlinks;
+                    nextlinks = nextlinks->next)
+                 if ((next = try_combine (insn, links->insn,
+                                          nextlinks->insn, NULL_RTX,
+                                          &new_direct_jump_p,
+                                          last_combined_insn)) != 0)
                    goto retry;
 
              /* Try four-instruction combinations.  */
-             for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
+             FOR_EACH_LOG_LINK (links, insn)
                {
-                 rtx next1;
-                 rtx link = XEXP (links, 0);
+                 struct insn_link *next1;
+                 rtx link = links->insn;
 
                  /* If the linked insn has been replaced by a note, then there
                     is no point in pursuing this chain any further.  */
                  if (NOTE_P (link))
                    continue;
 
-                 for (next1 = LOG_LINKS (link); next1; next1 = XEXP (next1, 1))
+                 FOR_EACH_LOG_LINK (next1, link)
                    {
-                     rtx link1 = XEXP (next1, 0);
+                     rtx link1 = next1->insn;
                      if (NOTE_P (link1))
                        continue;
                      /* I0 -> I1 -> I2 -> I3.  */
-                     for (nextlinks = LOG_LINKS (link1); nextlinks;
-                          nextlinks = XEXP (nextlinks, 1))
+                     FOR_EACH_LOG_LINK (nextlinks, link1)
                        if ((next = try_combine (insn, link, link1,
-                                                XEXP (nextlinks, 0),
-                                                &new_direct_jump_p)) != 0)
+                                                nextlinks->insn,
+                                                &new_direct_jump_p,
+                                                last_combined_insn)) != 0)
                          goto retry;
                      /* I0, I1 -> I2, I2 -> I3.  */
-                     for (nextlinks = XEXP (next1, 1); nextlinks;
-                          nextlinks = XEXP (nextlinks, 1))
+                     for (nextlinks = next1->next; nextlinks;
+                          nextlinks = nextlinks->next)
                        if ((next = try_combine (insn, link, link1,
-                                                XEXP (nextlinks, 0),
-                                                &new_direct_jump_p)) != 0)
+                                                nextlinks->insn,
+                                                &new_direct_jump_p,
+                                                last_combined_insn)) != 0)
                          goto retry;
                    }
 
-                 for (next1 = XEXP (links, 1); next1; next1 = XEXP (next1, 1))
+                 for (next1 = links->next; next1; next1 = next1->next)
                    {
-                     rtx link1 = XEXP (next1, 0);
+                     rtx link1 = next1->insn;
                      if (NOTE_P (link1))
                        continue;
                      /* I0 -> I2; I1, I2 -> I3.  */
-                     for (nextlinks = LOG_LINKS (link); nextlinks;
-                          nextlinks = XEXP (nextlinks, 1))
+                     FOR_EACH_LOG_LINK (nextlinks, link)
                        if ((next = try_combine (insn, link, link1,
-                                                XEXP (nextlinks, 0),
-                                                &new_direct_jump_p)) != 0)
+                                                nextlinks->insn,
+                                                &new_direct_jump_p,
+                                                last_combined_insn)) != 0)
                          goto retry;
                      /* I0 -> I1; I1, I2 -> I3.  */
-                     for (nextlinks = LOG_LINKS (link1); nextlinks;
-                          nextlinks = XEXP (nextlinks, 1))
+                     FOR_EACH_LOG_LINK (nextlinks, link1)
                        if ((next = try_combine (insn, link, link1,
-                                                XEXP (nextlinks, 0),
-                                                &new_direct_jump_p)) != 0)
+                                                nextlinks->insn,
+                                                &new_direct_jump_p,
+                                                last_combined_insn)) != 0)
                          goto retry;
                    }
                }
 
              /* Try this insn with each REG_EQUAL note it links back to.  */
-             for (links = LOG_LINKS (insn); links; links = XEXP (links, 1))
+             FOR_EACH_LOG_LINK (links, insn)
                {
                  rtx set, note;
-                 rtx temp = XEXP (links, 0);
+                 rtx temp = links->insn;
                  if ((set = single_set (temp)) != 0
                      && (note = find_reg_equal_equiv_note (temp)) != 0
                      && (note = XEXP (note, 0), GET_CODE (note)) != EXPR_LIST
@@ -1357,7 +1393,8 @@ combine_instructions (rtx f, unsigned int nregs)
                      i2mod_old_rhs = copy_rtx (orig);
                      i2mod_new_rhs = copy_rtx (note);
                      next = try_combine (insn, i2mod, NULL_RTX, NULL_RTX,
-                                         &new_direct_jump_p);
+                                         &new_direct_jump_p,
+                                         last_combined_insn);
                      i2mod = NULL_RTX;
                      if (next)
                        goto retry;
@@ -1375,12 +1412,12 @@ combine_instructions (rtx f, unsigned int nregs)
     }
 
   default_rtl_profile ();
-  clear_log_links ();
   clear_bb_flags ();
   new_direct_jump_p |= purge_all_dead_edges ();
   delete_noop_moves ();
 
   /* Clean up.  */
+  obstack_free (&insn_link_obstack, NULL);
   free (uid_log_links);
   free (uid_insn_cost);
   VEC_free (reg_stat_type, heap, reg_stat);
@@ -1551,13 +1588,11 @@ set_nonzero_bits_and_sign_copies (rtx x, const_rtx set, void *data)
          && !REGNO_REG_SET_P (DF_LR_IN (BLOCK_FOR_INSN (insn)),
                               REGNO (x)))
        {
-         rtx link;
+         struct insn_link *link;
 
-         for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
-           {
-             if (dead_or_set_p (XEXP (link, 0), x))
-               break;
-           }
+         FOR_EACH_LOG_LINK (link, insn)
+           if (dead_or_set_p (link->insn, x))
+             break;
          if (!link)
            {
              rsp->nonzero_bits = GET_MODE_MASK (GET_MODE (x));
@@ -1594,11 +1629,11 @@ set_nonzero_bits_and_sign_copies (rtx x, const_rtx set, void *data)
          if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD
              && CONST_INT_P (src)
              && INTVAL (src) > 0
-             && 0 != (INTVAL (src)
-                      & ((HOST_WIDE_INT) 1
+             && 0 != (UINTVAL (src)
+                      & ((unsigned HOST_WIDE_INT) 1
                          << (GET_MODE_BITSIZE (GET_MODE (x)) - 1))))
-           src = GEN_INT (INTVAL (src)
-                          | ((HOST_WIDE_INT) (-1)
+           src = GEN_INT (UINTVAL (src)
+                          | ((unsigned HOST_WIDE_INT) (-1)
                              << GET_MODE_BITSIZE (GET_MODE (x))));
 #endif
 
@@ -2049,7 +2084,7 @@ combinable_i3pat (rtx i3, rtx *loc, rtx i2dest, rtx i1dest, rtx i0dest,
          && REG_P (subdest)
          && reg_referenced_p (subdest, PATTERN (i3))
          && REGNO (subdest) != FRAME_POINTER_REGNUM
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
          && REGNO (subdest) != HARD_FRAME_POINTER_REGNUM
 #endif
 #if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
@@ -2091,7 +2126,7 @@ contains_muldiv (rtx x)
 
     case MULT:
       return ! (CONST_INT_P (XEXP (x, 1))
-               && exact_log2 (INTVAL (XEXP (x, 1))) >= 0);
+               && exact_log2 (UINTVAL (XEXP (x, 1))) >= 0);
     default:
       if (BINARY_P (x))
        return contains_muldiv (XEXP (x, 0))
@@ -2137,12 +2172,12 @@ cant_combine_insn_p (rtx insn)
   if (GET_CODE (dest) == SUBREG)
     dest = SUBREG_REG (dest);
   if (REG_P (src) && REG_P (dest)
-      && ((REGNO (src) < FIRST_PSEUDO_REGISTER
-          && ! fixed_regs[REGNO (src)]
-          && CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (src))))
-         || (REGNO (dest) < FIRST_PSEUDO_REGISTER
-             && ! fixed_regs[REGNO (dest)]
-             && CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (dest))))))
+      && ((HARD_REGISTER_P (src)
+          && ! TEST_HARD_REG_BIT (fixed_reg_set, REGNO (src))
+          && targetm.class_likely_spilled_p (REGNO_REG_CLASS (REGNO (src))))
+         || (HARD_REGISTER_P (dest)
+             && ! TEST_HARD_REG_BIT (fixed_reg_set, REGNO (dest))
+             && targetm.class_likely_spilled_p (REGNO_REG_CLASS (REGNO (dest))))))
     return 1;
 
   return 0;
@@ -2223,7 +2258,7 @@ likely_spilled_retval_p (rtx insn)
   do
     {
       if ((mask & 1 << nregs)
-         && CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (regno + nregs)))
+         && targetm.class_likely_spilled_p (REGNO_REG_CLASS (regno + nregs)))
        return 1;
     } while (nregs--);
   return 0;
@@ -2243,7 +2278,7 @@ adjust_for_new_dest (rtx 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));
+  distribute_links (alloc_insn_link (insn, NULL));
 
   df_insn_rescan (insn);
 }
@@ -2292,13 +2327,11 @@ reg_subword_p (rtx x, rtx reg)
 }
 
 #ifdef AUTO_INC_DEC
-/* Replace auto-increment addressing modes with explicit operations to
-   access the same addresses without modifying the corresponding
-   registers.  If AFTER holds, SRC is meant to be reused after the
-   side effect, otherwise it is to be reused before that.  */
+/* Replace auto-increment addressing modes with explicit operations to access
+   the same addresses without modifying the corresponding registers.  */
 
 static rtx
-cleanup_auto_inc_dec (rtx src, bool after, enum machine_mode mem_mode)
+cleanup_auto_inc_dec (rtx src, enum machine_mode mem_mode)
 {
   rtx x = src;
   const RTX_CODE code = GET_CODE (x);
@@ -2335,26 +2368,20 @@ cleanup_auto_inc_dec (rtx src, bool after, enum machine_mode mem_mode)
 
     case PRE_INC:
     case PRE_DEC:
-    case POST_INC:
-    case POST_DEC:
       gcc_assert (mem_mode != VOIDmode && mem_mode != BLKmode);
-      if (after == (code == PRE_INC || code == PRE_DEC))
-       x = cleanup_auto_inc_dec (XEXP (x, 0), after, mem_mode);
-      else
-       x = gen_rtx_PLUS (GET_MODE (x),
-                         cleanup_auto_inc_dec (XEXP (x, 0), after, mem_mode),
-                         GEN_INT ((code == PRE_INC || code == POST_INC)
-                                  ? GET_MODE_SIZE (mem_mode)
-                                  : -GET_MODE_SIZE (mem_mode)));
-      return x;
+      return gen_rtx_PLUS (GET_MODE (x),
+                          cleanup_auto_inc_dec (XEXP (x, 0), mem_mode),
+                          GEN_INT (code == PRE_INC
+                                   ? GET_MODE_SIZE (mem_mode)
+                                   : -GET_MODE_SIZE (mem_mode)));
 
+    case POST_INC:
+    case POST_DEC:
     case PRE_MODIFY:
     case POST_MODIFY:
-      if (after == (code == PRE_MODIFY))
-       x = XEXP (x, 0);
-      else
-       x = XEXP (x, 1);
-      return cleanup_auto_inc_dec (x, after, mem_mode);
+      return cleanup_auto_inc_dec (code == PRE_MODIFY
+                                  ? XEXP (x, 1) : XEXP (x, 0),
+                                  mem_mode);
 
     default:
       break;
@@ -2377,14 +2404,14 @@ cleanup_auto_inc_dec (rtx src, bool after, enum machine_mode mem_mode)
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     if (fmt[i] == 'e')
-      XEXP (x, i) = cleanup_auto_inc_dec (XEXP (x, i), after, mem_mode);
+      XEXP (x, i) = cleanup_auto_inc_dec (XEXP (x, i), mem_mode);
     else if (fmt[i] == 'E' || fmt[i] == 'V')
       {
        int j;
        XVEC (x, i) = rtvec_alloc (XVECLEN (x, i));
        for (j = 0; j < XVECLEN (x, i); j++)
          XVECEXP (x, i, j)
-           = cleanup_auto_inc_dec (XVECEXP (src, i, j), after, mem_mode);
+           = cleanup_auto_inc_dec (XVECEXP (src, i, j), mem_mode);
       }
 
   return x;
@@ -2397,7 +2424,6 @@ struct rtx_subst_pair
 {
   rtx to;
   bool adjusted;
-  bool after;
 };
 
 /* DATA points to an rtx_subst_pair.  Return the value that should be
@@ -2414,7 +2440,7 @@ propagate_for_debug_subst (rtx from, const_rtx old_rtx, void *data)
     {
       pair->adjusted = true;
 #ifdef AUTO_INC_DEC
-      pair->to = cleanup_auto_inc_dec (pair->to, pair->after, VOIDmode);
+      pair->to = cleanup_auto_inc_dec (pair->to, VOIDmode);
 #else
       pair->to = copy_rtx (pair->to);
 #endif
@@ -2424,22 +2450,22 @@ propagate_for_debug_subst (rtx from, const_rtx old_rtx, void *data)
   return copy_rtx (pair->to);
 }
 
-/* Replace occurrences of DEST with SRC in DEBUG_INSNs between INSN
-   and LAST.  If MOVE holds, debug insns must also be moved past
-   LAST.  */
+/* Replace all the occurrences of DEST with SRC in DEBUG_INSNs between INSN
+   and LAST, not including INSN, but including LAST.  Also stop at the end
+   of THIS_BASIC_BLOCK.  */
 
 static void
-propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src, bool move)
+propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src)
 {
-  rtx next, move_pos = move ? last : NULL_RTX, loc;
+  rtx next, loc, end = NEXT_INSN (BB_END (this_basic_block));
 
   struct rtx_subst_pair p;
   p.to = src;
   p.adjusted = false;
-  p.after = move;
 
   next = NEXT_INSN (insn);
-  while (next != last)
+  last = NEXT_INSN (last);
+  while (next != last && next != end)
     {
       insn = next;
       next = NEXT_INSN (insn);
@@ -2450,14 +2476,7 @@ propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src, bool move)
          if (loc == INSN_VAR_LOCATION_LOC (insn))
            continue;
          INSN_VAR_LOCATION_LOC (insn) = loc;
-         if (move_pos)
-           {
-             remove_insn (insn);
-             PREV_INSN (insn) = NEXT_INSN (insn) = NULL_RTX;
-             move_pos = emit_debug_insn_after (insn, move_pos);
-           }
-         else
-           df_insn_rescan (insn);
+         df_insn_rescan (insn);
        }
     }
 }
@@ -2471,14 +2490,31 @@ static void
 update_cfg_for_uncondjump (rtx insn)
 {
   basic_block bb = BLOCK_FOR_INSN (insn);
-  bool at_end = (BB_END (bb) == insn);
+  gcc_assert (BB_END (bb) == insn);
 
-  if (at_end)
-    purge_dead_edges (bb);
+  purge_dead_edges (bb);
 
   delete_insn (insn);
-  if (at_end && EDGE_COUNT (bb->succs) == 1)
-    single_succ_edge (bb)->flags |= EDGE_FALLTHRU;
+  if (EDGE_COUNT (bb->succs) == 1)
+    {
+      rtx insn;
+
+      single_succ_edge (bb)->flags |= EDGE_FALLTHRU;
+
+      /* Remove barriers from the footer if there are any.  */
+      for (insn = bb->il.rtl->footer; insn; insn = NEXT_INSN (insn))
+       if (BARRIER_P (insn))
+         {
+           if (PREV_INSN (insn))
+             NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
+           else
+             bb->il.rtl->footer = NEXT_INSN (insn);
+           if (NEXT_INSN (insn))
+             PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
+         }
+       else if (LABEL_P (insn))
+         break;
+    }
 }
 
 /* Try to combine the insns I0, I1 and I2 into I3.
@@ -2496,10 +2532,15 @@ update_cfg_for_uncondjump (rtx insn)
    resume scanning.
 
    Set NEW_DIRECT_JUMP_P to a nonzero value if try_combine creates a
-   new direct jump instruction.  */
+   new direct jump instruction.
+
+   LAST_COMBINED_INSN is either I3, or some insn after I3 that has
+   been I3 passed to an earlier try_combine within the same basic
+   block.  */
 
 static rtx
-try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
+try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
+            rtx last_combined_insn)
 {
   /* New patterns for I3 and I2, respectively.  */
   rtx newpat, newi2pat = 0;
@@ -2520,6 +2561,8 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
   rtx i3dest_killed = 0;
   /* SET_DEST and SET_SRC of I2, I1 and I0.  */
   rtx i2dest = 0, i2src = 0, i1dest = 0, i1src = 0, i0dest = 0, i0src = 0;
+  /* Copy of SET_SRC of I1, if needed.  */
+  rtx i1src_copy = 0;
   /* Set if I2DEST was reused as a scratch register.  */
   bool i2scratch = false;
   /* The PATTERNs of I0, I1, and I2, or a copy of them in certain cases.  */
@@ -2540,7 +2583,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
 
   int maxreg;
   rtx temp;
-  rtx link;
+  struct insn_link *link;
   rtx other_pat = 0;
   rtx new_other_notes;
   int i;
@@ -2619,7 +2662,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
 
   added_links_insn = 0;
 
-  /* First check for one important special-case that the code below will
+  /* First check for one important special case that the code below will
      not handle.  Namely, the case where I1 is zero, I2 is a PARALLEL
      and I3 is a SET whose SET_SRC is a SET_DEST in I2.  In that case,
      we may be able to replace that destination with the destination of I3.
@@ -2627,8 +2670,8 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
      remainder into a structure, in which case we want to do the computation
      directly into the structure to avoid register-register copies.
 
-     Note that this case handles both multiple sets in I2 and also
-     cases where I2 has a number of CLOBBER or PARALLELs.
+     Note that this case handles both multiple sets in I2 and also cases
+     where I2 has a number of CLOBBERs inside the PARALLEL.
 
      We make very conservative checks below and only try to handle the
      most common cases of this.  For example, we only handle the case
@@ -2672,8 +2715,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
 
       if (i == XVECLEN (p2, 0))
        for (i = 0; i < XVECLEN (p2, 0); i++)
-         if ((GET_CODE (XVECEXP (p2, 0, i)) == SET
-              || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER)
+         if (GET_CODE (XVECEXP (p2, 0, i)) == SET
              && SET_DEST (XVECEXP (p2, 0, i)) == SET_SRC (PATTERN (i3)))
            {
              combine_merges++;
@@ -2682,16 +2724,14 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
              subst_low_luid = DF_INSN_LUID (i2);
 
              added_sets_2 = added_sets_1 = added_sets_0 = 0;
-             i2src = SET_DEST (PATTERN (i3));
-             i2dest = SET_SRC (PATTERN (i3));
+             i2src = SET_SRC (XVECEXP (p2, 0, i));
+             i2dest = SET_DEST (XVECEXP (p2, 0, i));
              i2dest_killed = dead_or_set_p (i2, i2dest);
 
              /* Replace the dest in I2 with our dest and make the resulting
-                insn the new pattern for I3.  Then skip to where we
-                validate the pattern.  Everything was set up above.  */
-             SUBST (SET_DEST (XVECEXP (p2, 0, i)),
-                    SET_DEST (PATTERN (i3)));
-
+                insn the new pattern for I3.  Then skip to where we validate
+                the pattern.  Everything was set up above.  */
+             SUBST (SET_DEST (XVECEXP (p2, 0, i)), SET_DEST (PATTERN (i3)));
              newpat = p2;
              i3_subst_into_i2 = 1;
              goto validate_replacement;
@@ -2862,7 +2902,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
   i1_feeds_i2_n = i1 && insn_a_feeds_b (i1, i2);
   i0_feeds_i1_n = i0 && insn_a_feeds_b (i0, i1);
   i0_feeds_i2_n = (i0 && (!i0_feeds_i1_n ? insn_a_feeds_b (i0, i2)
-                         : (!dead_or_set_p (i1, i0dest)
+                         : (!reg_overlap_mentioned_p (i1dest, i0dest)
                             && reg_overlap_mentioned_p (i0dest, i2src))));
 
   /* Ensure that I3's pattern can be the destination of combines.  */
@@ -2902,15 +2942,18 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
     /* It's not the exception.  */
 #endif
 #ifdef AUTO_INC_DEC
-    for (link = REG_NOTES (i3); link; link = XEXP (link, 1))
-      if (REG_NOTE_KIND (link) == REG_INC
-         && (reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i2))
-             || (i1 != 0
-                 && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i1)))))
-       {
-         undo_all ();
-         return 0;
-       }
+    {
+      rtx link;
+      for (link = REG_NOTES (i3); link; link = XEXP (link, 1))
+       if (REG_NOTE_KIND (link) == REG_INC
+           && (reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i2))
+               || (i1 != 0
+                   && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i1)))))
+         {
+           undo_all ();
+           return 0;
+         }
+    }
 #endif
 
   /* See if the SETs in I1 or I2 need to be kept around in the merged
@@ -2938,6 +2981,18 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
   else
     added_sets_0 = 0;
 
+  /* We are about to copy insns for the case where they need to be kept
+     around.  Check that they can be copied in the merged instruction.  */
+
+  if (targetm.cannot_copy_insn_p
+      && ((added_sets_2 && targetm.cannot_copy_insn_p (i2))
+         || (i1 && added_sets_1 && targetm.cannot_copy_insn_p (i1))
+         || (i0 && added_sets_0 && targetm.cannot_copy_insn_p (i0))))
+    {
+      undo_all ();
+      return 0;
+    }
+
   /* If the set in I2 needs to be kept around, we must make a copy of
      PATTERN (I2), so that when we substitute I1SRC for I1DEST in
      PATTERN (I2), we are only substituting for the original I1DEST, not into
@@ -3047,7 +3102,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
       /* It is possible that the source of I2 or I1 may be performing
         an unneeded operation, such as a ZERO_EXTEND of something
         that is known to have the high part zero.  Handle that case
-        by letting subst look at the innermost one of them.
+        by letting subst look at the inner insns.
 
         Another way to do this would be to have a function that tries
         to simplify a single insn instead of merging two or more
@@ -3070,33 +3125,33 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
          if (i1)
            {
              subst_low_luid = DF_INSN_LUID (i1);
-             i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0);
-           }
-         else
-           {
-             subst_low_luid = DF_INSN_LUID (i2);
-             i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);
+             i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0, 0);
            }
+
+         subst_low_luid = DF_INSN_LUID (i2);
+         i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0, 0);
        }
 
       n_occurrences = 0;               /* `subst' counts here */
-
-      /* If I1 feeds into I2 and I1DEST is in I1SRC, we need to make a
-        unique copy of I2SRC each time we substitute it to avoid
-        self-referential rtl.  */
-
       subst_low_luid = DF_INSN_LUID (i2);
-      newpat = subst (PATTERN (i3), i2dest, i2src, 0,
-                     ((i1_feeds_i2_n && i1dest_in_i1src)
-                      || (i0_feeds_i2_n && i0dest_in_i0src)));
+
+      /* If I1 feeds into I2 and I1DEST is in I1SRC, we need to make a unique
+        copy of I2SRC each time we substitute it, in order to avoid creating
+        self-referential RTL when we will be substituting I1SRC for I1DEST
+        later.  Likewise if I0 feeds into I2, either directly or indirectly
+        through I1, and I0DEST is in I0SRC.  */
+      newpat = subst (PATTERN (i3), i2dest, i2src, 0, 0,
+                     (i1_feeds_i2_n && i1dest_in_i1src)
+                     || ((i0_feeds_i2_n || (i0_feeds_i1_n && i1_feeds_i2_n))
+                         && i0dest_in_i0src));
       substed_i2 = 1;
 
-      /* Record whether i2's body now appears within i3's body.  */
+      /* Record whether I2's body now appears within I3's body.  */
       i2_is_used = n_occurrences;
     }
 
-  /* If we already got a failure, don't try to do more.  Otherwise,
-     try to substitute in I1 if we have it.  */
+  /* If we already got a failure, don't try to do more.  Otherwise, try to
+     substitute I1 if we have it.  */
 
   if (i1 && GET_CODE (newpat) != CLOBBER)
     {
@@ -3107,10 +3162,10 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
           && i1_feeds_i2_n
           && dead_or_set_p (i2, i1dest)
           && !reg_overlap_mentioned_p (i1dest, newpat))
-         /* Before we can do this substitution, we must redo the test done
-            above (see detailed comments there) that ensures  that I1DEST
-            isn't mentioned in any SETs in NEWPAT that are field assignments.  */
-          || !combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX, NULL_RTX,
+          /* Before we can do this substitution, we must redo the test done
+             above (see detailed comments there) that ensures I1DEST isn't
+             mentioned in any SETs in NEWPAT that are field assignments.  */
+         || !combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX, NULL_RTX,
                                0, 0, 0))
        {
          undo_all ();
@@ -3119,28 +3174,42 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
 
       n_occurrences = 0;
       subst_low_luid = DF_INSN_LUID (i1);
-      newpat = subst (newpat, i1dest, i1src, 0,
+
+      /* If I0 feeds into I1 and I0DEST is in I0SRC, we need to make a unique
+        copy of I1SRC each time we substitute it, in order to avoid creating
+        self-referential RTL when we will be substituting I0SRC for I0DEST
+        later.  */
+      newpat = subst (newpat, i1dest, i1src, 0, 0,
                      i0_feeds_i1_n && i0dest_in_i0src);
       substed_i1 = 1;
+
+      /* Record whether I1's body now appears within I3's body.  */
       i1_is_used = n_occurrences;
     }
+
+  /* Likewise for I0 if we have it.  */
+
   if (i0 && GET_CODE (newpat) != CLOBBER)
     {
       if ((FIND_REG_INC_NOTE (i0, NULL_RTX) != 0
           && ((i0_feeds_i2_n && dead_or_set_p (i2, i0dest))
               || (i0_feeds_i1_n && dead_or_set_p (i1, i0dest)))
           && !reg_overlap_mentioned_p (i0dest, newpat))
-          || !combinable_i3pat (NULL_RTX, &newpat, i0dest, NULL_RTX, NULL_RTX,
+         || !combinable_i3pat (NULL_RTX, &newpat, i0dest, NULL_RTX, NULL_RTX,
                                0, 0, 0))
        {
          undo_all ();
          return 0;
        }
 
+      /* If the following substitution will modify I1SRC, make a copy of it
+        for the case where it is substituted for I1DEST in I2PAT later.  */
+      if (i0_feeds_i1_n && added_sets_2 && i1_feeds_i2_n)
+       i1src_copy = copy_rtx (i1src);
+
       n_occurrences = 0;
-      subst_low_luid = DF_INSN_LUID (i1);
-      newpat = subst (newpat, i0dest, i0src, 0,
-                     i0_feeds_i1_n && i0dest_in_i0src);
+      subst_low_luid = DF_INSN_LUID (i0);
+      newpat = subst (newpat, i0dest, i0src, 0, 0, 0);
       substed_i0 = 1;
     }
 
@@ -3202,17 +3271,18 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
        {
          rtx t = i1pat;
          if (i0_feeds_i1_n)
-           t = subst (t, i0dest, i0src, 0, 0);
+           t = subst (t, i0dest, i0src, 0, 0, 0);
 
          XVECEXP (newpat, 0, --total_sets) = t;
        }
       if (added_sets_2)
        {
          rtx t = i2pat;
-         if (i0_feeds_i2_n)
-           t = subst (t, i0dest, i0src, 0, 0);
          if (i1_feeds_i2_n)
-           t = subst (t, i1dest, i1src, 0, 0);
+           t = subst (t, i1dest, i1src_copy ? i1src_copy : i1src, 0, 0,
+                      i0_feeds_i1_n && i0dest_in_i0src);
+         if ((i0_feeds_i1_n && i1_feeds_i2_n) || i0_feeds_i2_n)
+           t = subst (t, i0dest, i0src, 0, 0, 0);
 
          XVECEXP (newpat, 0, --total_sets) = t;
        }
@@ -3387,7 +3457,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
            newpat = m_split;
        }
       else if (m_split && NEXT_INSN (NEXT_INSN (m_split)) == NULL_RTX
-              && (next_real_insn (i2) == i3
+              && (next_nonnote_nondebug_insn (i2) == i3
                   || ! use_crosses_set_p (PATTERN (m_split), DF_INSN_LUID (i2))))
        {
          rtx i2set, i3set;
@@ -3404,7 +3474,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
             is used between I2 and I3, we also can't use these insns.  */
 
          if (i2_code_number >= 0 && i2set && i3set
-             && (next_real_insn (i2) == i3
+             && (next_nonnote_nondebug_insn (i2) == i3
                  || ! reg_used_between_p (SET_DEST (i2set), i2, i3)))
            insn_code_number = recog_for_combine (&newi3pat, i3,
                                                  &new_i3_notes);
@@ -3452,7 +3522,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
              || GET_MODE (*split) == VOIDmode
              || can_change_dest_mode (i2dest, added_sets_2,
                                       GET_MODE (*split)))
-         && (next_real_insn (i2) == i3
+         && (next_nonnote_nondebug_insn (i2) == i3
              || ! use_crosses_set_p (*split, DF_INSN_LUID (i2)))
          /* We can't overwrite I2DEST if its value is still used by
             NEWPAT.  */
@@ -3493,7 +3563,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
          if (split_code == MULT
              && CONST_INT_P (XEXP (*split, 1))
              && INTVAL (XEXP (*split, 1)) > 0
-             && (i = exact_log2 (INTVAL (XEXP (*split, 1)))) >= 0)
+             && (i = exact_log2 (UINTVAL (XEXP (*split, 1)))) >= 0)
            {
              SUBST (*split, gen_rtx_ASHIFT (split_mode,
                                             XEXP (*split, 0), GEN_INT (i)));
@@ -3690,42 +3760,65 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
           && GET_CODE (XVECEXP (newpat, 0, 1)) == SET
           && 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)),
-                                  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))))
-#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
-          )
+                && contains_muldiv (SET_SRC (XVECEXP (newpat, 0, 1)))))
     {
       /* 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
+        but the one that references cc0 can't be the second, and
+        one which uses any regs/memory set in between i2 and i3 can't
         be first.  */
+      if (!use_crosses_set_p (SET_SRC (XVECEXP (newpat, 0, 1)),
+                             DF_INSN_LUID (i2))
 #ifdef HAVE_cc0
-      if (reg_referenced_p (cc0_rtx, XVECEXP (newpat, 0, 0)))
+         && !reg_referenced_p (cc0_rtx, XVECEXP (newpat, 0, 0))
+#endif
+        )
+       {
+         newi2pat = XVECEXP (newpat, 0, 1);
+         newpat = XVECEXP (newpat, 0, 0);
+       }
+      else if (!use_crosses_set_p (SET_SRC (XVECEXP (newpat, 0, 0)),
+                                  DF_INSN_LUID (i2))
+#ifdef HAVE_cc0
+              && !reg_referenced_p (cc0_rtx, XVECEXP (newpat, 0, 1))
+#endif
+             )
        {
          newi2pat = XVECEXP (newpat, 0, 0);
          newpat = XVECEXP (newpat, 0, 1);
        }
       else
-#endif
        {
-         newi2pat = XVECEXP (newpat, 0, 1);
-         newpat = XVECEXP (newpat, 0, 0);
+         undo_all ();
+         return 0;
        }
 
       i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
 
       if (i2_code_number >= 0)
-       insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+       {
+         /* recog_for_combine might have added CLOBBERs to newi2pat.
+            Make sure NEWPAT does not depend on the clobbered regs.  */
+         if (GET_CODE (newi2pat) == PARALLEL)
+           {
+             for (i = XVECLEN (newi2pat, 0) - 1; i >= 0; i--)
+               if (GET_CODE (XVECEXP (newi2pat, 0, i)) == CLOBBER)
+                 {
+                   rtx reg = XEXP (XVECEXP (newi2pat, 0, i), 0);
+                   if (reg_overlap_mentioned_p (reg, newpat))
+                     {
+                       undo_all ();
+                       return 0;
+                     }
+                 }
+           }
+
+         insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+       }
     }
 
   /* If it still isn't recognized, fail and change things back the way they
@@ -3797,7 +3890,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
                   i2src while its original mode is temporarily
                   restored, and then clear i2scratch so that we don't
                   do it again later.  */
-               propagate_for_debug (i2, i3, reg, i2src, false);
+               propagate_for_debug (i2, last_combined_insn, reg, i2src);
                i2scratch = false;
                /* Put back the new mode.  */
                adjust_reg_mode (reg, new_mode);
@@ -3810,13 +3903,16 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
                if (reg == i2dest)
                  {
                    first = i2;
-                   last = i3;
+                   last = last_combined_insn;
                  }
                else
                  {
                    first = i3;
                    last = undobuf.other_insn;
                    gcc_assert (last);
+                   if (DF_INSN_LUID (last)
+                       < DF_INSN_LUID (last_combined_insn))
+                     last = last_combined_insn;
                  }
 
                /* We're dealing with a reg that changed mode but not
@@ -3828,11 +3924,10 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
                   with this copy we have created; then, replace the
                   copy with the SUBREG of the original shared reg,
                   once again changed to the new mode.  */
-               propagate_for_debug (first, last, reg, tempreg, false);
+               propagate_for_debug (first, last, reg, tempreg);
                adjust_reg_mode (reg, new_mode);
                propagate_for_debug (first, last, tempreg,
-                                    lowpart_subreg (old_mode, reg, new_mode),
-                                    false);
+                                    lowpart_subreg (old_mode, reg, new_mode));
              }
          }
     }
@@ -3876,7 +3971,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
   if (swap_i2i3)
     {
       rtx insn;
-      rtx link;
+      struct insn_link *link;
       rtx ni2dest;
 
       /* I3 now uses what used to be its destination and which is now
@@ -3906,10 +4001,9 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
        {
          if (INSN_P (insn) && reg_referenced_p (ni2dest, PATTERN (insn)))
            {
-             for (link = LOG_LINKS (insn); link;
-                  link = XEXP (link, 1))
-               if (XEXP (link, 0) == i3)
-                 XEXP (link, 0) = i1;
+             FOR_EACH_LOG_LINK (link, insn)
+               if (link->insn == i3)
+                 link->insn = i1;
 
              break;
            }
@@ -3918,10 +4012,9 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
 
   {
     rtx i3notes, i2notes, i1notes = 0, i0notes = 0;
-    rtx i3links, i2links, i1links = 0, i0links = 0;
+    struct insn_link *i3links, *i2links, *i1links = 0, *i0links = 0;
     rtx midnotes = 0;
     int from_luid;
-    unsigned int regno;
     /* Compute which registers we expect to eliminate.  newi2pat may be setting
        either i3dest or i2dest, so we must check it.  Also, i1dest may be the
        same as i3dest, in which case newi2pat may be setting i1dest.  */
@@ -4022,9 +4115,9 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
                          || BB_HEAD (this_basic_block) != temp);
                 temp = NEXT_INSN (temp))
              if (temp != i3 && INSN_P (temp))
-               for (link = LOG_LINKS (temp); link; link = XEXP (link, 1))
-                 if (XEXP (link, 0) == i2)
-                   XEXP (link, 0) = i3;
+               FOR_EACH_LOG_LINK (link, temp)
+                 if (link->insn == i2)
+                   link->insn = i3;
 
        if (i3notes)
          {
@@ -4038,40 +4131,40 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
        i2notes = 0;
       }
 
-    LOG_LINKS (i3) = 0;
+    LOG_LINKS (i3) = NULL;
     REG_NOTES (i3) = 0;
-    LOG_LINKS (i2) = 0;
+    LOG_LINKS (i2) = NULL;
     REG_NOTES (i2) = 0;
 
     if (newi2pat)
       {
        if (MAY_HAVE_DEBUG_INSNS && i2scratch)
-         propagate_for_debug (i2, i3, i2dest, i2src, false);
+         propagate_for_debug (i2, last_combined_insn, i2dest, i2src);
        INSN_CODE (i2) = i2_code_number;
        PATTERN (i2) = newi2pat;
       }
     else
       {
        if (MAY_HAVE_DEBUG_INSNS && i2src)
-         propagate_for_debug (i2, i3, i2dest, i2src, i3_subst_into_i2);
+         propagate_for_debug (i2, last_combined_insn, i2dest, i2src);
        SET_INSN_DELETED (i2);
       }
 
     if (i1)
       {
-       LOG_LINKS (i1) = 0;
+       LOG_LINKS (i1) = NULL;
        REG_NOTES (i1) = 0;
        if (MAY_HAVE_DEBUG_INSNS)
-         propagate_for_debug (i1, i3, i1dest, i1src, false);
+         propagate_for_debug (i1, last_combined_insn, i1dest, i1src);
        SET_INSN_DELETED (i1);
       }
 
     if (i0)
       {
-       LOG_LINKS (i0) = 0;
+       LOG_LINKS (i0) = NULL;
        REG_NOTES (i0) = 0;
        if (MAY_HAVE_DEBUG_INSNS)
-         propagate_for_debug (i0, i3, i0dest, i0src, false);
+         propagate_for_debug (i0, last_combined_insn, i0dest, i0src);
        SET_INSN_DELETED (i0);
       }
 
@@ -4179,7 +4272,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
 
     if (REG_P (i2dest))
       {
-       rtx link;
+       struct insn_link *link;
        rtx i2_insn = 0, i2_val = 0, set;
 
        /* The insn that used to set this register doesn't exist, and
@@ -4189,11 +4282,10 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
           this and I2 set the register to a value that depended on its old
           contents, we will get confused.  If this insn is used, thing
           will be set correctly in combine_instructions.  */
-
-       for (link = LOG_LINKS (i3); link; link = XEXP (link, 1))
-         if ((set = single_set (XEXP (link, 0))) != 0
+       FOR_EACH_LOG_LINK (link, i3)
+         if ((set = single_set (link->insn)) != 0
              && rtx_equal_p (i2dest, SET_DEST (set)))
-           i2_insn = XEXP (link, 0), i2_val = SET_SRC (set);
+           i2_insn = link->insn, i2_val = SET_SRC (set);
 
        record_value_for_reg (i2dest, i2_insn, i2_val);
 
@@ -4202,44 +4294,39 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
        if (! added_sets_2
            && (newi2pat == 0 || ! reg_mentioned_p (i2dest, newi2pat))
            && ! i2dest_in_i2src)
-         {
-           regno = REGNO (i2dest);
-           INC_REG_N_SETS (regno, -1);
-         }
+         INC_REG_N_SETS (REGNO (i2dest), -1);
       }
 
     if (i1 && REG_P (i1dest))
       {
-       rtx link;
+       struct insn_link *link;
        rtx i1_insn = 0, i1_val = 0, set;
 
-       for (link = LOG_LINKS (i3); link; link = XEXP (link, 1))
-         if ((set = single_set (XEXP (link, 0))) != 0
+       FOR_EACH_LOG_LINK (link, i3)
+         if ((set = single_set (link->insn)) != 0
              && rtx_equal_p (i1dest, SET_DEST (set)))
-           i1_insn = XEXP (link, 0), i1_val = SET_SRC (set);
+           i1_insn = link->insn, i1_val = SET_SRC (set);
 
        record_value_for_reg (i1dest, i1_insn, i1_val);
 
-       regno = REGNO (i1dest);
        if (! added_sets_1 && ! i1dest_in_i1src)
-         INC_REG_N_SETS (regno, -1);
+         INC_REG_N_SETS (REGNO (i1dest), -1);
       }
 
     if (i0 && REG_P (i0dest))
       {
-       rtx link;
+       struct insn_link *link;
        rtx i0_insn = 0, i0_val = 0, set;
 
-       for (link = LOG_LINKS (i3); link; link = XEXP (link, 1))
-         if ((set = single_set (XEXP (link, 0))) != 0
+       FOR_EACH_LOG_LINK (link, i3)
+         if ((set = single_set (link->insn)) != 0
              && rtx_equal_p (i0dest, SET_DEST (set)))
-           i0_insn = XEXP (link, 0), i0_val = SET_SRC (set);
+           i0_insn = link->insn, i0_val = SET_SRC (set);
 
        record_value_for_reg (i0dest, i0_insn, i0_val);
 
-       regno = REGNO (i0dest);
        if (! added_sets_0 && ! i0dest_in_i0src)
-         INC_REG_N_SETS (regno, -1);
+         INC_REG_N_SETS (REGNO (i0dest), -1);
       }
 
     /* Update reg_stat[].nonzero_bits et al for any changes that may have
@@ -4321,7 +4408,8 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
 
   /* A noop might also need cleaning up of CFG, if it comes from the
      simplification of a jump.  */
-  if (GET_CODE (newpat) == SET
+  if (JUMP_P (i3)
+      && GET_CODE (newpat) == SET
       && SET_SRC (newpat) == pc_rtx
       && SET_DEST (newpat) == pc_rtx)
     {
@@ -4329,6 +4417,16 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
       update_cfg_for_uncondjump (i3);
     }
 
+  if (undobuf.other_insn != NULL_RTX
+      && JUMP_P (undobuf.other_insn)
+      && GET_CODE (PATTERN (undobuf.other_insn)) == SET
+      && SET_SRC (PATTERN (undobuf.other_insn)) == pc_rtx
+      && SET_DEST (PATTERN (undobuf.other_insn)) == pc_rtx)
+    {
+      *new_direct_jump_p = 1;
+      update_cfg_for_uncondjump (undobuf.other_insn);
+    }
+
   combine_successes++;
   undo_commit ();
 
@@ -4561,7 +4659,8 @@ find_split_point (rtx *loc, rtx insn, bool set_src)
          unsigned HOST_WIDE_INT src = INTVAL (SET_SRC (x));
          rtx dest = XEXP (SET_DEST (x), 0);
          enum machine_mode mode = GET_MODE (dest);
-         unsigned HOST_WIDE_INT mask = ((HOST_WIDE_INT) 1 << len) - 1;
+         unsigned HOST_WIDE_INT mask
+           = ((unsigned HOST_WIDE_INT) 1 << len) - 1;
          rtx or_mask;
 
          if (BITS_BIG_ENDIAN)
@@ -4606,7 +4705,7 @@ find_split_point (rtx *loc, rtx insn, bool set_src)
 
          if (CONST_INT_P (XEXP (SET_SRC (x), 1))
              && REG_P (XEXP (SET_SRC (x), 0))
-             && (pos = exact_log2 (INTVAL (XEXP (SET_SRC (x), 1)))) >= 7
+             && (pos = exact_log2 (UINTVAL (XEXP (SET_SRC (x), 1)))) >= 7
              && REG_P (SET_DEST (x))
              && (split = find_single_use (SET_DEST (x), insn, (rtx*) 0)) != 0
              && (GET_CODE (*split) == EQ || GET_CODE (*split) == NE)
@@ -4698,7 +4797,8 @@ find_split_point (rtx *loc, rtx insn, bool set_src)
                                  gen_rtx_LSHIFTRT
                                  (mode, gen_lowpart (mode, inner),
                                   GEN_INT (pos)),
-                                 GEN_INT (((HOST_WIDE_INT) 1 << len) - 1)));
+                                 GEN_INT (((unsigned HOST_WIDE_INT) 1 << len)
+                                          - 1)));
 
              split = find_split_point (&SET_SRC (x), insn, true);
              if (split && split != &SET_SRC (x))
@@ -4771,6 +4871,23 @@ find_split_point (rtx *loc, rtx insn, bool set_src)
 
     case PLUS:
     case MINUS:
+      /* Canonicalization can produce (minus A (mult B C)), where C is a
+        constant.  It may be better to try splitting (plus (mult B -C) A)
+        instead if this isn't a multiply by a power of two.  */
+      if (set_src && code == MINUS && GET_CODE (XEXP (x, 1)) == MULT
+         && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
+         && exact_log2 (INTVAL (XEXP (XEXP (x, 1), 1))) < 0)
+       {
+         enum machine_mode mode = GET_MODE (x);
+         unsigned HOST_WIDE_INT this_int = INTVAL (XEXP (XEXP (x, 1), 1));
+         HOST_WIDE_INT other_int = trunc_int_for_mode (-this_int, mode);
+         SUBST (*loc, gen_rtx_PLUS (mode, gen_rtx_MULT (mode,
+                                                        XEXP (XEXP (x, 1), 0),
+                                                        GEN_INT (other_int)),
+                                    XEXP (x, 0)));
+         return find_split_point (loc, insn, set_src);
+       }
+
       /* Split at a multiply-accumulate instruction.  However if this is
          the SET_SRC, we likely do not have such an instruction and it's
          worthless to try this split.  */
@@ -4831,11 +4948,13 @@ find_split_point (rtx *loc, rtx insn, bool set_src)
 
    IN_DEST is nonzero if we are processing the SET_DEST of a SET.
 
+   IN_COND is nonzero if we are at the top level of a condition.
+
    UNIQUE_COPY is nonzero if each substitution must be unique.  We do this
    by copying if `n_occurrences' is nonzero.  */
 
 static rtx
-subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
+subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
 {
   enum rtx_code code = GET_CODE (x);
   enum machine_mode op0_mode = VOIDmode;
@@ -4896,7 +5015,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
       && GET_CODE (XVECEXP (x, 0, 0)) == SET
       && GET_CODE (SET_SRC (XVECEXP (x, 0, 0))) == ASM_OPERANDS)
     {
-      new_rtx = subst (XVECEXP (x, 0, 0), from, to, 0, unique_copy);
+      new_rtx = subst (XVECEXP (x, 0, 0), from, to, 0, 0, unique_copy);
 
       /* If this substitution failed, this whole thing fails.  */
       if (GET_CODE (new_rtx) == CLOBBER
@@ -4913,7 +5032,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
              && GET_CODE (dest) != CC0
              && GET_CODE (dest) != PC)
            {
-             new_rtx = subst (dest, from, to, 0, unique_copy);
+             new_rtx = subst (dest, from, to, 0, 0, unique_copy);
 
              /* If this substitution failed, this whole thing fails.  */
              if (GET_CODE (new_rtx) == CLOBBER
@@ -4959,8 +5078,8 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
                    }
                  else
                    {
-                     new_rtx = subst (XVECEXP (x, i, j), from, to, 0,
-                                  unique_copy);
+                     new_rtx = subst (XVECEXP (x, i, j), from, to, 0, 0,
+                                      unique_copy);
 
                      /* If this substitution failed, this whole thing
                         fails.  */
@@ -5037,7 +5156,9 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
                                && (code == SUBREG || code == STRICT_LOW_PART
                                    || code == ZERO_EXTRACT))
                               || code == SET)
-                             && i == 0), unique_copy);
+                             && i == 0),
+                                code == IF_THEN_ELSE && i == 0,
+                                unique_copy);
 
              /* If we found that we will have to reject this combination,
                 indicate that by returning the CLOBBER ourselves, rather than
@@ -5094,7 +5215,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
       /* If X is sufficiently simple, don't bother trying to do anything
         with it.  */
       if (code != CONST_INT && code != REG && code != CLOBBER)
-       x = combine_simplify_rtx (x, op0_mode, in_dest);
+       x = combine_simplify_rtx (x, op0_mode, in_dest, in_cond);
 
       if (GET_CODE (x) == code)
        break;
@@ -5114,10 +5235,12 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
    expression.
 
    OP0_MODE is the original mode of XEXP (x, 0).  IN_DEST is nonzero
-   if we are inside a SET_DEST.  */
+   if we are inside a SET_DEST.  IN_COND is nonzero if we are at the top level
+   of a condition.  */
 
 static rtx
-combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
+combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest,
+                     int in_cond)
 {
   enum rtx_code code = GET_CODE (x);
   enum machine_mode mode = GET_MODE (x);
@@ -5172,8 +5295,8 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
             false arms to store-flag values.  Be careful to use copy_rtx
             here since true_rtx or false_rtx might share RTL with x as a
             result of the if_then_else_cond call above.  */
-         true_rtx = subst (copy_rtx (true_rtx), pc_rtx, pc_rtx, 0, 0);
-         false_rtx = subst (copy_rtx (false_rtx), pc_rtx, pc_rtx, 0, 0);
+         true_rtx = subst (copy_rtx (true_rtx), pc_rtx, pc_rtx, 0, 0, 0);
+         false_rtx = subst (copy_rtx (false_rtx), pc_rtx, pc_rtx, 0, 0, 0);
 
          /* If true_rtx and false_rtx are not general_operands, an if_then_else
             is unlikely to be simpler.  */
@@ -5439,7 +5562,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
         whose value is a comparison can be replaced with a subreg if
         STORE_FLAG_VALUE permits.  */
       if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-         && ((HOST_WIDE_INT) STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0
+         && (STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0
          && (temp = get_last_value (XEXP (x, 0)))
          && COMPARISON_P (temp))
        return gen_lowpart (mode, XEXP (x, 0));
@@ -5474,13 +5597,13 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
          && CONST_INT_P (XEXP (x, 1))
          && CONST_INT_P (XEXP (XEXP (x, 0), 1))
          && INTVAL (XEXP (x, 1)) == -INTVAL (XEXP (XEXP (x, 0), 1))
-         && ((i = exact_log2 (INTVAL (XEXP (XEXP (x, 0), 1)))) >= 0
-             || (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0)
+         && ((i = exact_log2 (UINTVAL (XEXP (XEXP (x, 0), 1)))) >= 0
+             || (i = exact_log2 (UINTVAL (XEXP (x, 1)))) >= 0)
          && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
          && ((GET_CODE (XEXP (XEXP (x, 0), 0)) == AND
               && CONST_INT_P (XEXP (XEXP (XEXP (x, 0), 0), 1))
-              && (INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))
-                  == ((HOST_WIDE_INT) 1 << (i + 1)) - 1))
+              && (UINTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))
+                  == ((unsigned HOST_WIDE_INT) 1 << (i + 1)) - 1))
              || (GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND
                  && (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)))
                      == (unsigned int) i + 1))))
@@ -5517,7 +5640,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
        {
          /* Try to simplify the expression further.  */
          rtx tor = simplify_gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
-         temp = combine_simplify_rtx (tor, mode, in_dest);
+         temp = combine_simplify_rtx (tor, mode, in_dest, 0);
 
          /* If we could, great.  If not, do not go ahead with the IOR
             replacement, since PLUS appears in many special purpose
@@ -5532,7 +5655,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
         (and <foo> (const_int pow2-1))  */
       if (GET_CODE (XEXP (x, 1)) == AND
          && CONST_INT_P (XEXP (XEXP (x, 1), 1))
-         && exact_log2 (-INTVAL (XEXP (XEXP (x, 1), 1))) >= 0
+         && exact_log2 (-UINTVAL (XEXP (XEXP (x, 1), 1))) >= 0
          && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
        return simplify_and_const_int (NULL_RTX, mode, XEXP (x, 0),
                                       -INTVAL (XEXP (XEXP (x, 1), 1)) - 1);
@@ -5566,7 +5689,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
       /* If this is a divide by a power of two, treat it as a shift if
         its first operand is a shift.  */
       if (CONST_INT_P (XEXP (x, 1))
-         && (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0
+         && (i = exact_log2 (UINTVAL (XEXP (x, 1)))) >= 0
          && (GET_CODE (XEXP (x, 0)) == ASHIFT
              || GET_CODE (XEXP (x, 0)) == LSHIFTRT
              || GET_CODE (XEXP (x, 0)) == ASHIFTRT
@@ -5608,9 +5731,17 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
             Remove any ZERO_EXTRACT we made when thinking this was a
             comparison.  It may now be simpler to use, e.g., an AND.  If a
             ZERO_EXTRACT is indeed appropriate, it will be placed back by
-            the call to make_compound_operation in the SET case.  */
+            the call to make_compound_operation in the SET case.
+
+            Don't apply these optimizations if the caller would
+            prefer a comparison rather than a value.
+            E.g., for the condition in an IF_THEN_ELSE most targets need
+            an explicit comparison.  */
+
+         if (in_cond)
+           ;
 
-         if (STORE_FLAG_VALUE == 1
+         else if (STORE_FLAG_VALUE == 1
              && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
              && op1 == const0_rtx
              && mode == GET_MODE (op0)
@@ -5656,7 +5787,10 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
 
          /* If STORE_FLAG_VALUE is -1, we have cases similar to
             those above.  */
-         if (STORE_FLAG_VALUE == -1
+         if (in_cond)
+           ;
+
+         else if (STORE_FLAG_VALUE == -1
              && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
              && op1 == const0_rtx
              && (num_sign_bit_copies (op0, mode)
@@ -5766,7 +5900,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
       else if (SHIFT_COUNT_TRUNCATED && !REG_P (XEXP (x, 1)))
        SUBST (XEXP (x, 1),
               force_to_mode (XEXP (x, 1), GET_MODE (XEXP (x, 1)),
-                             ((HOST_WIDE_INT) 1
+                             ((unsigned HOST_WIDE_INT) 1
                               << exact_log2 (GET_MODE_BITSIZE (GET_MODE (x))))
                              - 1,
                              0));
@@ -5854,11 +5988,11 @@ simplify_if_then_else (rtx x)
       if (reg_mentioned_p (from, true_rtx))
        true_rtx = subst (known_cond (copy_rtx (true_rtx), true_code,
                                      from, true_val),
-                     pc_rtx, pc_rtx, 0, 0);
+                         pc_rtx, pc_rtx, 0, 0, 0);
       if (reg_mentioned_p (from, false_rtx))
        false_rtx = subst (known_cond (copy_rtx (false_rtx), false_code,
                                   from, false_val),
-                      pc_rtx, pc_rtx, 0, 0);
+                          pc_rtx, pc_rtx, 0, 0, 0);
 
       SUBST (XEXP (x, 1), swapped ? false_rtx : true_rtx);
       SUBST (XEXP (x, 2), swapped ? true_rtx : false_rtx);
@@ -6075,11 +6209,11 @@ simplify_if_then_else (rtx x)
        {
          temp = subst (simplify_gen_relational (true_code, m, VOIDmode,
                                                 cond_op0, cond_op1),
-                       pc_rtx, pc_rtx, 0, 0);
+                       pc_rtx, pc_rtx, 0, 0, 0);
          temp = simplify_gen_binary (MULT, m, temp,
                                      simplify_gen_binary (MULT, m, c1,
                                                           const_true_rtx));
-         temp = subst (temp, pc_rtx, pc_rtx, 0, 0);
+         temp = subst (temp, pc_rtx, pc_rtx, 0, 0, 0);
          temp = simplify_gen_binary (op, m, gen_lowpart (m, z), temp);
 
          if (extend_op != UNKNOWN)
@@ -6097,10 +6231,10 @@ simplify_if_then_else (rtx x)
   if (true_code == NE && XEXP (cond, 1) == const0_rtx
       && false_rtx == const0_rtx && CONST_INT_P (true_rtx)
       && ((1 == nonzero_bits (XEXP (cond, 0), mode)
-          && (i = exact_log2 (INTVAL (true_rtx))) >= 0)
+          && (i = exact_log2 (UINTVAL (true_rtx))) >= 0)
          || ((num_sign_bit_copies (XEXP (cond, 0), mode)
               == GET_MODE_BITSIZE (mode))
-             && (i = exact_log2 (-INTVAL (true_rtx))) >= 0)))
+             && (i = exact_log2 (-UINTVAL (true_rtx))) >= 0)))
     return
       simplify_shift_const (NULL_RTX, ASHIFT, mode,
                            gen_lowpart (mode, XEXP (cond, 0)), i);
@@ -6109,9 +6243,9 @@ simplify_if_then_else (rtx x)
   if (true_code == NE && XEXP (cond, 1) == const0_rtx
       && false_rtx == const0_rtx && CONST_INT_P (true_rtx)
       && GET_MODE (XEXP (cond, 0)) == mode
-      && (INTVAL (true_rtx) & GET_MODE_MASK (mode))
+      && (UINTVAL (true_rtx) & GET_MODE_MASK (mode))
          == nonzero_bits (XEXP (cond, 0), mode)
-      && (i = exact_log2 (INTVAL (true_rtx) & GET_MODE_MASK (mode))) >= 0)
+      && (i = exact_log2 (UINTVAL (true_rtx) & GET_MODE_MASK (mode))) >= 0)
     return XEXP (cond, 0);
 
   return x;
@@ -6140,7 +6274,7 @@ simplify_set (rtx x)
   if (GET_MODE_CLASS (mode) == MODE_INT
       && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
     {
-      src = force_to_mode (src, mode, ~(HOST_WIDE_INT) 0, 0);
+      src = force_to_mode (src, mode, ~(unsigned HOST_WIDE_INT) 0, 0);
       SUBST (SET_SRC (x), src);
     }
 
@@ -6159,10 +6293,18 @@ simplify_set (rtx x)
       enum rtx_code new_code;
       rtx op0, op1, tmp;
       int other_changed = 0;
+      rtx inner_compare = NULL_RTX;
       enum machine_mode compare_mode = GET_MODE (dest);
 
       if (GET_CODE (src) == COMPARE)
-       op0 = XEXP (src, 0), op1 = XEXP (src, 1);
+       {
+         op0 = XEXP (src, 0), op1 = XEXP (src, 1);
+         if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
+           {
+             inner_compare = op0;
+             op0 = XEXP (inner_compare, 0), op1 = XEXP (inner_compare, 1);
+           }
+       }
       else
        op0 = src, op1 = CONST0_RTX (GET_MODE (src));
 
@@ -6204,6 +6346,12 @@ simplify_set (rtx x)
         need to use a different CC mode here.  */
       if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
        compare_mode = GET_MODE (op0);
+      else if (inner_compare
+              && GET_MODE_CLASS (GET_MODE (inner_compare)) == MODE_CC
+              && new_code == old_code
+              && op0 == XEXP (inner_compare, 0)
+              && op1 == XEXP (inner_compare, 1))
+       compare_mode = GET_MODE (inner_compare);
       else
        compare_mode = SELECT_CC_MODE (new_code, op0, op1);
 
@@ -6685,8 +6833,7 @@ expand_compound_operation (rtx x)
          && COMPARISON_P (XEXP (XEXP (x, 0), 0))
          && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
              <= HOST_BITS_PER_WIDE_INT)
-         && ((HOST_WIDE_INT) STORE_FLAG_VALUE
-             & ~GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
+         && (STORE_FLAG_VALUE & ~GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
        return XEXP (XEXP (x, 0), 0);
 
       /* Likewise for (zero_extend:DI (subreg:SI foo:DI 0)).  */
@@ -6696,8 +6843,7 @@ expand_compound_operation (rtx x)
          && COMPARISON_P (SUBREG_REG (XEXP (x, 0)))
          && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
              <= HOST_BITS_PER_WIDE_INT)
-         && ((HOST_WIDE_INT) STORE_FLAG_VALUE
-             & ~GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
+         && (STORE_FLAG_VALUE & ~GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
        return SUBREG_REG (XEXP (x, 0));
 
     }
@@ -6714,11 +6860,11 @@ expand_compound_operation (rtx x)
      count.  This can happen in a case like (x >> 31) & 255 on machines
      that can't shift by a constant.  On those machines, we would first
      combine the shift with the AND to produce a variable-position
-     extraction.  Then the constant of 31 would be substituted in to produce
-     a such a position.  */
+     extraction.  Then the constant of 31 would be substituted in
+     to produce such a position.  */
 
   modewidth = GET_MODE_BITSIZE (GET_MODE (x));
-  if (modewidth + len >= pos)
+  if (modewidth >= pos + len)
     {
       enum machine_mode mode = GET_MODE (x);
       tem = gen_lowpart (mode, XEXP (x, 0));
@@ -6734,7 +6880,7 @@ expand_compound_operation (rtx x)
                                  simplify_shift_const (NULL_RTX, LSHIFTRT,
                                                        GET_MODE (x),
                                                        XEXP (x, 0), pos),
-                                 ((HOST_WIDE_INT) 1 << len) - 1);
+                                 ((unsigned HOST_WIDE_INT) 1 << len) - 1);
   else
     /* Any other cases we can't handle.  */
     return x;
@@ -6855,7 +7001,7 @@ expand_field_assignment (const_rtx x)
       /* Now compute the equivalent expression.  Make a copy of INNER
         for the SET_DEST in case it is a MEM into which we will substitute;
         we don't want shared RTL in that case.  */
-      mask = GEN_INT (((HOST_WIDE_INT) 1 << len) - 1);
+      mask = GEN_INT (((unsigned HOST_WIDE_INT) 1 << len) - 1);
       cleared = simplify_gen_binary (AND, compute_mode,
                                     simplify_gen_unary (NOT, compute_mode,
                                       simplify_gen_binary (ASHIFT,
@@ -6931,7 +7077,7 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
   else if (GET_CODE (inner) == ASHIFT
           && CONST_INT_P (XEXP (inner, 1))
           && pos_rtx == 0 && pos == 0
-          && len > (unsigned HOST_WIDE_INT) INTVAL (XEXP (inner, 1)))
+          && len > UINTVAL (XEXP (inner, 1)))
     {
       /* We're extracting the least significant bits of an rtx
         (ashift X (const_int C)), where LEN > C.  Extract the
@@ -7337,7 +7483,8 @@ extract_left_shift (rtx x, int count)
       /* If we can safely shift this constant and we find the inner shift,
         make a new operation.  */
       if (CONST_INT_P (XEXP (x, 1))
-         && (INTVAL (XEXP (x, 1)) & ((((HOST_WIDE_INT) 1 << count)) - 1)) == 0
+         && (UINTVAL (XEXP (x, 1))
+             & ((((unsigned HOST_WIDE_INT) 1 << count)) - 1)) == 0
          && (tem = extract_left_shift (XEXP (x, 0), count)) != 0)
        return simplify_gen_binary (code, mode, tem,
                                    GEN_INT (INTVAL (XEXP (x, 1)) >> count));
@@ -7403,7 +7550,8 @@ make_compound_operation (rtx x, enum rtx_code in_code)
         an address.  */
       if (in_code == MEM && CONST_INT_P (XEXP (x, 1))
          && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT
-         && INTVAL (XEXP (x, 1)) >= 0)
+         && INTVAL (XEXP (x, 1)) >= 0
+         && SCALAR_INT_MODE_P (mode))
        {
          HOST_WIDE_INT count = INTVAL (XEXP (x, 1));
          HOST_WIDE_INT multval = (HOST_WIDE_INT) 1 << count;
@@ -7487,7 +7635,7 @@ make_compound_operation (rtx x, enum rtx_code in_code)
       /* If the constant is a power of two minus one and the first operand
         is a logical right shift, make an extraction.  */
       if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
-         && (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
+         && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0)
        {
          new_rtx = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
          new_rtx = make_extraction (mode, new_rtx, 0, XEXP (XEXP (x, 0), 1), i, 1,
@@ -7498,7 +7646,7 @@ make_compound_operation (rtx x, enum rtx_code in_code)
       else if (GET_CODE (XEXP (x, 0)) == SUBREG
               && subreg_lowpart_p (XEXP (x, 0))
               && GET_CODE (SUBREG_REG (XEXP (x, 0))) == LSHIFTRT
-              && (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
+              && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0)
        {
          new_rtx = make_compound_operation (XEXP (SUBREG_REG (XEXP (x, 0)), 0),
                                         next_code);
@@ -7511,7 +7659,7 @@ make_compound_operation (rtx x, enum rtx_code in_code)
                || GET_CODE (XEXP (x, 0)) == IOR)
               && GET_CODE (XEXP (XEXP (x, 0), 0)) == LSHIFTRT
               && GET_CODE (XEXP (XEXP (x, 0), 1)) == LSHIFTRT
-              && (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
+              && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0)
        {
          /* Apply the distributive law, and then try to make extractions.  */
          new_rtx = gen_rtx_fmt_ee (GET_CODE (XEXP (x, 0)), mode,
@@ -7527,7 +7675,7 @@ make_compound_operation (rtx x, enum rtx_code in_code)
 
       else if (GET_CODE (XEXP (x, 0)) == ROTATE
               && CONST_INT_P (XEXP (XEXP (x, 0), 1))
-              && (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0
+              && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0
               && i <= INTVAL (XEXP (XEXP (x, 0), 1)))
        {
          new_rtx = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
@@ -7563,7 +7711,7 @@ make_compound_operation (rtx x, enum rtx_code in_code)
         representable by an extraction even if no shift is present.
         If it doesn't end up being a ZERO_EXTEND, we will ignore it unless
         we are in a COMPARE.  */
-      else if ((i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
+      else if ((i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0)
        new_rtx = make_extraction (mode,
                               make_compound_operation (XEXP (x, 0),
                                                        next_code),
@@ -7572,7 +7720,7 @@ make_compound_operation (rtx x, enum rtx_code in_code)
       /* If we are in a comparison and this is an AND with a power of two,
         convert this into the appropriate bit extract.  */
       else if (in_code == COMPARE
-              && (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0)
+              && (i = exact_log2 (UINTVAL (XEXP (x, 1)))) >= 0)
        new_rtx = make_extraction (mode,
                               make_compound_operation (XEXP (x, 0),
                                                        next_code),
@@ -7653,7 +7801,8 @@ make_compound_operation (rtx x, enum rtx_code in_code)
            && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (inner))
            && subreg_lowpart_p (x))
          {
-           rtx newer = force_to_mode (tem, mode, ~(HOST_WIDE_INT) 0, 0);
+           rtx newer
+             = force_to_mode (tem, mode, ~(unsigned HOST_WIDE_INT) 0, 0);
 
            /* If we have something other than a SUBREG, we might have
               done an expansion, so rerun ourselves.  */
@@ -8015,16 +8164,17 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
              && GET_MODE_MASK (GET_MODE (x)) != mask
              && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
            {
-             HOST_WIDE_INT cval = (INTVAL (XEXP (x, 1))
-                                   | (GET_MODE_MASK (GET_MODE (x)) & ~mask));
+             unsigned HOST_WIDE_INT cval
+               = UINTVAL (XEXP (x, 1))
+                 | (GET_MODE_MASK (GET_MODE (x)) & ~mask);
              int width = GET_MODE_BITSIZE (GET_MODE (x));
              rtx y;
 
              /* If MODE is narrower than HOST_WIDE_INT and CVAL is a negative
                 number, sign extend it.  */
              if (width > 0 && width < HOST_BITS_PER_WIDE_INT
-                 && (cval & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
-               cval |= (HOST_WIDE_INT) -1 << width;
+                 && (cval & ((unsigned HOST_WIDE_INT) 1 << (width - 1))) != 0)
+               cval |= (unsigned HOST_WIDE_INT) -1 << width;
 
              y = simplify_gen_binary (AND, GET_MODE (x),
                                       XEXP (x, 0), GEN_INT (cval));
@@ -8052,8 +8202,8 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
           number, sign extend it.  */
 
        if (width < HOST_BITS_PER_WIDE_INT
-           && (smask & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
-         smask |= (HOST_WIDE_INT) -1 << width;
+           && (smask & ((unsigned HOST_WIDE_INT) 1 << (width - 1))) != 0)
+         smask |= (unsigned HOST_WIDE_INT) (-1) << width;
 
        if (CONST_INT_P (XEXP (x, 1))
            && exact_log2 (- smask) >= 0
@@ -8089,8 +8239,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       /* Similarly, if C contains every bit in the fuller_mask, then we may
         replace with (not Y).  */
       if (CONST_INT_P (XEXP (x, 0))
-         && ((INTVAL (XEXP (x, 0)) | (HOST_WIDE_INT) fuller_mask)
-             == INTVAL (XEXP (x, 0))))
+         && ((UINTVAL (XEXP (x, 0)) | fuller_mask) == UINTVAL (XEXP (x, 0))))
        {
          x = simplify_gen_unary (NOT, GET_MODE (x),
                                  XEXP (x, 1), GET_MODE (x));
@@ -8115,7 +8264,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
          && ((INTVAL (XEXP (XEXP (x, 0), 1))
               + floor_log2 (INTVAL (XEXP (x, 1))))
              < GET_MODE_BITSIZE (GET_MODE (x)))
-         && (INTVAL (XEXP (x, 1))
+         && (UINTVAL (XEXP (x, 1))
              & ~nonzero_bits (XEXP (x, 0), GET_MODE (x))) == 0)
        {
          temp = GEN_INT ((INTVAL (XEXP (x, 1)) & mask)
@@ -8262,7 +8411,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
 
          if (GET_MODE_BITSIZE (GET_MODE (x)) > HOST_BITS_PER_WIDE_INT)
            {
-             nonzero = ~(HOST_WIDE_INT) 0;
+             nonzero = ~(unsigned HOST_WIDE_INT) 0;
 
              /* GET_MODE_BITSIZE (GET_MODE (x)) - INTVAL (XEXP (x, 1))
                 is the number of bits a full-width mask would have set.
@@ -8393,7 +8542,8 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       /* (and (ne FOO 0) CONST) can be (and FOO CONST) if CONST is included
         in STORE_FLAG_VALUE and FOO has a single bit that might be nonzero,
         which is equal to STORE_FLAG_VALUE.  */
-      if ((mask & ~STORE_FLAG_VALUE) == 0 && XEXP (x, 1) == const0_rtx
+      if ((mask & ~STORE_FLAG_VALUE) == 0
+         && XEXP (x, 1) == const0_rtx
          && GET_MODE (XEXP (x, 0)) == mode
          && exact_log2 (nonzero_bits (XEXP (x, 0), mode)) >= 0
          && (nonzero_bits (XEXP (x, 0), mode)
@@ -8982,8 +9132,8 @@ make_field_assignment (rtx x)
       && INTVAL (XEXP (assign, 1)) < HOST_BITS_PER_WIDE_INT
       && GET_CODE (src) == AND
       && CONST_INT_P (XEXP (src, 1))
-      && ((unsigned HOST_WIDE_INT) INTVAL (XEXP (src, 1))
-         == ((unsigned HOST_WIDE_INT) 1 << INTVAL (XEXP (assign, 1))) - 1))
+      && UINTVAL (XEXP (src, 1))
+        == ((unsigned HOST_WIDE_INT) 1 << INTVAL (XEXP (assign, 1))) - 1)
     src = XEXP (src, 0);
 
   return gen_rtx_SET (VOIDmode, assign, src);
@@ -9385,11 +9535,11 @@ reg_nonzero_bits_for_combine (const_rtx x, enum machine_mode mode,
       if (GET_MODE_BITSIZE (GET_MODE (x)) < GET_MODE_BITSIZE (mode)
          && CONST_INT_P (tem)
          && INTVAL (tem) > 0
-         && 0 != (INTVAL (tem)
-                  & ((HOST_WIDE_INT) 1
+         && 0 != (UINTVAL (tem)
+                  & ((unsigned HOST_WIDE_INT) 1
                      << (GET_MODE_BITSIZE (GET_MODE (x)) - 1))))
-       tem = GEN_INT (INTVAL (tem)
-                      | ((HOST_WIDE_INT) (-1)
+       tem = GEN_INT (UINTVAL (tem)
+                      | ((unsigned HOST_WIDE_INT) (-1)
                          << GET_MODE_BITSIZE (GET_MODE (x))));
 #endif
       return tem;
@@ -9783,8 +9933,8 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
       if (GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
          && code == ASHIFTRT
          && ((nonzero_bits (varop, shift_mode)
-              & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (shift_mode) - 1)))
-             == 0))
+              & ((unsigned HOST_WIDE_INT) 1
+                 << (GET_MODE_BITSIZE (shift_mode) - 1))) == 0))
        code = LSHIFTRT;
 
       if (((code == LSHIFTRT
@@ -9841,7 +9991,9 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
                  > GET_MODE_SIZE (GET_MODE (varop)))
              && (unsigned int) ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (varop)))
                                  + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
-                == mode_words)
+                == mode_words
+             && GET_MODE_CLASS (GET_MODE (varop)) == MODE_INT
+             && GET_MODE_CLASS (GET_MODE (SUBREG_REG (varop))) == MODE_INT)
            {
              varop = SUBREG_REG (varop);
              if (GET_MODE_SIZE (GET_MODE (varop)) > GET_MODE_SIZE (mode))
@@ -9855,13 +10007,13 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
             is cheaper.  But it is still better on those machines to
             merge two shifts into one.  */
          if (CONST_INT_P (XEXP (varop, 1))
-             && exact_log2 (INTVAL (XEXP (varop, 1))) >= 0)
+             && exact_log2 (UINTVAL (XEXP (varop, 1))) >= 0)
            {
              varop
                = simplify_gen_binary (ASHIFT, GET_MODE (varop),
                                       XEXP (varop, 0),
                                       GEN_INT (exact_log2 (
-                                               INTVAL (XEXP (varop, 1)))));
+                                               UINTVAL (XEXP (varop, 1)))));
              continue;
            }
          break;
@@ -9869,13 +10021,13 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
        case UDIV:
          /* Similar, for when divides are cheaper.  */
          if (CONST_INT_P (XEXP (varop, 1))
-             && exact_log2 (INTVAL (XEXP (varop, 1))) >= 0)
+             && exact_log2 (UINTVAL (XEXP (varop, 1))) >= 0)
            {
              varop
                = simplify_gen_binary (LSHIFTRT, GET_MODE (varop),
                                       XEXP (varop, 0),
                                       GEN_INT (exact_log2 (
-                                               INTVAL (XEXP (varop, 1)))));
+                                               UINTVAL (XEXP (varop, 1)))));
              continue;
            }
          break;
@@ -9927,8 +10079,8 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
                {
                  /* C3 has the low-order C1 bits zero.  */
 
-                 mask = (GET_MODE_MASK (mode)
-                         & ~(((HOST_WIDE_INT) 1 << first_count) - 1));
+                 mask = GET_MODE_MASK (mode)
+                        & ~(((unsigned HOST_WIDE_INT) 1 << first_count) - 1);
 
                  varop = simplify_and_const_int (NULL_RTX, result_mode,
                                                  XEXP (varop, 0), mask);
@@ -10150,8 +10302,7 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
              && GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT
              && STORE_FLAG_VALUE == -1
              && nonzero_bits (XEXP (varop, 0), result_mode) == 1
-             && merge_outer_ops (&outer_op, &outer_const, XOR,
-                                 (HOST_WIDE_INT) 1, result_mode,
+             && merge_outer_ops (&outer_op, &outer_const, XOR, 1, result_mode,
                                  &complement_p))
            {
              varop = XEXP (varop, 0);
@@ -10175,8 +10326,7 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
          /* NEG commutes with ASHIFT since it is multiplication.  Move the
             NEG outside to allow shifts to combine.  */
          if (code == ASHIFT
-             && merge_outer_ops (&outer_op, &outer_const, NEG,
-                                 (HOST_WIDE_INT) 0, result_mode,
+             && merge_outer_ops (&outer_op, &outer_const, NEG, 0, result_mode,
                                  &complement_p))
            {
              varop = XEXP (varop, 0);
@@ -10192,8 +10342,7 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
              && count == (GET_MODE_BITSIZE (result_mode) - 1)
              && XEXP (varop, 1) == constm1_rtx
              && nonzero_bits (XEXP (varop, 0), result_mode) == 1
-             && merge_outer_ops (&outer_op, &outer_const, XOR,
-                                 (HOST_WIDE_INT) 1, result_mode,
+             && merge_outer_ops (&outer_op, &outer_const, XOR, 1, result_mode,
                                  &complement_p))
            {
              count = 0;
@@ -10917,7 +11066,8 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
          else if (const_op == 0
                   && mode_width <= HOST_BITS_PER_WIDE_INT
                   && (nonzero_bits (op0, mode)
-                      & ((HOST_WIDE_INT) 1 << (mode_width - 1))) == 0)
+                      & ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)))
+                        == 0)
            code = EQ;
          break;
 
@@ -10947,7 +11097,8 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
          else if (const_op == 0
                   && mode_width <= HOST_BITS_PER_WIDE_INT
                   && (nonzero_bits (op0, mode)
-                      & ((HOST_WIDE_INT) 1 << (mode_width - 1))) == 0)
+                      & ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)))
+                      == 0)
            code = NE;
          break;
 
@@ -10962,8 +11113,9 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
            }
 
          /* (unsigned) < 0x80000000 is equivalent to >= 0.  */
-         else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
-                  && (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1)))
+         else if (mode_width <= HOST_BITS_PER_WIDE_INT
+                  && (unsigned HOST_WIDE_INT) const_op
+                     == (unsigned HOST_WIDE_INT) 1 << (mode_width - 1))
            {
              const_op = 0, op1 = const0_rtx;
              code = GE;
@@ -10978,8 +11130,9 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
            code = EQ;
 
          /* (unsigned) <= 0x7fffffff is equivalent to >= 0.  */
-         else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
-                  && (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1))
+         else if (mode_width <= HOST_BITS_PER_WIDE_INT
+                  && (unsigned HOST_WIDE_INT) const_op
+                     == ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)) - 1)
            {
              const_op = 0, op1 = const0_rtx;
              code = GE;
@@ -10997,8 +11150,9 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
            }
 
          /* (unsigned) >= 0x80000000 is equivalent to < 0.  */
-         else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
-                  && (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1)))
+         else if (mode_width <= HOST_BITS_PER_WIDE_INT
+                  && (unsigned HOST_WIDE_INT) const_op
+                     == (unsigned HOST_WIDE_INT) 1 << (mode_width - 1))
            {
              const_op = 0, op1 = const0_rtx;
              code = LT;
@@ -11013,8 +11167,9 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
            code = NE;
 
          /* (unsigned) > 0x7fffffff is equivalent to < 0.  */
-         else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
-                  && (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1))
+         else if (mode_width <= HOST_BITS_PER_WIDE_INT
+                  && (unsigned HOST_WIDE_INT) const_op
+                     == ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)) - 1)
            {
              const_op = 0, op1 = const0_rtx;
              code = LT;
@@ -11037,8 +11192,8 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
       if (sign_bit_comparison_p
          && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
        op0 = force_to_mode (op0, mode,
-                            ((HOST_WIDE_INT) 1
-                             << (GET_MODE_BITSIZE (mode) - 1)),
+                            (unsigned HOST_WIDE_INT) 1
+                            << (GET_MODE_BITSIZE (mode) - 1),
                             0);
 
       /* Now try cases based on the opcode of OP0.  If none of the cases
@@ -11058,7 +11213,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              && CONST_INT_P (XEXP (op0, 0))
              && XEXP (op0, 1) == const1_rtx
              && equality_comparison_p && const_op == 0
-             && (i = exact_log2 (INTVAL (XEXP (op0, 0)))) >= 0)
+             && (i = exact_log2 (UINTVAL (XEXP (op0, 0)))) >= 0)
            {
              if (BITS_BIG_ENDIAN)
                {
@@ -11134,7 +11289,8 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              && (GET_CODE (XEXP (op0, 0)) == ABS
                  || (mode_width <= HOST_BITS_PER_WIDE_INT
                      && (nonzero_bits (XEXP (op0, 0), mode)
-                         & ((HOST_WIDE_INT) 1 << (mode_width - 1))) == 0)))
+                         & ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)))
+                        == 0)))
            {
              op0 = XEXP (op0, 0);
              code = (code == LT ? NE : EQ);
@@ -11171,7 +11327,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              && mode_width <= HOST_BITS_PER_WIDE_INT)
            {
              op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0),
-                                           ((HOST_WIDE_INT) 1
+                                           ((unsigned HOST_WIDE_INT) 1
                                             << (mode_width - 1
                                                 - INTVAL (XEXP (op0, 1)))));
              code = (code == LT ? NE : EQ);
@@ -11348,8 +11504,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
             of bits in X minus 1, is one iff X > 0.  */
          if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 0)) == ASHIFTRT
              && CONST_INT_P (XEXP (XEXP (op0, 0), 1))
-             && (unsigned HOST_WIDE_INT) INTVAL (XEXP (XEXP (op0, 0), 1))
-                == mode_width - 1
+             && UINTVAL (XEXP (XEXP (op0, 0), 1)) == mode_width - 1
              && rtx_equal_p (XEXP (XEXP (op0, 0), 0), XEXP (op0, 1)))
            {
              op0 = XEXP (op0, 1);
@@ -11395,7 +11550,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              || (GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT
                  && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
                  && (STORE_FLAG_VALUE
-                     & (((HOST_WIDE_INT) 1
+                     & (((unsigned HOST_WIDE_INT) 1
                          << (GET_MODE_BITSIZE (GET_MODE (op0)) - 1))))
                  && (code == LT || code == GE)))
            {
@@ -11435,11 +11590,9 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              && GET_CODE (XEXP (op0, 0)) == ASHIFT
              && XEXP (XEXP (op0, 0), 0) == const1_rtx)
            {
-             op0 = simplify_and_const_int
-               (NULL_RTX, mode, gen_rtx_LSHIFTRT (mode,
-                                                  XEXP (op0, 1),
-                                                  XEXP (XEXP (op0, 0), 1)),
-                (HOST_WIDE_INT) 1);
+             op0 = gen_rtx_LSHIFTRT (mode, XEXP (op0, 1),
+                                     XEXP (XEXP (op0, 0), 1));
+             op0 = simplify_and_const_int (NULL_RTX, mode, op0, 1);
              continue;
            }
 
@@ -11496,7 +11649,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
             transformation is invalid.  */
          if ((equality_comparison_p || unsigned_comparison_p)
              && CONST_INT_P (XEXP (op0, 1))
-             && (i = exact_log2 ((INTVAL (XEXP (op0, 1))
+             && (i = exact_log2 ((UINTVAL (XEXP (op0, 1))
                                   & GET_MODE_MASK (mode))
                                  + 1)) >= 0
              && const_op >> i == 0
@@ -11556,8 +11709,8 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              && XEXP (op0, 1) == const1_rtx
              && GET_CODE (XEXP (op0, 0)) == NOT)
            {
-             op0 = simplify_and_const_int
-               (NULL_RTX, mode, XEXP (XEXP (op0, 0), 0), (HOST_WIDE_INT) 1);
+             op0 = simplify_and_const_int (NULL_RTX, mode,
+                                           XEXP (XEXP (op0, 0), 0), 1);
              code = (code == NE ? EQ : NE);
              continue;
            }
@@ -11577,13 +11730,13 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
                      && CONST_INT_P (XEXP (shift_op, 1))
                      && CONST_INT_P (shift_count)
                      && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-                     && (INTVAL (XEXP (shift_op, 1))
-                         == (HOST_WIDE_INT) 1 << INTVAL (shift_count))))
+                     && (UINTVAL (XEXP (shift_op, 1))
+                         == (unsigned HOST_WIDE_INT) 1
+                              << INTVAL (shift_count))))
                {
-                 op0 = simplify_and_const_int
-                   (NULL_RTX, mode,
-                    gen_rtx_LSHIFTRT (mode, XEXP (shift_op, 0), shift_count),
-                    (HOST_WIDE_INT) 1);
+                 op0
+                   = gen_rtx_LSHIFTRT (mode, XEXP (shift_op, 0), shift_count);
+                 op0 = simplify_and_const_int (NULL_RTX, mode, op0, 1);
                  code = (code == NE ? EQ : NE);
                  continue;
                }
@@ -11600,8 +11753,9 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              && INTVAL (XEXP (op0, 1)) >= 0
              && ((INTVAL (XEXP (op0, 1)) + ! equality_comparison_p)
                  < HOST_BITS_PER_WIDE_INT)
-             && ((const_op
-                  & (((HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1))) - 1)) == 0)
+             && (((unsigned HOST_WIDE_INT) const_op
+                  & (((unsigned HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1)))
+                     - 1)) == 0)
              && mode_width <= HOST_BITS_PER_WIDE_INT
              && (nonzero_bits (XEXP (op0, 0), mode)
                  & ~(mask >> (INTVAL (XEXP (op0, 1))
@@ -11623,7 +11777,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              && mode_width <= HOST_BITS_PER_WIDE_INT)
            {
              op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0),
-                                           ((HOST_WIDE_INT) 1
+                                           ((unsigned HOST_WIDE_INT) 1
                                             << (mode_width - 1
                                                 - INTVAL (XEXP (op0, 1)))));
              code = (code == LT ? NE : EQ);
@@ -11635,11 +11789,9 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
             low-order bit.  */
          if (const_op == 0 && equality_comparison_p
              && CONST_INT_P (XEXP (op0, 1))
-             && (unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1))
-                == mode_width - 1)
+             && UINTVAL (XEXP (op0, 1)) == mode_width - 1)
            {
-             op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0),
-                                           (HOST_WIDE_INT) 1);
+             op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0), 1);
              continue;
            }
          break;
@@ -11703,13 +11855,14 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
          /* If we have (compare (xshiftrt FOO N) (const_int C)) and
             the low order N bits of FOO are known to be zero, we can do this
             by comparing FOO with C shifted left N bits so long as no
-            overflow occurs.  */
+            overflow occurs.  Even if the low order N bits of FOO aren't known
+            to be zero, if the comparison is >= or < we can use the same
+            optimization and for > or <= by setting all the low
+            order N bits in the comparison constant.  */
          if (CONST_INT_P (XEXP (op0, 1))
-             && INTVAL (XEXP (op0, 1)) >= 0
+             && INTVAL (XEXP (op0, 1)) > 0
              && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT
              && mode_width <= HOST_BITS_PER_WIDE_INT
-             && (nonzero_bits (XEXP (op0, 0), mode)
-                 & (((HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1))) - 1)) == 0
              && (((unsigned HOST_WIDE_INT) const_op
                   + (GET_CODE (op0) != LSHIFTRT
                      ? ((GET_MODE_MASK (mode) >> INTVAL (XEXP (op0, 1)) >> 1)
@@ -11717,15 +11870,27 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
                      : 0))
                  <= GET_MODE_MASK (mode) >> INTVAL (XEXP (op0, 1))))
            {
-             /* If the shift was logical, then we must make the condition
-                unsigned.  */
-             if (GET_CODE (op0) == LSHIFTRT)
-               code = unsigned_condition (code);
-
-             const_op <<= INTVAL (XEXP (op0, 1));
-             op1 = GEN_INT (const_op);
-             op0 = XEXP (op0, 0);
-             continue;
+             unsigned HOST_WIDE_INT low_bits
+               = (nonzero_bits (XEXP (op0, 0), mode)
+                  & (((unsigned HOST_WIDE_INT) 1
+                      << INTVAL (XEXP (op0, 1))) - 1));
+             if (low_bits == 0 || !equality_comparison_p)
+               {
+                 /* If the shift was logical, then we must make the condition
+                    unsigned.  */
+                 if (GET_CODE (op0) == LSHIFTRT)
+                   code = unsigned_condition (code);
+
+                 const_op <<= INTVAL (XEXP (op0, 1));
+                 if (low_bits != 0
+                     && (code == GT || code == GTU
+                         || code == LE || code == LEU))
+                   const_op
+                     |= (((HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1))) - 1);
+                 op1 = GEN_INT (const_op);
+                 op0 = XEXP (op0, 0);
+                 continue;
+               }
            }
 
          /* If we are using this shift to extract just the sign bit, we
@@ -11733,8 +11898,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
          if (const_op == 0
              && (equality_comparison_p || sign_bit_comparison_p)
              && CONST_INT_P (XEXP (op0, 1))
-             && (unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1))
-                == mode_width - 1)
+             && UINTVAL (XEXP (op0, 1)) == mode_width - 1)
            {
              op0 = XEXP (op0, 0);
              code = (code == NE || code == GT ? LT : GE);
@@ -11831,7 +11995,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
            {
              op0 = simplify_gen_binary (AND, tmode,
                                         gen_lowpart (tmode, op0),
-                                        GEN_INT ((HOST_WIDE_INT) 1
+                                        GEN_INT ((unsigned HOST_WIDE_INT) 1
                                                  << (GET_MODE_BITSIZE (mode)
                                                      - 1)));
              code = (code == LT) ? NE : EQ;
@@ -12248,7 +12412,8 @@ record_dead_and_set_regs (rtx insn)
 static void
 record_promoted_value (rtx insn, rtx subreg)
 {
-  rtx links, set;
+  struct insn_link *links;
+  rtx set;
   unsigned int regno = REGNO (SUBREG_REG (subreg));
   enum machine_mode mode = GET_MODE (subreg);
 
@@ -12259,14 +12424,14 @@ record_promoted_value (rtx insn, rtx subreg)
     {
       reg_stat_type *rsp;
 
-      insn = XEXP (links, 0);
+      insn = links->insn;
       set = single_set (insn);
 
       if (! set || !REG_P (SET_DEST (set))
          || REGNO (SET_DEST (set)) != regno
          || GET_MODE (SET_DEST (set)) != GET_MODE (SUBREG_REG (subreg)))
        {
-         links = XEXP (links, 1);
+         links = links->next;
          continue;
        }
 
@@ -12747,7 +12912,7 @@ mark_used_regs_combine (rtx x)
        {
          /* None of this applies to the stack, frame or arg pointers.  */
          if (regno == STACK_POINTER_REGNUM
-#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
              || regno == HARD_FRAME_POINTER_REGNUM
 #endif
 #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
@@ -13050,10 +13215,6 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
          place = i3;
          break;
 
-       case REG_VALUE_PROFILE:
-         /* Just get rid of this note, as it is unused later anyway.  */
-         break;
-
        case REG_NON_LOCAL_GOTO:
          if (JUMP_P (i3))
            place = i3;
@@ -13403,8 +13564,8 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
                          && DF_INSN_LUID (from_insn) > DF_INSN_LUID (i2)
                          && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
                        {
-                         rtx links = LOG_LINKS (place);
-                         LOG_LINKS (place) = 0;
+                         struct insn_link *links = LOG_LINKS (place);
+                         LOG_LINKS (place) = NULL;
                          distribute_links (links);
                        }
                      break;
@@ -13535,9 +13696,9 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
    pointing at I3 when I3's destination is changed.  */
 
 static void
-distribute_links (rtx links)
+distribute_links (struct insn_link *links)
 {
-  rtx link, next_link;
+  struct insn_link *link, *next_link;
 
   for (link = links; link; link = next_link)
     {
@@ -13545,7 +13706,7 @@ distribute_links (rtx links)
       rtx insn;
       rtx set, reg;
 
-      next_link = XEXP (link, 1);
+      next_link = link->next;
 
       /* If the insn that this link points to is a NOTE or isn't a single
         set, ignore it.  In the latter case, it isn't clear what we
@@ -13558,8 +13719,8 @@ distribute_links (rtx links)
         replace I3, I2, and I1 by I3 and I2.  But in that case the
         destination of I2 also remains unchanged.  */
 
-      if (NOTE_P (XEXP (link, 0))
-         || (set = single_set (XEXP (link, 0))) == 0)
+      if (NOTE_P (link->insn)
+         || (set = single_set (link->insn)) == 0)
        continue;
 
       reg = SET_DEST (set);
@@ -13576,7 +13737,7 @@ distribute_links (rtx links)
         I3 to I2.  Also note that not much searching is typically done here
         since most links don't point very far away.  */
 
-      for (insn = NEXT_INSN (XEXP (link, 0));
+      for (insn = NEXT_INSN (link->insn);
           (insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR
                     || BB_HEAD (this_basic_block->next_bb) != insn));
           insn = NEXT_INSN (insn))
@@ -13602,15 +13763,15 @@ distribute_links (rtx links)
 
       if (place)
        {
-         rtx link2;
+         struct insn_link *link2;
 
-         for (link2 = LOG_LINKS (place); link2; link2 = XEXP (link2, 1))
-           if (XEXP (link2, 0) == XEXP (link, 0))
+         FOR_EACH_LOG_LINK (link2, place)
+           if (link2->insn == link->insn)
              break;
 
-         if (link2 == 0)
+         if (link2 == NULL)
            {
-             XEXP (link, 1) = LOG_LINKS (place);
+             link->next = LOG_LINKS (place);
              LOG_LINKS (place) = link;
 
              /* Set added_links_insn to the earliest insn we added a