]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/combine.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / combine.c
index d200c5abd07675bd5c27f93047396ff4e0d78f62..892c834a160ad56cc1c5dd3c57199b2390b382a0 100644 (file)
@@ -1,5 +1,5 @@
 /* Optimize by combining instructions for GNU compiler.
-   Copyright (C) 1987-2019 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"
@@ -100,12 +85,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "insn-attr.h"
 #include "rtlhooks-def.h"
 #include "expr.h"
-#include "params.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.  */
 
@@ -545,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.  */
 
@@ -572,16 +557,14 @@ find_single_use_1 (rtx dest, rtx *loc)
     case SYMBOL_REF:
     CASE_CONST_ANY:
     case CLOBBER:
-    case CLOBBER_HIGH:
       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)))
@@ -651,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
@@ -667,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;
 
@@ -1130,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)
@@ -1141,8 +1106,6 @@ 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
@@ -1155,7 +1118,6 @@ 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;
@@ -1174,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 ();
 
@@ -1235,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));
@@ -1252,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)
     {
@@ -1333,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)
@@ -1488,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))
@@ -1601,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).  */
@@ -1763,9 +1663,6 @@ set_nonzero_bits_and_sign_copies (rtx x, const_rtx set, void *data)
          return;
        }
 
-      /* Should not happen as we only using pseduo registers.  */
-      gcc_assert (GET_CODE (set) != CLOBBER_HIGH);
-
       /* If this register is being initialized using itself, and the
         register is uninitialized in this basic block, and there are
         no LOG_LINKS which set the register, then part of the
@@ -1857,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.
@@ -1924,7 +1821,6 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED,
 
              /* We can ignore CLOBBERs.  */
            case CLOBBER:
-           case CLOBBER_HIGH:
              break;
 
            case SET:
@@ -2037,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
@@ -2064,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;
 
 
@@ -2116,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;
@@ -2124,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)))
@@ -2143,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.  */
 
@@ -2463,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
@@ -2535,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
@@ -2595,8 +2439,6 @@ is_parallel_of_n_reg_sets (rtx pat, int n)
        if (XEXP (XVECEXP (pat, 0, i), 0) == const0_rtx)
          return false;
        break;
-      case CLOBBER_HIGH:
-       break;
       default:
        return false;
       }
@@ -2630,15 +2472,16 @@ 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
+/* Return whether X is just a single_set, with the source
    a general_operand.  */
 static bool
-is_just_move (rtx x)
+is_just_move (rtx_insn *x)
 {
-  if (INSN_P (x))
-    x = PATTERN (x);
+  rtx set = single_set (x);
+  if (!set)
+    return false;
 
-  return (GET_CODE (x) == SET && general_operand (SET_SRC (x), VOIDmode));
+  return general_operand (SET_SRC (set), VOIDmode);
 }
 
 /* Callback function to count autoincs.  */
@@ -2897,8 +2740,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       for (i = 0; ok && i < XVECLEN (p2, 0); i++)
        {
          if ((GET_CODE (XVECEXP (p2, 0, i)) == SET
-              || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER
-              || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER_HIGH)
+              || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER)
              && reg_overlap_mentioned_p (SET_DEST (PATTERN (i3)),
                                          SET_DEST (XVECEXP (p2, 0, i))))
            ok = false;
@@ -3030,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)
@@ -3062,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)
@@ -3221,6 +3063,16 @@ 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.  */
 
@@ -3270,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.
@@ -3281,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))
@@ -3821,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
@@ -4008,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
@@ -4102,8 +3953,7 @@ 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
@@ -4116,7 +3966,6 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
               && find_reg_note (i2, REG_DEAD,
                                 SUBREG_REG (SET_DEST (set1))))
          && !modified_between_p (SET_DEST (set1), i2, i3)
-         && (!HAVE_cc0 || !reg_referenced_p (cc0_rtx, set0))
          /* 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)
@@ -4132,7 +3981,6 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
                    && find_reg_note (i2, REG_DEAD,
                                      SUBREG_REG (SET_DEST (set0))))
               && !modified_between_p (SET_DEST (set0), i2, i3)
-              && (!HAVE_cc0 || !reg_referenced_p (cc0_rtx, set1))
               /* 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)
@@ -4200,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))
@@ -4359,25 +4194,29 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       if (GET_CODE (x) == PARALLEL)
        x = XVECEXP (newi2pat, 0, 0);
 
-      /* It can only be a SET of a REG or of a SUBREG of a REG.  */
-      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))
+      if (REG_P (SET_DEST (x))
+         || (GET_CODE (SET_DEST (x)) == SUBREG
+             && REG_P (SUBREG_REG (SET_DEST (x)))))
        {
-         struct insn_link *link;
-         FOR_EACH_LOG_LINK (link, insn)
-           if (link->insn == i3 && link->regno == regno)
-             {
-               link->insn = i2;
-               done = true;
-               break;
-             }
+         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->regno == regno)
+                 {
+                   link->insn = i2;
+                   done = true;
+                   break;
+                 }
+           }
        }
     }
 
@@ -5099,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))
@@ -5138,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)
@@ -5524,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);
 
@@ -5544,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";
 
@@ -5620,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
@@ -5688,6 +5505,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
                }
              else if (CONST_SCALAR_INT_P (new_rtx)
                       && (GET_CODE (x) == ZERO_EXTEND
+                          || GET_CODE (x) == SIGN_EXTEND
                           || GET_CODE (x) == FLOAT
                           || GET_CODE (x) == UNSIGNED_FLOAT))
                {
@@ -6095,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;
 
@@ -6257,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);
@@ -6470,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;
@@ -6647,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)
@@ -6868,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)
@@ -6950,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))
            {
@@ -7074,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.
@@ -7444,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;
@@ -7664,6 +7481,24 @@ 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
@@ -10170,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
@@ -11002,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);
@@ -11819,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
@@ -12258,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;
 
@@ -12415,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
@@ -13288,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);
            }
 
@@ -13409,15 +13249,6 @@ record_dead_and_set_regs_1 (rtx dest, const_rtx setter, void *data)
                              ? SET_SRC (setter)
                              : gen_lowpart (GET_MODE (dest),
                                             SET_SRC (setter)));
-      else if (GET_CODE (setter) == CLOBBER_HIGH)
-       {
-         reg_stat_type *rsp = &reg_stat[REGNO (dest)];
-         if (rsp->last_set_value
-             && reg_is_clobbered_by_clobber_high
-                  (REGNO (dest), GET_MODE (rsp->last_set_value),
-                   XEXP (setter, 0)))
-           record_value_for_reg (dest, NULL, NULL_RTX);
-       }
       else
        record_value_for_reg (dest, record_dead_insn, NULL_RTX);
     }
@@ -13863,10 +13694,6 @@ reg_dead_at_p_1 (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED)
   if (!REG_P (dest))
     return;
 
-  if (GET_CODE (x) == CLOBBER_HIGH
-      && !reg_is_clobbered_by_clobber_high (reg_dead_reg, XEXP (x, 0)))
-    return;
-
   regno = REGNO (dest);
   endregno = END_REGNO (dest);
   if (reg_dead_endregno > regno && reg_dead_regno < endregno)
@@ -13955,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:
@@ -14357,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.  */
@@ -14385,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)))
@@ -14629,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);
@@ -14642,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.
@@ -14675,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
                        {