]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/combine.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / combine.c
index 36713a1daca617e734fba52e8fbca93ff5f7dc64..892c834a160ad56cc1c5dd3c57199b2390b382a0 100644 (file)
@@ -1,5 +1,5 @@
 /* Optimize by combining instructions for GNU compiler.
-   Copyright (C) 1987-2018 Free Software Foundation, Inc.
+   Copyright (C) 1987-2021 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -33,12 +33,6 @@ along with GCC; see the file COPYING3.  If not see
    small number of quadruplets of insns A, B, C and D for which
    there's high likelihood of success.
 
-   LOG_LINKS does not have links for use of the CC0.  They don't
-   need to, because the insn that sets the CC0 is always immediately
-   before the insn that tests it.  So we always regard a branch
-   insn as having a logical link to the preceding insn.  The same is true
-   for an insn explicitly using CC0.
-
    We check (with modified_between_p) to avoid combining in such a way
    as to move a computation to a place where its value would be different.
 
@@ -64,16 +58,7 @@ along with GCC; see the file COPYING3.  If not see
 
    To simplify substitution, we combine only when the earlier insn(s)
    consist of only a single assignment.  To simplify updating afterward,
-   we never combine when a subroutine call appears in the middle.
-
-   Since we do not represent assignments to CC0 explicitly except when that
-   is all an insn does, there is no LOG_LINKS entry in an insn that uses
-   the condition code for the insn that set the condition code.
-   Fortunately, these two insns must be consecutive.
-   Therefore, every JUMP_INSN is taken to have an implicit logical link
-   to the preceding insn.  This is not quite right, since non-jumps can
-   also use the condition code; but in practice such insns would not
-   combine anyway.  */
+   we never combine when a subroutine call appears in the middle.  */
 
 #include "config.h"
 #include "system.h"
@@ -99,11 +84,13 @@ along with GCC; see the file COPYING3.  If not see
 #include "explow.h"
 #include "insn-attr.h"
 #include "rtlhooks-def.h"
-#include "params.h"
+#include "expr.h"
 #include "tree-pass.h"
 #include "valtrack.h"
 #include "rtl-iter.h"
 #include "print-rtl.h"
+#include "function-abi.h"
+#include "rtlanal.h"
 
 /* Number of attempts to combine instructions in this function.  */
 
@@ -529,7 +516,7 @@ target_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1,
 }
 
 /* Try to split PATTERN found in INSN.  This returns NULL_RTX if
-   PATTERN can not be split.  Otherwise, it returns an insn sequence.
+   PATTERN cannot be split.  Otherwise, it returns an insn sequence.
    This is a wrapper around split_insns which ensures that the
    reg_stat vector is made larger if the splitter creates a new
    register.  */
@@ -543,13 +530,13 @@ combine_split_insns (rtx pattern, rtx_insn *insn)
   ret = split_insns (pattern, insn);
   nregs = max_reg_num ();
   if (nregs > reg_stat.length ())
-    reg_stat.safe_grow_cleared (nregs);
+    reg_stat.safe_grow_cleared (nregs, true);
   return ret;
 }
 
 /* This is used by find_single_use to locate an rtx in LOC that
-   contains exactly one use of DEST, which is typically either a REG
-   or CC0.  It returns a pointer to the innermost rtx expression
+   contains exactly one use of DEST, which is typically a REG.
+   It returns a pointer to the innermost rtx expression
    containing DEST.  Appearances of DEST that are being used to
    totally replace it are not counted.  */
 
@@ -573,12 +560,11 @@ find_single_use_1 (rtx dest, rtx *loc)
       return 0;
 
     case SET:
-      /* If the destination is anything other than CC0, PC, a REG or a SUBREG
+      /* If the destination is anything other than PC, a REG or a SUBREG
         of a REG that occupies all of the REG, the insn uses DEST if
         it is mentioned in the destination or the source.  Otherwise, we
         need just check the source.  */
-      if (GET_CODE (SET_DEST (x)) != CC0
-         && GET_CODE (SET_DEST (x)) != PC
+      if (GET_CODE (SET_DEST (x)) != PC
          && !REG_P (SET_DEST (x))
          && ! (GET_CODE (SET_DEST (x)) == SUBREG
                && REG_P (SUBREG_REG (SET_DEST (x)))
@@ -648,9 +634,6 @@ find_single_use_1 (rtx dest, rtx *loc)
 
    If PLOC is nonzero, *PLOC is set to the insn containing the single use.
 
-   If DEST is cc0_rtx, we look only at the next insn.  In that case, we don't
-   care about REG_DEAD notes or LOG_LINKS.
-
    Otherwise, we find the single use by finding an insn that has a
    LOG_LINKS pointing at INSN and has a REG_DEAD note for DEST.  If DEST is
    only referenced once in that insn, we know that it must be the first
@@ -664,19 +647,6 @@ find_single_use (rtx dest, rtx_insn *insn, rtx_insn **ploc)
   rtx *result;
   struct insn_link *link;
 
-  if (dest == cc0_rtx)
-    {
-      next = NEXT_INSN (insn);
-      if (next == 0
-         || (!NONJUMP_INSN_P (next) && !JUMP_P (next)))
-       return 0;
-
-      result = find_single_use_1 (dest, &PATTERN (next));
-      if (result && ploc)
-       *ploc = next;
-      return result;
-    }
-
   if (!REG_P (dest))
     return 0;
 
@@ -981,14 +951,17 @@ combine_validate_cost (rtx_insn *i0, rtx_insn *i1, rtx_insn *i2, rtx_insn *i3,
 }
 
 
-/* Delete any insns that copy a register to itself.  */
+/* Delete any insns that copy a register to itself.
+   Return true if the CFG was changed.  */
 
-static void
+static bool
 delete_noop_moves (void)
 {
   rtx_insn *insn, *next;
   basic_block bb;
 
+  bool edges_deleted = false;
+
   FOR_EACH_BB_FN (bb, cfun)
     {
       for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); insn = next)
@@ -999,10 +972,12 @@ delete_noop_moves (void)
              if (dump_file)
                fprintf (dump_file, "deleting noop move %d\n", INSN_UID (insn));
 
-             delete_insn_and_edges (insn);
+             edges_deleted |= delete_insn_and_edges (insn);
            }
        }
     }
+
+  return edges_deleted;
 }
 
 \f
@@ -1122,9 +1097,7 @@ create_log_links (void)
 /* 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.
-   We also check the implicit dependency created by a cc0 setter/user
-   pair.  */
+   depending on A, since in that case we would not record a link for B.  */
 
 static bool
 insn_a_feeds_b (rtx_insn *a, rtx_insn *b)
@@ -1133,21 +1106,18 @@ insn_a_feeds_b (rtx_insn *a, rtx_insn *b)
   FOR_EACH_LOG_LINK (links, b)
     if (links->insn == a)
       return true;
-  if (HAVE_cc0 && sets_cc0_p (a))
-    return true;
   return false;
 }
 \f
 /* Main entry point for combiner.  F is the first insn of the function.
    NREGS is the first unused pseudo-reg number.
 
-   Return nonzero if the combiner has turned an indirect jump
-   instruction into a direct jump.  */
+   Return nonzero if the CFG was changed (e.g. if the combiner has
+   turned an indirect jump instruction into a direct jump).  */
 static int
 combine_instructions (rtx_insn *f, unsigned int nregs)
 {
   rtx_insn *insn, *next;
-  rtx_insn *prev;
   struct insn_link *links, *nextlinks;
   rtx_insn *first;
   basic_block last_bb;
@@ -1166,7 +1136,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs)
 
   rtl_hooks = combine_rtl_hooks;
 
-  reg_stat.safe_grow_cleared (nregs);
+  reg_stat.safe_grow_cleared (nregs, true);
 
   init_recog_no_volatile ();
 
@@ -1217,8 +1187,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs)
             subst_low_luid = DF_INSN_LUID (insn);
             subst_insn = insn;
 
-           note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies,
-                        insn);
+           note_stores (insn, set_nonzero_bits_and_sign_copies, insn);
            record_dead_and_set_regs (insn);
 
            if (AUTO_INC_DEC)
@@ -1228,8 +1197,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs)
                                                    insn);
 
            /* Record the current insn_cost of this instruction.  */
-           if (NONJUMP_INSN_P (insn))
-             INSN_COST (insn) = insn_cost (insn, optimize_this_for_speed_p);
+           INSN_COST (insn) = insn_cost (insn, optimize_this_for_speed_p);
            if (dump_file)
              {
                fprintf (dump_file, "insn_cost %d for ", INSN_COST (insn));
@@ -1245,7 +1213,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs)
   init_reg_last ();
   setup_incoming_promotions (first);
   last_bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
-  int max_combine = PARAM_VALUE (PARAM_MAX_COMBINE_INSNS);
+  int max_combine = param_max_combine_insns;
 
   FOR_EACH_BB_FN (this_basic_block, cfun)
     {
@@ -1326,69 +1294,6 @@ combine_instructions (rtx_insn *f, unsigned int nregs)
                    }
              }
 
-         /* Try to combine a jump insn that uses CC0
-            with a preceding insn that sets CC0, and maybe with its
-            logical predecessor as well.
-            This is how we make decrement-and-branch insns.
-            We need this special code because data flow connections
-            via CC0 do not get entered in LOG_LINKS.  */
-
-         if (HAVE_cc0
-             && JUMP_P (insn)
-             && (prev = prev_nonnote_insn (insn)) != 0
-             && NONJUMP_INSN_P (prev)
-             && sets_cc0_p (PATTERN (prev)))
-           {
-             if ((next = try_combine (insn, prev, NULL, NULL,
-                                      &new_direct_jump_p,
-                                      last_combined_insn)) != 0)
-               goto retry;
-
-             FOR_EACH_LOG_LINK (nextlinks, prev)
-                 if ((next = try_combine (insn, prev, nextlinks->insn,
-                                          NULL, &new_direct_jump_p,
-                                          last_combined_insn)) != 0)
-                   goto retry;
-           }
-
-         /* Do the same for an insn that explicitly references CC0.  */
-         if (HAVE_cc0 && NONJUMP_INSN_P (insn)
-             && (prev = prev_nonnote_insn (insn)) != 0
-             && NONJUMP_INSN_P (prev)
-             && sets_cc0_p (PATTERN (prev))
-             && GET_CODE (PATTERN (insn)) == SET
-             && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (insn))))
-           {
-             if ((next = try_combine (insn, prev, NULL, NULL,
-                                      &new_direct_jump_p,
-                                      last_combined_insn)) != 0)
-               goto retry;
-
-             FOR_EACH_LOG_LINK (nextlinks, prev)
-                 if ((next = try_combine (insn, prev, nextlinks->insn,
-                                          NULL, &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.  */
-         if (HAVE_cc0)
-           {
-             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, links->insn,
-                                           prev, NULL, &new_direct_jump_p,
-                                           last_combined_insn)) != 0)
-                 goto retry;
-           }
-
          /* Try combining an insn with two different insns whose results it
             uses.  */
          if (max_combine >= 3)
@@ -1481,6 +1386,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs)
              if ((set = single_set (temp)) != 0
                  && (note = find_reg_equal_equiv_note (temp)) != 0
                  && (note = XEXP (note, 0), GET_CODE (note)) != EXPR_LIST
+                 && ! side_effects_p (SET_SRC (set))
                  /* Avoid using a register that may already been marked
                     dead by an earlier instruction.  */
                  && ! unmentioned_reg_p (note, SET_SRC (set))
@@ -1527,7 +1433,7 @@ retry:
   default_rtl_profile ();
   clear_bb_flags ();
   new_direct_jump_p |= purge_all_dead_edges ();
-  delete_noop_moves ();
+  new_direct_jump_p |= delete_noop_moves ();
 
   /* Clean up.  */
   obstack_free (&insn_link_obstack, NULL);
@@ -1594,7 +1500,8 @@ setup_incoming_promotions (rtx_insn *first)
          function lie within the current compilation unit.  (This does
         take into account the exporting of a function via taking its
         address, and so forth.)  */
-      strictly_local = cgraph_node::local_info (current_function_decl)->local;
+      strictly_local
+       = cgraph_node::local_info_node (current_function_decl)->local;
 
       /* The mode and signedness of the argument before any promotions happen
          (equal to the mode of the pseudo holding it at that stage).  */
@@ -1696,9 +1603,13 @@ update_rsp_from_reg_equal (reg_stat_type *rsp, rtx_insn *insn, const_rtx set,
   /* Don't call nonzero_bits if it cannot change anything.  */
   if (rsp->nonzero_bits != HOST_WIDE_INT_M1U)
     {
-      bits = nonzero_bits (src, nonzero_bits_mode);
+      machine_mode mode = GET_MODE (x);
+      if (GET_MODE_CLASS (mode) == MODE_INT
+         && HWI_COMPUTABLE_MODE_P (mode))
+       mode = nonzero_bits_mode;
+      bits = nonzero_bits (src, mode);
       if (reg_equal && bits)
-       bits &= nonzero_bits (reg_equal, nonzero_bits_mode);
+       bits &= nonzero_bits (reg_equal, mode);
       rsp->nonzero_bits |= bits;
     }
 
@@ -1706,7 +1617,7 @@ update_rsp_from_reg_equal (reg_stat_type *rsp, rtx_insn *insn, const_rtx set,
   if (rsp->sign_bit_copies != 1)
     {
       num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x));
-      if (reg_equal && num != GET_MODE_PRECISION (GET_MODE (x)))
+      if (reg_equal && maybe_ne (num, GET_MODE_PRECISION (GET_MODE (x))))
        {
          unsigned int numeq = num_sign_bit_copies (reg_equal, GET_MODE (x));
          if (num == 0 || numeq > num)
@@ -1843,7 +1754,7 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED,
   else if (next_active_insn (insn) != i3)
     all_adjacent = false;
     
-  /* Can combine only if previous insn is a SET of a REG, a SUBREG or CC0.
+  /* Can combine only if previous insn is a SET of a REG or a SUBREG,
      or a PARALLEL consisting of such a SET and CLOBBERs.
 
      If INSN has CLOBBER parallel parts, ignore them for our processing.
@@ -1990,6 +1901,7 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED,
               && (reg_used_between_p (dest, succ2, i3)
                   || reg_used_between_p (dest, succ, succ2)))
              || (!succ2 && succ && reg_used_between_p (dest, succ, i3))
+             || (!succ2 && !succ && reg_used_between_p (dest, insn, i3))
              || (succ
                  /* SUCC and SUCC2 can be split halves from a PARALLEL; in
                     that case SUCC is not in the insn stream, so use SUCC2
@@ -2021,7 +1933,7 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED,
       || (DF_INSN_LUID (insn) < last_call_luid && ! CONSTANT_P (src)))
     return 0;
 
-  /* DEST must either be a REG or CC0.  */
+  /* DEST must be a REG.  */
   if (REG_P (dest))
     {
       /* If register alignment is being enforced for multi-word items in all
@@ -2048,7 +1960,7 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED,
                                                  GET_MODE (src)))))
        return 0;
     }
-  else if (GET_CODE (dest) != CC0)
+  else
     return 0;
 
 
@@ -2100,7 +2012,7 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED,
   is_volatile_p = volatile_refs_p (PATTERN (insn))
     ? volatile_refs_p
     : volatile_insn_p;
-    
+
   for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
     if (INSN_P (p) && p != succ && p != succ2 && is_volatile_p (PATTERN (p)))
       return 0;
@@ -2108,13 +2020,14 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED,
   /* If INSN contains an autoincrement or autodecrement, make sure that
      register is not used between there and I3, and not already used in
      I3 either.  Neither must it be used in PRED or SUCC, if they exist.
-     Also insist that I3 not be a jump; if it were one
-     and the incremented register were spilled, we would lose.  */
+     Also insist that I3 not be a jump if using LRA; if it were one
+     and the incremented register were spilled, we would lose.
+     Reload handles this correctly.  */
 
   if (AUTO_INC_DEC)
     for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
       if (REG_NOTE_KIND (link) == REG_INC
-         && (JUMP_P (i3)
+         && ((JUMP_P (i3) && targetm.lra_p ())
              || reg_used_between_p (XEXP (link, 0), insn, i3)
              || (pred != NULL_RTX
                  && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (pred)))
@@ -2127,23 +2040,6 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED,
              || reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i3))))
        return 0;
 
-  /* Don't combine an insn that follows a CC0-setting insn.
-     An insn that uses CC0 must not be separated from the one that sets it.
-     We do, however, allow I2 to follow a CC0-setting insn if that insn
-     is passed as I1; in that case it will be deleted also.
-     We also allow combining in this case if all the insns are adjacent
-     because that would leave the two CC0 insns adjacent as well.
-     It would be more logical to test whether CC0 occurs inside I1 or I2,
-     but that would be much slower, and this ought to be equivalent.  */
-
-  if (HAVE_cc0)
-    {
-      p = prev_nonnote_insn (insn);
-      if (p && p != pred && NONJUMP_INSN_P (p) && sets_cc0_p (PATTERN (p))
-         && ! all_adjacent)
-       return 0;
-    }
-
   /* If we get here, we have passed all the tests and the combination is
      to be allowed.  */
 
@@ -2343,7 +2239,11 @@ cant_combine_insn_p (rtx_insn *insn)
   if (REG_P (src) && REG_P (dest)
       && ((HARD_REGISTER_P (src)
           && ! TEST_HARD_REG_BIT (fixed_reg_set, REGNO (src))
-          && targetm.class_likely_spilled_p (REGNO_REG_CLASS (REGNO (src))))
+#ifdef LEAF_REGISTERS
+          && ! LEAF_REGISTERS [REGNO (src)])
+#else
+          )
+#endif
          || (HARD_REGISTER_P (dest)
              && ! TEST_HARD_REG_BIT (fixed_reg_set, REGNO (dest))
              && targetm.class_likely_spilled_p (REGNO_REG_CLASS (REGNO (dest))))))
@@ -2419,7 +2319,7 @@ likely_spilled_retval_p (rtx_insn *insn)
   info.mask = mask;
   for (p = PREV_INSN (use); info.mask && p != insn; p = PREV_INSN (p))
     if (INSN_P (p))
-      note_stores (PATTERN (p), likely_spilled_retval_1, &info);
+      note_stores (p, likely_spilled_retval_1, &info);
   mask = info.mask;
 
   /* Check if any of the (probably) live return value registers is
@@ -2443,7 +2343,7 @@ static void
 adjust_for_new_dest (rtx_insn *insn)
 {
   /* For notes, be conservative and simply remove them.  */
-  remove_reg_equal_equiv_notes (insn);
+  remove_reg_equal_equiv_notes (insn, true);
 
   /* 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
@@ -2515,42 +2415,6 @@ reg_subword_p (rtx x, rtx reg)
         && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT;
 }
 
-/* Delete the unconditional jump INSN and adjust the CFG correspondingly.
-   Note that the INSN should be deleted *after* removing dead edges, so
-   that the kept edge is the fallthrough edge for a (set (pc) (pc))
-   but not for a (set (pc) (label_ref FOO)).  */
-
-static void
-update_cfg_for_uncondjump (rtx_insn *insn)
-{
-  basic_block bb = BLOCK_FOR_INSN (insn);
-  gcc_assert (BB_END (bb) == insn);
-
-  purge_dead_edges (bb);
-
-  delete_insn (insn);
-  if (EDGE_COUNT (bb->succs) == 1)
-    {
-      rtx_insn *insn;
-
-      single_succ_edge (bb)->flags |= EDGE_FALLTHRU;
-
-      /* Remove barriers from the footer if there are any.  */
-      for (insn = BB_FOOTER (bb); insn; insn = NEXT_INSN (insn))
-       if (BARRIER_P (insn))
-         {
-           if (PREV_INSN (insn))
-             SET_NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
-           else
-             BB_FOOTER (bb) = NEXT_INSN (insn);
-           if (NEXT_INSN (insn))
-             SET_PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
-         }
-       else if (LABEL_P (insn))
-         break;
-    }
-}
-
 /* Return whether PAT is a PARALLEL of exactly N register SETs followed
    by an arbitrary number of CLOBBERs.  */
 static bool
@@ -2569,10 +2433,15 @@ is_parallel_of_n_reg_sets (rtx pat, int n)
        || !REG_P (SET_DEST (XVECEXP (pat, 0, i))))
       return false;
   for ( ; i < len; i++)
-    if (GET_CODE (XVECEXP (pat, 0, i)) != CLOBBER
-       || XEXP (XVECEXP (pat, 0, i), 0) == const0_rtx)
-      return false;
-
+    switch (GET_CODE (XVECEXP (pat, 0, i)))
+      {
+      case CLOBBER:
+       if (XEXP (XVECEXP (pat, 0, i), 0) == const0_rtx)
+         return false;
+       break;
+      default:
+       return false;
+      }
   return true;
 }
 
@@ -2603,6 +2472,28 @@ can_split_parallel_of_n_reg_sets (rtx_insn *insn, int n)
   return true;
 }
 
+/* Return whether X is just a single_set, with the source
+   a general_operand.  */
+static bool
+is_just_move (rtx_insn *x)
+{
+  rtx set = single_set (x);
+  if (!set)
+    return false;
+
+  return general_operand (SET_SRC (set), VOIDmode);
+}
+
+/* Callback function to count autoincs.  */
+
+static int
+count_auto_inc (rtx, rtx, rtx, rtx, rtx, void *arg)
+{
+  (*((int *) arg))++;
+
+  return 0;
+}
+
 /* Try to combine the insns I0, I1 and I2 into I3.
    Here I0, I1 and I2 appear earlier than I3.
    I0 and I1 can be zero; then we combine just I2 into I3, or I1 and I2 into
@@ -2665,7 +2556,10 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
   /* Notes that I1, I2 or I3 is a MULT operation.  */
   int have_mult = 0;
   int swap_i2i3 = 0;
+  int split_i2i3 = 0;
   int changed_i3_dest = 0;
+  bool i2_was_move = false, i3_was_move = false;
+  int n_auto_inc = 0;
 
   int maxreg;
   rtx_insn *temp_insn;
@@ -2978,7 +2872,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
      This undoes a previous combination and allows us to match a branch-and-
      decrement insn.  */
 
-  if (!HAVE_cc0 && i1 == 0
+  if (i1 == 0
       && is_parallel_of_n_reg_sets (PATTERN (i2), 2)
       && (GET_MODE_CLASS (GET_MODE (SET_DEST (XVECEXP (PATTERN (i2), 0, 0))))
          == MODE_CC)
@@ -3010,7 +2904,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
   /* If I2 is a PARALLEL of two SETs of REGs (and perhaps some CLOBBERs),
      make those two SETs separate I1 and I2 insns, and make an I0 that is
      the original I1.  */
-  if (!HAVE_cc0 && i0 == 0
+  if (i0 == 0
       && is_parallel_of_n_reg_sets (PATTERN (i2), 2)
       && can_split_parallel_of_n_reg_sets (i2, 2)
       && !reg_used_between_p (SET_DEST (XVECEXP (PATTERN (i2), 0, 0)), i2, i3)
@@ -3037,26 +2931,30 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
   /* Verify that I2 and maybe I1 and I0 can be combined into I3.  */
   if (!can_combine_p (i2, i3, i0, i1, NULL, NULL, &i2dest, &i2src))
     {
-      if (dump_file)
+      if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, "Can't combine i2 into i3\n");
       undo_all ();
       return 0;
     }
   if (i1 && !can_combine_p (i1, i3, i0, NULL, i2, NULL, &i1dest, &i1src))
     {
-      if (dump_file)
+      if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, "Can't combine i1 into i3\n");
       undo_all ();
       return 0;
     }
   if (i0 && !can_combine_p (i0, i3, NULL, NULL, i1, i2, &i0dest, &i0src))
     {
-      if (dump_file)
+      if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, "Can't combine i0 into i3\n");
       undo_all ();
       return 0;
     }
 
+  /* Record whether i2 and i3 are trivial moves.  */
+  i2_was_move = is_just_move (i2);
+  i3_was_move = is_just_move (i3);
+
   /* Record whether I2DEST is used in I2SRC and similarly for the other
      cases.  Knowing this will help in register status updating below.  */
   i2dest_in_i2src = reg_overlap_mentioned_p (i2dest, i2src);
@@ -3165,6 +3063,26 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       return 0;
     }
 
+  /* We cannot safely duplicate volatile references in any case.  */
+
+  if ((added_sets_2 && volatile_refs_p (PATTERN (i2)))
+      || (added_sets_1 && volatile_refs_p (PATTERN (i1)))
+      || (added_sets_0 && volatile_refs_p (PATTERN (i0))))
+    {
+      undo_all ();
+      return 0;
+    }
+
+  /* Count how many auto_inc expressions there were in the original insns;
+     we need to have the same number in the resulting patterns.  */
+
+  if (i0)
+    for_each_inc_dec (PATTERN (i0), count_auto_inc, &n_auto_inc);
+  if (i1)
+    for_each_inc_dec (PATTERN (i1), count_auto_inc, &n_auto_inc);
+  for_each_inc_dec (PATTERN (i2), count_auto_inc, &n_auto_inc);
+  for_each_inc_dec (PATTERN (i3), count_auto_inc, &n_auto_inc);
+
   /* 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
@@ -3204,7 +3122,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
 
   subst_insn = i3;
 
-  /* Many machines that don't use CC0 have insns that can both perform an
+  /* Many machines have insns that can both perform an
      arithmetic operation and set the condition code.  These operations will
      be represented as a PARALLEL with the first element of the vector
      being a COMPARE of an arithmetic operation with the constant zero.
@@ -3215,7 +3133,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
      needed, and make the PARALLEL by just replacing I2DEST in I3SRC with
      I2SRC.  Later we will make the PARALLEL that contains I2.  */
 
-  if (!HAVE_cc0 && i1 == 0 && added_sets_2 && GET_CODE (PATTERN (i3)) == SET
+  if (i1 == 0 && added_sets_2 && GET_CODE (PATTERN (i3)) == SET
       && GET_CODE (SET_SRC (PATTERN (i3))) == COMPARE
       && CONST_INT_P (XEXP (SET_SRC (PATTERN (i3)), 1))
       && rtx_equal_p (XEXP (SET_SRC (PATTERN (i3)), 0), i2dest))
@@ -3279,7 +3197,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
                {
                  /* Replace cc_use_loc with entire new RTX.  */
                  SUBST (*cc_use_loc,
-                        gen_rtx_fmt_ee (compare_code, compare_mode,
+                        gen_rtx_fmt_ee (compare_code, GET_MODE (*cc_use_loc),
                                         newpat_dest, const0_rtx));
                  undobuf.other_insn = cc_use_insn;
                }
@@ -3288,7 +3206,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
                  /* Just replace the CC reg with a new mode.  */
                  SUBST (XEXP (*cc_use_loc, 0), newpat_dest);
                  undobuf.other_insn = cc_use_insn;
-               }             
+               }
            }
 
          /* Now we modify the current newpat:
@@ -3366,18 +3284,11 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
 
   if (i1 && GET_CODE (newpat) != CLOBBER)
     {
-      /* Check that an autoincrement side-effect on I1 has not been lost.
-        This happens if I1DEST is mentioned in I2 and dies there, and
-        has disappeared from the new pattern.  */
-      if ((FIND_REG_INC_NOTE (i1, NULL_RTX) != 0
-          && 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 I1DEST isn't
-             mentioned in any SETs in NEWPAT that are field assignments.  */
-         || !combinable_i3pat (NULL, &newpat, i1dest, NULL_RTX, NULL_RTX,
-                               0, 0, 0))
+      /* 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.  */
+      if (!combinable_i3pat (NULL, &newpat, i1dest, NULL_RTX, NULL_RTX,
+                            0, 0, 0))
        {
          undo_all ();
          return 0;
@@ -3407,12 +3318,8 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
 
   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, &newpat, i0dest, NULL_RTX, NULL_RTX,
-                               0, 0, 0))
+      if (!combinable_i3pat (NULL, &newpat, i0dest, NULL_RTX, NULL_RTX,
+                            0, 0, 0))
        {
          undo_all ();
          return 0;
@@ -3433,6 +3340,20 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       substed_i0 = 1;
     }
 
+  if (n_auto_inc)
+    {
+      int new_n_auto_inc = 0;
+      for_each_inc_dec (newpat, count_auto_inc, &new_n_auto_inc);
+
+      if (n_auto_inc != new_n_auto_inc)
+       {
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           fprintf (dump_file, "Number of auto_inc expressions changed\n");
+         undo_all ();
+         return 0;
+       }
+    }
+
   /* Fail if an autoincrement side-effect has been duplicated.  Be careful
      to count all the ways that I2SRC and I1SRC can be used.  */
   if ((FIND_REG_INC_NOTE (i2, NULL_RTX) != 0
@@ -3752,7 +3673,6 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
         are set between I2 and I3.  */
       if (insn_code_number < 0
           && (split = find_split_point (&newpat, i3, false)) != 0
-         && (!HAVE_cc0 || REG_P (i2dest))
          /* We need I2DEST in the proper mode.  If it is a hard register
             or the only use of a pseudo, we can change its mode.
             Make sure we don't change a hard register to have a mode that
@@ -3939,7 +3859,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
      eliminate the copy.
 
      We cannot do this if the destination of the first assignment is a
-     condition code register or cc0.  We eliminate this case by making sure
+     condition code register.  We eliminate this case by making sure
      the SET_DEST and SET_SRC have the same mode.
 
      We cannot do this if the destination of the second assignment is
@@ -3962,16 +3882,20 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
           && ! (temp_expr = SET_DEST (XVECEXP (newpat, 0, 1)),
                 (REG_P (temp_expr)
                  && reg_stat[REGNO (temp_expr)].nonzero_bits != 0
-                 && GET_MODE_PRECISION (GET_MODE (temp_expr)) < BITS_PER_WORD
-                 && GET_MODE_PRECISION (GET_MODE (temp_expr)) < HOST_BITS_PER_INT
+                 && known_lt (GET_MODE_PRECISION (GET_MODE (temp_expr)),
+                              BITS_PER_WORD)
+                 && known_lt (GET_MODE_PRECISION (GET_MODE (temp_expr)),
+                              HOST_BITS_PER_INT)
                  && (reg_stat[REGNO (temp_expr)].nonzero_bits
                      != GET_MODE_MASK (word_mode))))
           && ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG
                 && (temp_expr = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))),
                     (REG_P (temp_expr)
                      && reg_stat[REGNO (temp_expr)].nonzero_bits != 0
-                     && GET_MODE_PRECISION (GET_MODE (temp_expr)) < BITS_PER_WORD
-                     && GET_MODE_PRECISION (GET_MODE (temp_expr)) < HOST_BITS_PER_INT
+                     && known_lt (GET_MODE_PRECISION (GET_MODE (temp_expr)),
+                                  BITS_PER_WORD)
+                     && known_lt (GET_MODE_PRECISION (GET_MODE (temp_expr)),
+                                  HOST_BITS_PER_INT)
                      && (reg_stat[REGNO (temp_expr)].nonzero_bits
                          != GET_MODE_MASK (word_mode)))))
           && ! reg_overlap_mentioned_p (SET_DEST (XVECEXP (newpat, 0, 1)),
@@ -4001,15 +3925,20 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
      other insns to combine, but the destination of that SET is still live.
 
      Also do this if we started with two insns and (at least) one of the
-     resulting sets is a noop; this noop will be deleted later.  */
+     resulting sets is a noop; this noop will be deleted later.
+
+     Also do this if we started with two insns neither of which was a simple
+     move.  */
 
   else if (insn_code_number < 0 && asm_noperands (newpat) < 0
           && GET_CODE (newpat) == PARALLEL
           && XVECLEN (newpat, 0) == 2
           && GET_CODE (XVECEXP (newpat, 0, 0)) == SET
           && GET_CODE (XVECEXP (newpat, 0, 1)) == SET
-          && (i1 || set_noop_p (XVECEXP (newpat, 0, 0))
-                 || set_noop_p (XVECEXP (newpat, 0, 1)))
+          && (i1
+              || set_noop_p (XVECEXP (newpat, 0, 0))
+              || set_noop_p (XVECEXP (newpat, 0, 1))
+              || (!i2_was_move && !i3_was_move))
           && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != ZERO_EXTRACT
           && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 0))) != STRICT_LOW_PART
           && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != ZERO_EXTRACT
@@ -4024,19 +3953,19 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       rtx set0 = XVECEXP (newpat, 0, 0);
       rtx set1 = XVECEXP (newpat, 0, 1);
 
-      /* Normally, it doesn't matter which of the two is done first,
-        but the one that references cc0 can't be the second, and
+      /* Normally, it doesn't matter which of the two is done first, but
         one which uses any regs/memory set in between i2 and i3 can't
         be first.  The PARALLEL might also have been pre-existing in i3,
         so we need to make sure that we won't wrongly hoist a SET to i2
-        that would conflict with a death note present in there.  */
+        that would conflict with a death note present in there, or would
+        have its dest modified between i2 and i3.  */
       if (!modified_between_p (SET_SRC (set1), i2, i3)
          && !(REG_P (SET_DEST (set1))
               && find_reg_note (i2, REG_DEAD, SET_DEST (set1)))
          && !(GET_CODE (SET_DEST (set1)) == SUBREG
               && find_reg_note (i2, REG_DEAD,
                                 SUBREG_REG (SET_DEST (set1))))
-         && (!HAVE_cc0 || !reg_referenced_p (cc0_rtx, set0))
+         && !modified_between_p (SET_DEST (set1), i2, i3)
          /* If I3 is a jump, ensure that set0 is a jump so that
             we do not create invalid RTL.  */
          && (!JUMP_P (i3) || SET_DEST (set0) == pc_rtx)
@@ -4051,7 +3980,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
               && !(GET_CODE (SET_DEST (set0)) == SUBREG
                    && find_reg_note (i2, REG_DEAD,
                                      SUBREG_REG (SET_DEST (set0))))
-              && (!HAVE_cc0 || !reg_referenced_p (cc0_rtx, set1))
+              && !modified_between_p (SET_DEST (set0), i2, i3)
               /* If I3 is a jump, ensure that set1 is a jump so that
                  we do not create invalid RTL.  */
               && (!JUMP_P (i3) || SET_DEST (set1) == pc_rtx)
@@ -4087,6 +4016,9 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
            }
 
          insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+
+         if (insn_code_number >= 0)
+           split_i2i3 = 1;
        }
     }
 
@@ -4116,19 +4048,6 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
        }
     }
 
-  /* If I2 is the CC0 setter and I3 is the CC0 user then check whether
-     they are adjacent to each other or not.  */
-  if (HAVE_cc0)
-    {
-      rtx_insn *p = prev_nonnote_insn (i3);
-      if (p && p != i2 && NONJUMP_INSN_P (p) && newi2pat
-         && sets_cc0_p (newi2pat))
-       {
-         undo_all ();
-         return 0;
-       }
-    }
-
   /* Only allow this combination if insn_cost reports that the
      replacement instructions are cheaper than the originals.  */
   if (!combine_validate_cost (i0, i1, i2, i3, newpat, newi2pat, other_pat))
@@ -4254,43 +4173,49 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
 
   if (swap_i2i3)
     {
-      rtx_insn *insn;
-      struct insn_link *link;
-      rtx ni2dest;
-
       /* I3 now uses what used to be its destination and which is now
         I2's destination.  This requires us to do a few adjustments.  */
       PATTERN (i3) = newpat;
       adjust_for_new_dest (i3);
+    }
 
-      /* We need a LOG_LINK from I3 to I2.  But we used to have one,
-        so we still will.
+  if (swap_i2i3 || split_i2i3)
+    {
+      /* We might need a LOG_LINK from I3 to I2.  But then we used to
+        have one, so we still will.
 
         However, some later insn might be using I2's dest and have
-        a LOG_LINK pointing at I3.  We must remove this link.
-        The simplest way to remove the link is to point it at I1,
-        which we know will be a NOTE.  */
+        a LOG_LINK pointing at I3.  We should change it to point at
+        I2 instead.  */
 
       /* newi2pat is usually a SET here; however, recog_for_combine might
         have added some clobbers.  */
-      if (GET_CODE (newi2pat) == PARALLEL)
-       ni2dest = SET_DEST (XVECEXP (newi2pat, 0, 0));
-      else
-       ni2dest = SET_DEST (newi2pat);
+      rtx x = newi2pat;
+      if (GET_CODE (x) == PARALLEL)
+       x = XVECEXP (newi2pat, 0, 0);
 
-      for (insn = NEXT_INSN (i3);
-          insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR_FOR_FN (cfun)
-                   || insn != BB_HEAD (this_basic_block->next_bb));
-          insn = NEXT_INSN (insn))
+      if (REG_P (SET_DEST (x))
+         || (GET_CODE (SET_DEST (x)) == SUBREG
+             && REG_P (SUBREG_REG (SET_DEST (x)))))
        {
-         if (NONDEBUG_INSN_P (insn)
-             && reg_referenced_p (ni2dest, PATTERN (insn)))
+         unsigned int regno = reg_or_subregno (SET_DEST (x));
+
+         bool done = false;
+         for (rtx_insn *insn = NEXT_INSN (i3);
+              !done
+              && insn
+              && NONDEBUG_INSN_P (insn)
+              && BLOCK_FOR_INSN (insn) == this_basic_block;
+              insn = NEXT_INSN (insn))
            {
+             struct insn_link *link;
              FOR_EACH_LOG_LINK (link, insn)
-               if (link->insn == i3)
-                 link->insn = i1;
-
-             break;
+               if (link->insn == i3 && link->regno == regno)
+                 {
+                   link->insn = i2;
+                   done = true;
+                   break;
+                 }
            }
        }
     }
@@ -4655,8 +4580,8 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
        been made to this insn.  The order is important, because newi2pat
        can affect nonzero_bits of newpat.  */
     if (newi2pat)
-      note_stores (newi2pat, set_nonzero_bits_and_sign_copies, NULL);
-    note_stores (newpat, set_nonzero_bits_and_sign_copies, NULL);
+      note_pattern_stores (newi2pat, set_nonzero_bits_and_sign_copies, NULL);
+    note_pattern_stores (newpat, set_nonzero_bits_and_sign_copies, NULL);
   }
 
   if (undobuf.other_insn != NULL_RTX)
@@ -4897,7 +4822,7 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src)
        }
 
       /* If we have a PLUS whose second operand is a constant and the
-        address is not valid, perhaps will can split it up using
+        address is not valid, perhaps we can split it up using
         the machine-specific way to split large constants.  We use
         the first pseudo-reg (one of the virtual regs) as a placeholder;
         it will not remain in the result.  */
@@ -4912,7 +4837,7 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src)
 
          /* This should have produced two insns, each of which sets our
             placeholder.  If the source of the second is a valid address,
-            we can make put both sources together and make a split point
+            we can put both sources together and make a split point
             in the middle.  */
 
          if (seq
@@ -4953,14 +4878,51 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src)
                }
            }
 
+         /* If that didn't work and we have a nested plus, like:
+            ((REG1 * CONST1) + REG2) + CONST2 and (REG1 + REG2) + CONST2
+            is valid address, try to split (REG1 * CONST1).  */
+         if (GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS
+             && !OBJECT_P (XEXP (XEXP (XEXP (x, 0), 0), 0))
+             && OBJECT_P (XEXP (XEXP (XEXP (x, 0), 0), 1))
+             && ! (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SUBREG
+                   && OBJECT_P (SUBREG_REG (XEXP (XEXP (XEXP (x, 0),
+                                                        0), 0)))))
+           {
+             rtx tem = XEXP (XEXP (XEXP (x, 0), 0), 0);
+             XEXP (XEXP (XEXP (x, 0), 0), 0) = reg;
+             if (memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
+                                              MEM_ADDR_SPACE (x)))
+               {
+                 XEXP (XEXP (XEXP (x, 0), 0), 0) = tem;
+                 return &XEXP (XEXP (XEXP (x, 0), 0), 0);
+               }
+             XEXP (XEXP (XEXP (x, 0), 0), 0) = tem;
+           }
+         else if (GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS
+                  && OBJECT_P (XEXP (XEXP (XEXP (x, 0), 0), 0))
+                  && !OBJECT_P (XEXP (XEXP (XEXP (x, 0), 0), 1))
+                  && ! (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == SUBREG
+                        && OBJECT_P (SUBREG_REG (XEXP (XEXP (XEXP (x, 0),
+                                                             0), 1)))))
+           {
+             rtx tem = XEXP (XEXP (XEXP (x, 0), 0), 1);
+             XEXP (XEXP (XEXP (x, 0), 0), 1) = reg;
+             if (memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
+                                              MEM_ADDR_SPACE (x)))
+               {
+                 XEXP (XEXP (XEXP (x, 0), 0), 1) = tem;
+                 return &XEXP (XEXP (XEXP (x, 0), 0), 1);
+               }
+             XEXP (XEXP (XEXP (x, 0), 0), 1) = tem;
+           }
+
          /* If that didn't work, perhaps the first operand is complex and
             needs to be computed separately, so make a split point there.
             This will occur on machines that just support REG + CONST
             and have a constant moved through some previous computation.  */
-
-         else if (!OBJECT_P (XEXP (XEXP (x, 0), 0))
-                  && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
-                        && OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
+         if (!OBJECT_P (XEXP (XEXP (x, 0), 0))
+             && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
+                   && OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
            return &XEXP (XEXP (x, 0), 0);
        }
 
@@ -4976,19 +4938,6 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src)
       break;
 
     case SET:
-      /* If SET_DEST is CC0 and SET_SRC is not an operand, a COMPARE, or a
-        ZERO_EXTRACT, the most likely reason why this doesn't match is that
-        we need to put the operand into a register.  So split at that
-        point.  */
-
-      if (SET_DEST (x) == cc0_rtx
-         && GET_CODE (SET_SRC (x)) != COMPARE
-         && GET_CODE (SET_SRC (x)) != ZERO_EXTRACT
-         && !OBJECT_P (SET_SRC (x))
-         && ! (GET_CODE (SET_SRC (x)) == SUBREG
-               && OBJECT_P (SUBREG_REG (SET_SRC (x)))))
-       return &SET_SRC (x);
-
       /* See if we can split SET_SRC as it stands.  */
       split = find_split_point (&SET_SRC (x), insn, true);
       if (split && split != &SET_SRC (x))
@@ -5015,10 +4964,9 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src)
        {
          HOST_WIDE_INT pos = INTVAL (XEXP (SET_DEST (x), 2));
          unsigned HOST_WIDE_INT len = INTVAL (XEXP (SET_DEST (x), 1));
-         unsigned HOST_WIDE_INT src = INTVAL (SET_SRC (x));
          rtx dest = XEXP (SET_DEST (x), 0);
-         unsigned HOST_WIDE_INT mask
-           = (HOST_WIDE_INT_1U << len) - 1;
+         unsigned HOST_WIDE_INT mask = (HOST_WIDE_INT_1U << len) - 1;
+         unsigned HOST_WIDE_INT src = INTVAL (SET_SRC (x)) & mask;
          rtx or_mask;
 
          if (BITS_BIG_ENDIAN)
@@ -5140,8 +5088,9 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src)
          break;
        }
 
-      if (len && pos >= 0
-         && pos + len <= GET_MODE_PRECISION (GET_MODE (inner))
+      if (len
+         && known_subrange_p (pos, len,
+                              0, GET_MODE_PRECISION (GET_MODE (inner)))
          && is_a <scalar_int_mode> (GET_MODE (SET_SRC (x)), &mode))
        {
          /* For unsigned, we have a choice of a shift followed by an
@@ -5400,9 +5349,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
        {
          rtx dest = SET_DEST (XVECEXP (x, 0, i));
 
-         if (!REG_P (dest)
-             && GET_CODE (dest) != CC0
-             && GET_CODE (dest) != PC)
+         if (!REG_P (dest) && GET_CODE (dest) != PC)
            {
              new_rtx = subst (dest, from, to, 0, 0, unique_copy);
 
@@ -5420,13 +5367,12 @@ subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
       len = GET_RTX_LENGTH (code);
       fmt = GET_RTX_FORMAT (code);
 
-      /* We don't need to process a SET_DEST that is a register, CC0,
-        or PC, so set up to skip this common case.  All other cases
-        where we want to suppress replacing something inside a
-        SET_SRC are handled via the IN_DEST operand.  */
+      /* We don't need to process a SET_DEST that is a register or PC, so
+        set up to skip this common case.  All other cases where we want
+        to suppress replacing something inside a SET_SRC are handled via
+        the IN_DEST operand.  */
       if (code == SET
          && (REG_P (SET_DEST (x))
-             || GET_CODE (SET_DEST (x)) == CC0
              || GET_CODE (SET_DEST (x)) == PC))
        fmt = "ie";
 
@@ -5496,22 +5442,17 @@ subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
                     from in the outside mode, and that may be invalid
                     if it is an fp reg copied in integer mode.
 
-                    We allow two exceptions to this: It is valid if
+                    We allow an exception to this: It is valid if
                     it is inside another SUBREG and the mode of that
                     SUBREG and the mode of the inside of TO is
-                    tieable and it is valid if X is a SET that copies
-                    FROM to CC0.  */
+                    tieable.  */
 
                  if (GET_CODE (to) == SUBREG
                      && !targetm.modes_tieable_p (GET_MODE (to),
                                                   GET_MODE (SUBREG_REG (to)))
                      && ! (code == SUBREG
                            && (targetm.modes_tieable_p
-                               (GET_MODE (x), GET_MODE (SUBREG_REG (to)))))
-                     && (!HAVE_cc0
-                         || (! (code == SET
-                                && i == 1
-                                && XEXP (x, 0) == cc0_rtx))))
+                               (GET_MODE (x), GET_MODE (SUBREG_REG (to))))))
                    return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
 
                  if (code == SUBREG
@@ -5563,11 +5504,16 @@ subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
                    x = gen_rtx_CLOBBER (mode, const0_rtx);
                }
              else if (CONST_SCALAR_INT_P (new_rtx)
-                      && GET_CODE (x) == ZERO_EXTEND)
+                      && (GET_CODE (x) == ZERO_EXTEND
+                          || GET_CODE (x) == SIGN_EXTEND
+                          || GET_CODE (x) == FLOAT
+                          || GET_CODE (x) == UNSIGNED_FLOAT))
                {
-                 x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
-                                               new_rtx, GET_MODE (XEXP (x, 0)));
-                 gcc_assert (x);
+                 x = simplify_unary_operation (GET_CODE (x), GET_MODE (x),
+                                               new_rtx,
+                                               GET_MODE (XEXP (x, 0)));
+                 if (!x)
+                   return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
                }
              else
                SUBST (XEXP (x, i), new_rtx);
@@ -5719,7 +5665,11 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest,
          /* If everything is a comparison, what we have is highly unlikely
             to be simpler, so don't use it.  */
          && ! (COMPARISON_P (x)
-               && (COMPARISON_P (true_rtx) || COMPARISON_P (false_rtx))))
+               && (COMPARISON_P (true_rtx) || COMPARISON_P (false_rtx)))
+         /* Similarly, if we end up with one of the expressions the same
+            as the original, it is certainly not simpler.  */
+         && ! rtx_equal_p (x, true_rtx)
+         && ! rtx_equal_p (x, false_rtx))
        {
          rtx cop1 = const0_rtx;
          enum rtx_code cond_code = simplify_comparison (NE, &cond, &cop1);
@@ -5777,14 +5727,6 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest,
                                                                 mode, VOIDmode,
                                                                 cond, cop1),
                                        mode);
-             else
-               return gen_rtx_IF_THEN_ELSE (mode,
-                                            simplify_gen_relational (cond_code,
-                                                                     mode,
-                                                                     VOIDmode,
-                                                                     cond,
-                                                                     cop1),
-                                            true_rtx, false_rtx);
 
              code = GET_CODE (x);
              op0_mode = VOIDmode;
@@ -5884,8 +5826,9 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest,
            && known_eq (subreg_lowpart_offset (int_mode, int_op0_mode),
                         SUBREG_BYTE (x))
            && HWI_COMPUTABLE_MODE_P (int_op0_mode)
-           && (nonzero_bits (SUBREG_REG (x), int_op0_mode)
-               & GET_MODE_MASK (int_mode)) == 0)
+           && ((nonzero_bits (SUBREG_REG (x), int_op0_mode)
+                & GET_MODE_MASK (int_mode)) == 0)
+           && !side_effects_p (SUBREG_REG (x)))
          return CONST0_RTX (int_mode);
       }
 
@@ -5958,8 +5901,11 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest,
                              GET_MODE_MASK (mode), 0));
 
       /* We can truncate a constant value and return it.  */
-      if (CONST_INT_P (XEXP (x, 0)))
-       return gen_int_mode (INTVAL (XEXP (x, 0)), mode);
+      {
+       poly_int64 c;
+       if (poly_int_rtx_p (XEXP (x, 0), &c))
+         return gen_int_mode (c, mode);
+      }
 
       /* Similarly to what we do in simplify-rtx.c, a truncate of a register
         whose value is a comparison can be replaced with a subreg if
@@ -5967,7 +5913,8 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest,
       if (HWI_COMPUTABLE_MODE_P (mode)
          && (STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0
          && (temp = get_last_value (XEXP (x, 0)))
-         && COMPARISON_P (temp))
+         && COMPARISON_P (temp)
+         && TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (XEXP (x, 0))))
        return gen_lowpart (mode, XEXP (x, 0));
       break;
 
@@ -6007,8 +5954,9 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest,
               && (UINTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))
                   == (HOST_WIDE_INT_1U << (i + 1)) - 1))
              || (GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND
-                 && (GET_MODE_PRECISION (GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)))
-                     == (unsigned int) i + 1))))
+                 && known_eq ((GET_MODE_PRECISION
+                               (GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)))),
+                              (unsigned int) i + 1))))
        return simplify_shift_const
          (NULL_RTX, ASHIFTRT, int_mode,
           simplify_shift_const (NULL_RTX, ASHIFT, int_mode,
@@ -6128,8 +6076,7 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest,
       /* If the first operand is a condition code, we can't do anything
         with it.  */
       if (GET_CODE (XEXP (x, 0)) == COMPARE
-         || (GET_MODE_CLASS (GET_MODE (XEXP (x, 0))) != MODE_CC
-             && ! CC0_P (XEXP (x, 0))))
+         || GET_MODE_CLASS (GET_MODE (XEXP (x, 0))) != MODE_CC)
        {
          rtx op0 = XEXP (x, 0);
          rtx op1 = XEXP (x, 1);
@@ -6341,6 +6288,19 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest,
                              - 1,
                              0));
       break;
+    case VEC_SELECT:
+      {
+       rtx trueop0 = XEXP (x, 0);
+       mode = GET_MODE (trueop0);
+       rtx trueop1 = XEXP (x, 1);
+       /* If we select a low-part subreg, return that.  */
+       if (vec_series_lowpart_p (GET_MODE (x), mode, trueop1))
+         {
+           rtx new_rtx = lowpart_subreg (GET_MODE (x), trueop0, mode);
+           if (new_rtx != NULL_RTX)
+             return new_rtx;
+         }
+      }
 
     default:
       break;
@@ -6434,7 +6394,7 @@ simplify_if_then_else (rtx x)
                          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),
+                                      from, false_val),
                           pc_rtx, pc_rtx, 0, 0, 0);
 
       SUBST (XEXP (x, 1), swapped ? false_rtx : true_rtx);
@@ -6463,7 +6423,6 @@ simplify_if_then_else (rtx x)
          || reg_mentioned_p (true_rtx, false_rtx)
          || rtx_equal_p (false_rtx, XEXP (cond, 0))))
     {
-      true_code = reversed_comparison_code (cond, NULL);
       SUBST (XEXP (x, 0), reversed_comparison (cond, GET_MODE (cond)));
       SUBST (XEXP (x, 1), false_rtx);
       SUBST (XEXP (x, 2), true_rtx);
@@ -6519,7 +6478,10 @@ simplify_if_then_else (rtx x)
 
   /* Look for MIN or MAX.  */
 
-  if ((! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations)
+  if ((! FLOAT_MODE_P (mode)
+       || (flag_unsafe_math_optimizations
+          && !HONOR_NANS (mode)
+          && !HONOR_SIGNED_ZEROS (mode)))
       && comparison_p
       && rtx_equal_p (XEXP (cond, 0), true_rtx)
       && rtx_equal_p (XEXP (cond, 1), false_rtx)
@@ -6740,12 +6702,9 @@ simplify_set (rtx x)
       SUBST (SET_SRC (x), src);
     }
 
-  /* If we are setting CC0 or if the source is a COMPARE, look for the use of
-     the comparison result and try to simplify it unless we already have used
-     undobuf.other_insn.  */
-  if ((GET_MODE_CLASS (mode) == MODE_CC
-       || GET_CODE (src) == COMPARE
-       || CC0_P (dest))
+  /* If the source is a COMPARE, look for the use of the comparison result
+     and try to simplify it unless we already have used undobuf.other_insn.  */
+  if ((GET_MODE_CLASS (mode) == MODE_CC || GET_CODE (src) == COMPARE)
       && (cc_use = find_single_use (dest, subst_insn, &other_insn)) != 0
       && (undobuf.other_insn == 0 || other_insn == undobuf.other_insn)
       && COMPARISON_P (*cc_use)
@@ -6822,7 +6781,7 @@ simplify_set (rtx x)
         a hard register, just build new versions with the proper mode.  If it
         is a pseudo, we lose unless it is only time we set the pseudo, in
         which case we can safely change its mode.  */
-      if (!HAVE_cc0 && compare_mode != GET_MODE (dest))
+      if (compare_mode != GET_MODE (dest))
        {
          if (can_change_dest_mode (dest, 0, compare_mode))
            {
@@ -6925,10 +6884,10 @@ simplify_set (rtx x)
 
   if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
       && !OBJECT_P (SUBREG_REG (src))
-      && (((GET_MODE_SIZE (GET_MODE (src)) + (UNITS_PER_WORD - 1))
-          / UNITS_PER_WORD)
-         == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
-              + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))
+      && (known_equal_after_align_up
+         (GET_MODE_SIZE (GET_MODE (src)),
+          GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))),
+          UNITS_PER_WORD))
       && (WORD_REGISTER_OPERATIONS || !paradoxical_subreg_p (src))
       && ! (REG_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER
            && !REG_CAN_CHANGE_MODE_P (REGNO (dest),
@@ -6946,24 +6905,6 @@ simplify_set (rtx x)
       src = SET_SRC (x), dest = SET_DEST (x);
     }
 
-  /* If we have (set (cc0) (subreg ...)), we try to remove the subreg
-     in SRC.  */
-  if (dest == cc0_rtx
-      && partial_subreg_p (src)
-      && subreg_lowpart_p (src))
-    {
-      rtx inner = SUBREG_REG (src);
-      machine_mode inner_mode = GET_MODE (inner);
-
-      /* Here we make sure that we don't have a sign bit on.  */
-      if (val_signbit_known_clear_p (GET_MODE (src),
-                                    nonzero_bits (inner, inner_mode)))
-       {
-         SUBST (SET_SRC (x), inner);
-         src = SET_SRC (x);
-       }
-    }
-
   /* If we have (set FOO (subreg:M (mem:N BAR) 0)) with M wider than N, this
      would require a paradoxical subreg.  Replace the subreg with a
      zero_extend to avoid the reload that would otherwise be required.
@@ -7316,11 +7257,15 @@ expand_compound_operation (rtx x)
                                  mode, tem, modewidth - len);
     }
   else if (unsignedp && len < HOST_BITS_PER_WIDE_INT)
-    tem = simplify_and_const_int (NULL_RTX, mode,
-                                 simplify_shift_const (NULL_RTX, LSHIFTRT,
-                                                       mode, XEXP (x, 0),
-                                                       pos),
-                                 (HOST_WIDE_INT_1U << len) - 1);
+    {
+      tem = simplify_shift_const (NULL_RTX, LSHIFTRT, inner_mode,
+                                 XEXP (x, 0), pos);
+      tem = gen_lowpart (mode, tem);
+      if (!tem || GET_CODE (tem) == CLOBBER)
+       return x;
+      tem = simplify_and_const_int (NULL_RTX, mode, tem,
+                                   (HOST_WIDE_INT_1U << len) - 1);
+    }
   else
     /* Any other cases we can't handle.  */
     return x;
@@ -7346,7 +7291,7 @@ expand_field_assignment (const_rtx x)
 {
   rtx inner;
   rtx pos;                     /* Always counts from low bit.  */
-  int len;
+  int len, inner_len;
   rtx mask, cleared, masked;
   scalar_int_mode compute_mode;
 
@@ -7356,8 +7301,10 @@ expand_field_assignment (const_rtx x)
       if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART
          && GET_CODE (XEXP (SET_DEST (x), 0)) == SUBREG)
        {
+         rtx x0 = XEXP (SET_DEST (x), 0);
+         if (!GET_MODE_PRECISION (GET_MODE (x0)).is_constant (&len))
+           break;
          inner = SUBREG_REG (XEXP (SET_DEST (x), 0));
-         len = GET_MODE_PRECISION (GET_MODE (XEXP (SET_DEST (x), 0)));
          pos = gen_int_mode (subreg_lsb (XEXP (SET_DEST (x), 0)),
                              MAX_MODE_INT);
        }
@@ -7365,33 +7312,30 @@ expand_field_assignment (const_rtx x)
               && CONST_INT_P (XEXP (SET_DEST (x), 1)))
        {
          inner = XEXP (SET_DEST (x), 0);
+         if (!GET_MODE_PRECISION (GET_MODE (inner)).is_constant (&inner_len))
+           break;
+
          len = INTVAL (XEXP (SET_DEST (x), 1));
          pos = XEXP (SET_DEST (x), 2);
 
          /* A constant position should stay within the width of INNER.  */
-         if (CONST_INT_P (pos)
-             && INTVAL (pos) + len > GET_MODE_PRECISION (GET_MODE (inner)))
+         if (CONST_INT_P (pos) && INTVAL (pos) + len > inner_len)
            break;
 
          if (BITS_BIG_ENDIAN)
            {
              if (CONST_INT_P (pos))
-               pos = GEN_INT (GET_MODE_PRECISION (GET_MODE (inner)) - len
-                              - INTVAL (pos));
+               pos = GEN_INT (inner_len - len - INTVAL (pos));
              else if (GET_CODE (pos) == MINUS
                       && CONST_INT_P (XEXP (pos, 1))
-                      && (INTVAL (XEXP (pos, 1))
-                          == GET_MODE_PRECISION (GET_MODE (inner)) - len))
+                      && INTVAL (XEXP (pos, 1)) == inner_len - len)
                /* If position is ADJUST - X, new position is X.  */
                pos = XEXP (pos, 0);
              else
-               {
-                 HOST_WIDE_INT prec = GET_MODE_PRECISION (GET_MODE (inner));
-                 pos = simplify_gen_binary (MINUS, GET_MODE (pos),
-                                            gen_int_mode (prec - len,
-                                                          GET_MODE (pos)),
-                                            pos);
-               }
+               pos = simplify_gen_binary (MINUS, GET_MODE (pos),
+                                          gen_int_mode (inner_len - len,
+                                                        GET_MODE (pos)),
+                                          pos);
            }
        }
 
@@ -7511,7 +7455,7 @@ make_extraction (machine_mode mode, rtx inner, HOST_WIDE_INT pos,
             bits outside of is_mode, don't look through
             non-paradoxical SUBREGs.  See PR82192.  */
          || (pos_rtx == NULL_RTX
-             && pos + len <= GET_MODE_PRECISION (is_mode))))
+             && known_le (pos + len, GET_MODE_PRECISION (is_mode)))))
     {
       /* If going from (subreg:SI (mem:QI ...)) to (mem:QI ...),
         consider just the QI as the memory to extract from.
@@ -7537,12 +7481,30 @@ make_extraction (machine_mode mode, rtx inner, HOST_WIDE_INT pos,
       if (new_rtx != 0)
        return gen_rtx_ASHIFT (mode, new_rtx, XEXP (inner, 1));
     }
+  else if (GET_CODE (inner) == MULT
+          && CONST_INT_P (XEXP (inner, 1))
+          && pos_rtx == 0 && pos == 0)
+    {
+      /* We're extracting the least significant bits of an rtx
+        (mult X (const_int 2^C)), where LEN > C.  Extract the
+        least significant (LEN - C) bits of X, giving an rtx
+        whose mode is MODE, then multiply it by 2^C.  */
+      const HOST_WIDE_INT shift_amt = exact_log2 (INTVAL (XEXP (inner, 1)));
+      if (IN_RANGE (shift_amt, 1, len - 1))
+       {
+         new_rtx = make_extraction (mode, XEXP (inner, 0),
+                                    0, 0, len - shift_amt,
+                                    unsignedp, in_dest, in_compare);
+         if (new_rtx)
+           return gen_rtx_MULT (mode, new_rtx, XEXP (inner, 1));
+       }
+    }
   else if (GET_CODE (inner) == TRUNCATE
           /* If trying or potentionally trying to extract
              bits outside of is_mode, don't look through
              TRUNCATE.  See PR82192.  */
           && pos_rtx == NULL_RTX
-          && pos + len <= GET_MODE_PRECISION (is_mode))
+          && known_le (pos + len, GET_MODE_PRECISION (is_mode)))
     inner = XEXP (inner, 0);
 
   inner_mode = GET_MODE (inner);
@@ -7575,6 +7537,7 @@ make_extraction (machine_mode mode, rtx inner, HOST_WIDE_INT pos,
              /* We can't do this if we are widening INNER_MODE (it
                 may not be aligned, for one thing).  */
              && !paradoxical_subreg_p (tmode, inner_mode)
+             && known_le (pos + len, GET_MODE_PRECISION (is_mode))
              && (inner_mode == tmode
                  || (! mode_dependent_address_p (XEXP (inner, 0),
                                                  MEM_ADDR_SPACE (inner))
@@ -7589,11 +7552,12 @@ make_extraction (machine_mode mode, rtx inner, HOST_WIDE_INT pos,
 
       if (MEM_P (inner))
        {
-         HOST_WIDE_INT offset;
+         poly_int64 offset;
 
          /* POS counts from lsb, but make OFFSET count in memory order.  */
          if (BYTES_BIG_ENDIAN)
-           offset = (GET_MODE_PRECISION (is_mode) - len - pos) / BITS_PER_UNIT;
+           offset = bits_to_bytes_round_down (GET_MODE_PRECISION (is_mode)
+                                              - len - pos);
          else
            offset = pos / BITS_PER_UNIT;
 
@@ -7685,7 +7649,7 @@ make_extraction (machine_mode mode, rtx inner, HOST_WIDE_INT pos,
      other cases, we would only be going outside our object in cases when
      an original shift would have been undefined.  */
   if (MEM_P (inner)
-      && ((pos_rtx == 0 && pos + len > GET_MODE_PRECISION (is_mode))
+      && ((pos_rtx == 0 && maybe_gt (pos + len, GET_MODE_PRECISION (is_mode)))
          || (pos_rtx != 0 && len != 1)))
     return 0;
 
@@ -7700,9 +7664,10 @@ make_extraction (machine_mode mode, rtx inner, HOST_WIDE_INT pos,
      For memory, assume that the desired extraction_mode and pos_mode
      are the same as for a register operation, since at present we don't
      have named patterns for aligned memory structures.  */
-  struct extraction_insn insn;
-  if (get_best_reg_extraction_insn (&insn, pattern,
-                                   GET_MODE_BITSIZE (inner_mode), mode))
+  class extraction_insn insn;
+  unsigned int inner_size;
+  if (GET_MODE_BITSIZE (inner_mode).is_constant (&inner_size)
+      && get_best_reg_extraction_insn (&insn, pattern, inner_size, mode))
     {
       wanted_inner_reg_mode = insn.struct_mode.require ();
       pos_mode = insn.pos_mode;
@@ -7715,6 +7680,10 @@ make_extraction (machine_mode mode, rtx inner, HOST_WIDE_INT pos,
       && partial_subreg_p (extraction_mode, mode))
     extraction_mode = mode;
 
+  /* Punt if len is too large for extraction_mode.  */
+  if (maybe_gt (len, GET_MODE_PRECISION (extraction_mode)))
+    return NULL_RTX;
+
   if (!MEM_P (inner))
     wanted_inner_mode = wanted_inner_reg_mode;
   else
@@ -7738,9 +7707,11 @@ make_extraction (machine_mode mode, rtx inner, HOST_WIDE_INT pos,
         If it's a MEM we need to recompute POS relative to that.
         However, if we're extracting from (or inserting into) a register,
         we want to recompute POS relative to wanted_inner_mode.  */
-      int width = (MEM_P (inner)
-                  ? GET_MODE_BITSIZE (is_mode)
-                  : GET_MODE_BITSIZE (wanted_inner_mode));
+      int width;
+      if (!MEM_P (inner))
+       width = GET_MODE_BITSIZE (wanted_inner_mode);
+      else if (!GET_MODE_BITSIZE (is_mode).is_constant (&width))
+       return NULL_RTX;
 
       if (pos_rtx == 0)
        pos = width - len - pos;
@@ -7764,7 +7735,7 @@ make_extraction (machine_mode mode, rtx inner, HOST_WIDE_INT pos,
       && ! mode_dependent_address_p (XEXP (inner, 0), MEM_ADDR_SPACE (inner))
       && ! MEM_VOLATILE_P (inner))
     {
-      int offset = 0;
+      poly_int64 offset = 0;
 
       /* The computations below will be correct if the machine is big
         endian in both bits and bytes or little endian in bits and bytes.
@@ -8164,8 +8135,10 @@ make_compound_operation_int (scalar_int_mode mode, rtx *x_ptr,
 
          sub = XEXP (XEXP (x, 0), 0);
          machine_mode sub_mode = GET_MODE (sub);
+         int sub_width;
          if ((REG_P (sub) || MEM_P (sub))
-             && GET_MODE_PRECISION (sub_mode) < mode_width)
+             && GET_MODE_PRECISION (sub_mode).is_constant (&sub_width)
+             && sub_width < mode_width)
            {
              unsigned HOST_WIDE_INT mode_mask = GET_MODE_MASK (sub_mode);
              unsigned HOST_WIDE_INT mask;
@@ -8175,8 +8148,7 @@ make_compound_operation_int (scalar_int_mode mode, rtx *x_ptr,
              if ((mask & mode_mask) == mode_mask)
                {
                  new_rtx = make_compound_operation (sub, next_code);
-                 new_rtx = make_extraction (mode, new_rtx, 0, 0,
-                                            GET_MODE_PRECISION (sub_mode),
+                 new_rtx = make_extraction (mode, new_rtx, 0, 0, sub_width,
                                             1, 0, in_code == COMPARE);
                }
            }
@@ -8675,6 +8647,7 @@ force_int_to_mode (rtx x, scalar_int_mode mode, scalar_int_mode xmode,
   int next_select = just_select || code == XOR || code == NOT || code == NEG;
   unsigned HOST_WIDE_INT fuller_mask;
   rtx op0, op1, temp;
+  poly_int64 const_op0;
 
   /* When we have an arithmetic operation, or a shift whose count we
      do not know, we need to assume that all bits up to the highest-order
@@ -8798,8 +8771,8 @@ force_int_to_mode (rtx x, scalar_int_mode mode, scalar_int_mode xmode,
     case MINUS:
       /* If X is (minus C Y) where C's least set bit is larger than any bit
         in the mask, then we may replace with (neg Y).  */
-      if (CONST_INT_P (XEXP (x, 0))
-         && least_bit_hwi (UINTVAL (XEXP (x, 0))) > mask)
+      if (poly_int_rtx_p (XEXP (x, 0), &const_op0)
+         && known_alignment (poly_uint64 (const_op0)) > mask)
        {
          x = simplify_gen_unary (NEG, xmode, XEXP (x, 1), xmode);
          return force_to_mode (x, mode, mask, next_select);
@@ -8898,7 +8871,7 @@ force_int_to_mode (rtx x, scalar_int_mode mode, scalar_int_mode xmode,
        mask = fuller_mask;
 
       op0 = gen_lowpart_or_truncate (op_mode,
-                                    force_to_mode (XEXP (x, 0), op_mode,
+                                    force_to_mode (XEXP (x, 0), mode,
                                                    mask, next_select));
 
       if (op_mode != xmode || op0 != XEXP (x, 0))
@@ -9269,6 +9242,7 @@ if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
 
          if (COMPARISON_P (cond0)
              && COMPARISON_P (cond1)
+             && SCALAR_INT_MODE_P (mode)
              && ((GET_CODE (cond0) == reversed_comparison_code (cond1, NULL)
                   && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
                   && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
@@ -9449,12 +9423,12 @@ known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val)
          if (COMPARISON_P (x))
            {
              if (comparison_dominates_p (cond, code))
-               return const_true_rtx;
+               return VECTOR_MODE_P (GET_MODE (x)) ? x : const_true_rtx;
 
              code = reversed_comparison_code (x, NULL);
              if (code != UNKNOWN
                  && comparison_dominates_p (cond, code))
-               return const0_rtx;
+               return CONST0_RTX (GET_MODE (x));
              else
                return x;
            }
@@ -9497,7 +9471,7 @@ known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val)
          /* We must simplify subreg here, before we lose track of the
             original inner_mode.  */
          new_rtx = simplify_subreg (GET_MODE (x), r,
-                                inner_mode, SUBREG_BYTE (x));
+                                    inner_mode, SUBREG_BYTE (x));
          if (new_rtx)
            return new_rtx;
          else
@@ -9522,7 +9496,7 @@ known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val)
          /* We must simplify the zero_extend here, before we lose
             track of the original inner_mode.  */
          new_rtx = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
-                                         r, inner_mode);
+                                             r, inner_mode);
          if (new_rtx)
            return new_rtx;
          else
@@ -10031,7 +10005,7 @@ simplify_and_const_int_1 (scalar_int_mode mode, rtx varop,
   constop &= nonzero;
 
   /* If we don't have any bits left, return zero.  */
-  if (constop == 0)
+  if (constop == 0 && !side_effects_p (varop))
     return const0_rtx;
 
   /* If VAROP is a NEG of something known to be zero or 1 and CONSTOP is
@@ -10120,6 +10094,7 @@ simplify_and_const_int (rtx x, scalar_int_mode mode, rtx varop,
 \f
 /* Given a REG X of mode XMODE, compute which bits in X can be nonzero.
    We don't care about bits outside of those defined in MODE.
+   We DO care about all the bits in MODE, even if XMODE is smaller than MODE.
 
    For most X this is simply GET_MODE_MASK (GET_MODE (MODE)), but if X is
    a shift, AND, or zero_extract, we can do better.  */
@@ -10140,7 +10115,8 @@ reg_nonzero_bits_for_combine (const_rtx x, scalar_int_mode xmode,
   rsp = &reg_stat[REGNO (x)];
   if (rsp->last_set_value != 0
       && (rsp->last_set_mode == mode
-         || (GET_MODE_CLASS (rsp->last_set_mode) == MODE_INT
+         || (REGNO (x) >= FIRST_PSEUDO_REGISTER
+             && GET_MODE_CLASS (rsp->last_set_mode) == MODE_INT
              && GET_MODE_CLASS (mode) == MODE_INT))
       && ((rsp->last_set_label >= label_tick_ebb_start
           && rsp->last_set_label < label_tick)
@@ -10459,8 +10435,6 @@ simplify_shift_const_1 (enum rtx_code code, machine_mode result_mode,
   machine_mode mode = result_mode;
   machine_mode shift_mode;
   scalar_int_mode tmode, inner_mode, int_mode, int_varop_mode, int_result_mode;
-  unsigned int mode_words
-    = (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
   /* We form (outer_op (code varop count) (outer_const)).  */
   enum rtx_code outer_op = UNKNOWN;
   HOST_WIDE_INT outer_const = 0;
@@ -10641,9 +10615,8 @@ simplify_shift_const_1 (enum rtx_code code, machine_mode result_mode,
          if (subreg_lowpart_p (varop)
              && is_int_mode (GET_MODE (SUBREG_REG (varop)), &inner_mode)
              && GET_MODE_SIZE (inner_mode) > GET_MODE_SIZE (int_varop_mode)
-             && (unsigned int) ((GET_MODE_SIZE (inner_mode)
-                                 + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
-                == mode_words
+             && (CEIL (GET_MODE_SIZE (inner_mode), UNITS_PER_WORD)
+                 == CEIL (GET_MODE_SIZE (int_mode), UNITS_PER_WORD))
              && GET_MODE_CLASS (int_varop_mode) == MODE_INT)
            {
              varop = SUBREG_REG (varop);
@@ -10864,8 +10837,11 @@ simplify_shift_const_1 (enum rtx_code code, machine_mode result_mode,
                break;
              /* For ((int) (cstLL >> count)) >> cst2 just give up.  Queuing
                 up outer sign extension (often left and right shift) is
-                hardly more efficient than the original.  See PR70429.  */
-             if (code == ASHIFTRT && int_mode != int_result_mode)
+                hardly more efficient than the original.  See PR70429.
+                Similarly punt for rotates with different modes.
+                See PR97386.  */
+             if ((code == ASHIFTRT || code == ROTATE)
+                 && int_mode != int_result_mode)
                break;
 
              rtx count_rtx = gen_int_shift_amount (int_result_mode, count);
@@ -11473,8 +11449,15 @@ change_zero_ext (rtx pat)
                                  gen_int_shift_amount (inner_mode, start));
          else
            x = XEXP (x, 0);
+
          if (mode != inner_mode)
-           x = gen_lowpart_SUBREG (mode, x);
+           {
+             if (REG_P (x) && HARD_REGISTER_P (x)
+                 && !can_change_dest_mode (x, 0, mode))
+               continue;
+
+             x = gen_lowpart_SUBREG (mode, x);
+           }
        }
       else if (GET_CODE (x) == ZERO_EXTEND
               && GET_CODE (XEXP (x, 0)) == SUBREG
@@ -11486,7 +11469,13 @@ change_zero_ext (rtx pat)
          size = GET_MODE_PRECISION (inner_mode);
          x = SUBREG_REG (XEXP (x, 0));
          if (GET_MODE (x) != mode)
-           x = gen_lowpart_SUBREG (mode, x);
+           {
+             if (REG_P (x) && HARD_REGISTER_P (x)
+                 && !can_change_dest_mode (x, 0, mode))
+               continue;
+
+             x = gen_lowpart_SUBREG (mode, x);
+           }
        }
       else if (GET_CODE (x) == ZERO_EXTEND
               && REG_P (XEXP (x, 0))
@@ -11615,8 +11604,6 @@ static rtx
 gen_lowpart_for_combine (machine_mode omode, rtx x)
 {
   machine_mode imode = GET_MODE (x);
-  unsigned int osize = GET_MODE_SIZE (omode);
-  unsigned int isize = GET_MODE_SIZE (imode);
   rtx result;
 
   if (omode == imode)
@@ -11624,8 +11611,9 @@ gen_lowpart_for_combine (machine_mode omode, rtx x)
 
   /* We can only support MODE being wider than a word if X is a
      constant integer or has a mode the same size.  */
-  if (GET_MODE_SIZE (omode) > UNITS_PER_WORD
-      && ! (CONST_SCALAR_INT_P (x) || isize == osize))
+  if (maybe_gt (GET_MODE_SIZE (omode), UNITS_PER_WORD)
+      && ! (CONST_SCALAR_INT_P (x)
+           || known_eq (GET_MODE_SIZE (imode), GET_MODE_SIZE (omode))))
     goto fail;
 
   /* X might be a paradoxical (subreg (mem)).  In that case, gen_lowpart
@@ -11642,8 +11630,6 @@ gen_lowpart_for_combine (machine_mode omode, rtx x)
 
       if (imode == omode)
        return x;
-
-      isize = GET_MODE_SIZE (imode);
     }
 
   result = gen_lowpart_common (omode, x);
@@ -11671,7 +11657,9 @@ gen_lowpart_for_combine (machine_mode omode, rtx x)
 
   /* If X is a comparison operator, rewrite it in a new mode.  This
      probably won't match, but may allow further simplifications.  */
-  else if (COMPARISON_P (x))
+  else if (COMPARISON_P (x)
+          && SCALAR_INT_MODE_P (imode)
+          && SCALAR_INT_MODE_P (omode))
     return gen_rtx_fmt_ee (GET_CODE (x), omode, XEXP (x, 0), XEXP (x, 1));
 
   /* If we couldn't simplify X any other way, just enclose it in a
@@ -12110,7 +12098,6 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
          /* We can't do anything if OP0 is a condition code value, rather
             than an actual data value.  */
          if (const_op != 0
-             || CC0_P (XEXP (op0, 0))
              || GET_MODE_CLASS (GET_MODE (XEXP (op0, 0))) == MODE_CC)
            break;
 
@@ -12267,7 +12254,8 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
             bit.  This will be converted into a ZERO_EXTRACT.  */
          if (const_op == 0 && sign_bit_comparison_p
              && CONST_INT_P (XEXP (op0, 1))
-             && mode_width <= HOST_BITS_PER_WIDE_INT)
+             && mode_width <= HOST_BITS_PER_WIDE_INT
+             && UINTVAL (XEXP (op0, 1)) < mode_width)
            {
              op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0),
                                            (HOST_WIDE_INT_1U
@@ -13140,7 +13128,7 @@ record_value_for_reg (rtx reg, rtx_insn *insn, rtx value)
            {
              /* If there are two or more occurrences of REG in VALUE,
                 prevent the value from growing too much.  */
-             if (count_rtxs (tem) > MAX_LAST_VALUE_RTL)
+             if (count_rtxs (tem) > param_max_last_value_rtl)
                tem = gen_rtx_CLOBBER (GET_MODE (tem), const0_rtx);
            }
 
@@ -13241,18 +13229,26 @@ record_dead_and_set_regs_1 (rtx dest, const_rtx setter, void *data)
   if (REG_P (dest))
     {
       /* If we are setting the whole register, we know its value.  Otherwise
-        show that we don't know the value.  We can handle SUBREG in
-        some cases.  */
+        show that we don't know the value.  We can handle a SUBREG if it's
+        the low part, but we must be careful with paradoxical SUBREGs on
+        RISC architectures because we cannot strip e.g. an extension around
+        a load and record the naked load since the RTL middle-end considers
+        that the upper bits are defined according to LOAD_EXTEND_OP.  */
       if (GET_CODE (setter) == SET && dest == SET_DEST (setter))
        record_value_for_reg (dest, record_dead_insn, SET_SRC (setter));
       else if (GET_CODE (setter) == SET
               && GET_CODE (SET_DEST (setter)) == SUBREG
               && SUBREG_REG (SET_DEST (setter)) == dest
-              && GET_MODE_PRECISION (GET_MODE (dest)) <= BITS_PER_WORD
+              && known_le (GET_MODE_PRECISION (GET_MODE (dest)),
+                           BITS_PER_WORD)
               && subreg_lowpart_p (SET_DEST (setter)))
        record_value_for_reg (dest, record_dead_insn,
-                             gen_lowpart (GET_MODE (dest),
-                                                      SET_SRC (setter)));
+                             WORD_REGISTER_OPERATIONS
+                             && word_register_operation_p (SET_SRC (setter))
+                             && paradoxical_subreg_p (SET_DEST (setter))
+                             ? SET_SRC (setter)
+                             : gen_lowpart (GET_MODE (dest),
+                                            SET_SRC (setter)));
       else
        record_value_for_reg (dest, record_dead_insn, NULL_RTX);
     }
@@ -13300,11 +13296,21 @@ record_dead_and_set_regs (rtx_insn *insn)
 
   if (CALL_P (insn))
     {
+      HARD_REG_SET callee_clobbers
+       = insn_callee_abi (insn).full_and_partial_reg_clobbers ();
       hard_reg_set_iterator hrsi;
-      EXECUTE_IF_SET_IN_HARD_REG_SET (regs_invalidated_by_call, 0, i, hrsi)
+      EXECUTE_IF_SET_IN_HARD_REG_SET (callee_clobbers, 0, i, hrsi)
        {
          reg_stat_type *rsp;
 
+         /* ??? We could try to preserve some information from the last
+            set of register I if the call doesn't actually clobber
+            (reg:last_set_mode I), which might be true for ABIs with
+            partial clobbers.  However, it would be difficult to
+            update last_set_nonzero_bits and last_sign_bit_copies
+            to account for the part of I that actually was clobbered.
+            It wouldn't help much anyway, since we rarely see this
+            situation before RA.  */
          rsp = &reg_stat[i];
          rsp->last_set_invalid = 1;
          rsp->last_set = insn;
@@ -13322,10 +13328,10 @@ record_dead_and_set_regs (rtx_insn *insn)
         the return value register is set at this LUID.  We could
         still replace a register with the return value from the
         wrong subroutine call!  */
-      note_stores (PATTERN (insn), record_dead_and_set_regs_1, NULL_RTX);
+      note_stores (insn, record_dead_and_set_regs_1, NULL_RTX);
     }
   else
-    note_stores (PATTERN (insn), record_dead_and_set_regs_1, insn);
+    note_stores (insn, record_dead_and_set_regs_1, insn);
 }
 
 /* If a SUBREG has the promoted bit set, it is in fact a property of the
@@ -13650,8 +13656,8 @@ get_last_value (const_rtx x)
 
   /* If fewer bits were set than what we are asked for now, we cannot use
      the value.  */
-  if (GET_MODE_PRECISION (rsp->last_set_mode)
-      < GET_MODE_PRECISION (GET_MODE (x)))
+  if (maybe_lt (GET_MODE_PRECISION (rsp->last_set_mode),
+               GET_MODE_PRECISION (GET_MODE (x))))
     return 0;
 
   /* If the value has all its registers valid, return it.  */
@@ -13673,6 +13679,7 @@ get_last_value (const_rtx x)
 
 static unsigned int reg_dead_regno, reg_dead_endregno;
 static int reg_dead_flag;
+rtx reg_dead_reg;
 
 /* Function called via note_stores from reg_dead_at_p.
 
@@ -13710,6 +13717,7 @@ reg_dead_at_p (rtx reg, rtx_insn *insn)
   /* Set variables for reg_dead_at_p_1.  */
   reg_dead_regno = REGNO (reg);
   reg_dead_endregno = END_REGNO (reg);
+  reg_dead_reg = reg;
 
   reg_dead_flag = 0;
 
@@ -13733,7 +13741,7 @@ reg_dead_at_p (rtx reg, rtx_insn *insn)
          if (find_regno_note (insn, REG_UNUSED, reg_dead_regno))
            return 1;
 
-         note_stores (PATTERN (insn), reg_dead_at_p_1, NULL);
+         note_stores (insn, reg_dead_at_p_1, NULL);
          if (reg_dead_flag)
            return reg_dead_flag == 1 ? 1 : 0;
 
@@ -13774,9 +13782,6 @@ mark_used_regs_combine (rtx x)
     case ADDR_VEC:
     case ADDR_DIFF_VEC:
     case ASM_INPUT:
-    /* CC0 must die in the insn after it is set, so we don't need to take
-       special note of it here.  */
-    case CC0:
       return;
 
     case CLOBBER:
@@ -13889,7 +13894,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_luid, rtx_insn *to_insn,
         FROM_LUID and TO_INSN.  If so, find it.  This is PR83304.  */
       if (!where_dead || DF_INSN_LUID (where_dead) >= DF_INSN_LUID (to_insn))
        {
-         rtx_insn *insn = prev_real_insn (to_insn);
+         rtx_insn *insn = prev_real_nondebug_insn (to_insn);
          while (insn
                 && BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (to_insn)
                 && DF_INSN_LUID (insn) >= from_luid)
@@ -13901,7 +13906,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_luid, rtx_insn *to_insn,
                  break;
                }
 
-             insn = prev_real_insn (insn);
+             insn = prev_real_nondebug_insn (insn);
            }
        }
 
@@ -14176,6 +14181,7 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
        case REG_SETJMP:
        case REG_TM:
        case REG_CALL_DECL:
+       case REG_UNTYPED_CALL:
        case REG_CALL_NOCF_CHECK:
          /* These notes must remain with the call.  It should not be
             possible for both I2 and I3 to be a call.  */
@@ -14204,6 +14210,11 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
             we keep notes from i2 or i1 if they will turn into REG_DEAD
             notes.  */
 
+         /* If this register is set or clobbered between FROM_INSN and I3,
+            we should not create a note for it.  */
+         if (reg_set_between_p (XEXP (note, 0), from_insn, i3))
+           break;
+
          /* If this register is set or clobbered in I3, put the note there
             unless there is one already.  */
          if (reg_set_p (XEXP (note, 0), PATTERN (i3)))
@@ -14448,7 +14459,6 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
                    {
                      rtx set = single_set (tem_insn);
                      rtx inner_dest = 0;
-                     rtx_insn *cc0_setter = NULL;
 
                      if (set != 0)
                        for (inner_dest = SET_DEST (set);
@@ -14461,17 +14471,12 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
                      /* Verify that it was the set, and not a clobber that
                         modified the register.
 
-                        CC0 targets must be careful to maintain setter/user
-                        pairs.  If we cannot delete the setter due to side
+                        If we cannot delete the setter due to side
                         effects, mark the user with an UNUSED note instead
                         of deleting it.  */
 
                      if (set != 0 && ! side_effects_p (SET_SRC (set))
-                         && rtx_equal_p (XEXP (note, 0), inner_dest)
-                         && (!HAVE_cc0
-                             || (! reg_mentioned_p (cc0_rtx, SET_SRC (set))
-                                 || ((cc0_setter = prev_cc0_setter (tem_insn)) != NULL
-                                     && sets_cc0_p (PATTERN (cc0_setter)) > 0))))
+                         && rtx_equal_p (XEXP (note, 0), inner_dest))
                        {
                          /* Move the notes and links of TEM_INSN elsewhere.
                             This might delete other dead insns recursively.
@@ -14494,23 +14499,6 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
                          SET_INSN_DELETED (tem_insn);
                          if (tem_insn == i2)
                            i2 = NULL;
-
-                         /* Delete the setter too.  */
-                         if (cc0_setter)
-                           {
-                             PATTERN (cc0_setter) = pc_rtx;
-                             old_notes = REG_NOTES (cc0_setter);
-                             REG_NOTES (cc0_setter) = NULL;
-
-                             distribute_notes (old_notes, cc0_setter,
-                                               cc0_setter, NULL,
-                                               NULL_RTX, NULL_RTX, NULL_RTX);
-                             distribute_links (LOG_LINKS (cc0_setter));
-
-                             SET_INSN_DELETED (cc0_setter);
-                             if (cc0_setter == i2)
-                               i2 = NULL;
-                           }
                        }
                      else
                        {
@@ -14743,6 +14731,9 @@ distribute_links (struct insn_link *links)
             || GET_CODE (reg) == SUBREG)
        reg = XEXP (reg, 0);
 
+      if (reg == pc_rtx)
+       continue;
+
       /* A LOG_LINK is defined as being placed on the first insn that uses
         a register and points to the insn that sets the register.  Start
         searching at the next insn after the target of the link and stop
@@ -14835,11 +14826,52 @@ dump_combine_total_stats (FILE *file)
      total_attempts, total_merges, total_extras, total_successes);
 }
 \f
+/* Make pseudo-to-pseudo copies after every hard-reg-to-pseudo-copy, because
+   the reg-to-reg copy can usefully combine with later instructions, but we
+   do not want to combine the hard reg into later instructions, for that
+   restricts register allocation.  */
+static void
+make_more_copies (void)
+{
+  basic_block bb;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      rtx_insn *insn;
+
+      FOR_BB_INSNS (bb, insn)
+        {
+          if (!NONDEBUG_INSN_P (insn))
+            continue;
+
+         rtx set = single_set (insn);
+         if (!set)
+           continue;
+
+         rtx dest = SET_DEST (set);
+         if (!(REG_P (dest) && !HARD_REGISTER_P (dest)))
+             continue;
+
+         rtx src = SET_SRC (set);
+         if (!(REG_P (src) && HARD_REGISTER_P (src)))
+           continue;
+         if (TEST_HARD_REG_BIT (fixed_reg_set, REGNO (src)))
+           continue;
+
+         rtx new_reg = gen_reg_rtx (GET_MODE (dest));
+         rtx_insn *new_insn = gen_move_insn (new_reg, src);
+         SET_SRC (set) = new_reg;
+         emit_insn_before (new_insn, insn);
+         df_insn_rescan (insn);
+       }
+    }
+}
+
 /* Try combining insns through substitution.  */
 static unsigned int
 rest_of_handle_combine (void)
 {
-  int rebuild_jump_labels_after_combine;
+  make_more_copies ();
 
   df_set_flags (DF_LR_RUN_DCE + DF_DEFER_INSN_RESCAN);
   df_note_add_problem ();
@@ -14848,7 +14880,7 @@ rest_of_handle_combine (void)
   regstat_init_n_sets_and_refs ();
   reg_n_sets_max = max_reg_num ();
 
-  rebuild_jump_labels_after_combine
+  int rebuild_jump_labels_after_combine
     = combine_instructions (get_insns (), max_reg_num ());
 
   /* Combining insns may have turned an indirect jump into a