ipa/97673 - fix input_location leak
[gcc.git] / gcc / rtlanal.c
index 403769efef1bdcb97b9916f70b49414410ad9402..d1240b0b7c5a8ffcc0e505c4ccc078270175bf53 100644 (file)
@@ -1,5 +1,5 @@
 /* Analyze RTL for GNU compiler.
-   Copyright (C) 1987-2016 Free Software Foundation, Inc.
+   Copyright (C) 1987-2021 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "backend.h"
 #include "target.h"
 #include "rtl.h"
+#include "rtlanal.h"
 #include "tree.h"
 #include "predict.h"
 #include "df.h"
@@ -35,6 +36,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "recog.h"
 #include "addresses.h"
 #include "rtl-iter.h"
+#include "hard-reg-set.h"
+#include "function-abi.h"
 
 /* Forward declarations */
 static void set_of_1 (rtx, const_rtx, void *);
@@ -43,17 +46,18 @@ static bool covers_regno_no_parallel_p (const_rtx, unsigned int);
 static int computed_jump_p_1 (const_rtx);
 static void parms_set (rtx, const_rtx, void *);
 
-static unsigned HOST_WIDE_INT cached_nonzero_bits (const_rtx, machine_mode,
+static unsigned HOST_WIDE_INT cached_nonzero_bits (const_rtx, scalar_int_mode,
                                                    const_rtx, machine_mode,
                                                    unsigned HOST_WIDE_INT);
-static unsigned HOST_WIDE_INT nonzero_bits1 (const_rtx, machine_mode,
+static unsigned HOST_WIDE_INT nonzero_bits1 (const_rtx, scalar_int_mode,
                                             const_rtx, machine_mode,
                                              unsigned HOST_WIDE_INT);
-static unsigned int cached_num_sign_bit_copies (const_rtx, machine_mode, const_rtx,
-                                                machine_mode,
+static unsigned int cached_num_sign_bit_copies (const_rtx, scalar_int_mode,
+                                               const_rtx, machine_mode,
                                                 unsigned int);
-static unsigned int num_sign_bit_copies1 (const_rtx, machine_mode, const_rtx,
-                                          machine_mode, unsigned int);
+static unsigned int num_sign_bit_copies1 (const_rtx, scalar_int_mode,
+                                         const_rtx, machine_mode,
+                                         unsigned int);
 
 rtx_subrtx_bound_info rtx_all_subrtx_bounds[NUM_RTX_CODE];
 rtx_subrtx_bound_info rtx_nonconst_subrtx_bounds[NUM_RTX_CODE];
@@ -94,7 +98,7 @@ generic_subrtx_iterator <T>::add_single_to_queue (array_type &array,
       /* A previous iteration might also have moved from the stack to the
         heap, in which case the heap array will already be big enough.  */
       if (vec_safe_length (array.heap) <= i)
-       vec_safe_grow (array.heap, i + 1);
+       vec_safe_grow (array.heap, i + 1, true);
       base = array.heap->address ();
       memcpy (base, array.stack, sizeof (array.stack));
       base[LOCAL_ELEMS] = x;
@@ -343,7 +347,7 @@ rtx_varies_p (const_rtx x, bool for_alias)
    FROM and TO for the current function, as it was at the start
    of the routine.  */
 
-static HOST_WIDE_INT
+static poly_int64
 get_initial_register_offset (int from, int to)
 {
   static const struct elim_table_t
@@ -351,16 +355,16 @@ get_initial_register_offset (int from, int to)
     const int from;
     const int to;
   } table[] = ELIMINABLE_REGS;
-  HOST_WIDE_INT offset1, offset2;
+  poly_int64 offset1, offset2;
   unsigned int i, j;
 
   if (to == from)
     return 0;
 
-  /* It is not safe to call INITIAL_ELIMINATION_OFFSET
-     before the reload pass.  We need to give at least
-     an estimation for the resulting frame size.  */
-  if (! reload_completed)
+  /* It is not safe to call INITIAL_ELIMINATION_OFFSET before the epilogue
+     is completed, but we need to give at least an estimate for the stack
+     pointer based on the frame size.  */
+  if (!epilogue_completed)
     {
       offset1 = crtl->outgoing_args_size + get_frame_size ();
 #if !STACK_GROWS_DOWNWARD
@@ -456,16 +460,18 @@ get_initial_register_offset (int from, int to)
    references on strict alignment machines.  */
 
 static int
-rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT size,
+rtx_addr_can_trap_p_1 (const_rtx x, poly_int64 offset, poly_int64 size,
                       machine_mode mode, bool unaligned_mems)
 {
   enum rtx_code code = GET_CODE (x);
+  gcc_checking_assert (mode == BLKmode || known_size_p (size));
+  poly_int64 const_x1;
 
   /* The offset must be a multiple of the mode size if we are considering
      unaligned memory references on strict alignment machines.  */
-  if (STRICT_ALIGNMENT && unaligned_mems && GET_MODE_SIZE (mode) != 0)
+  if (STRICT_ALIGNMENT && unaligned_mems && mode != BLKmode)
     {
-      HOST_WIDE_INT actual_offset = offset;
+      poly_int64 actual_offset = offset;
 
 #ifdef SPARC_STACK_BOUNDARY_HACK
       /* ??? The SPARC port may claim a STACK_BOUNDARY higher than
@@ -476,7 +482,7 @@ rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT size,
        actual_offset -= STACK_POINTER_OFFSET;
 #endif
 
-      if (actual_offset % GET_MODE_SIZE (mode) != 0)
+      if (!multiple_p (actual_offset, GET_MODE_SIZE (mode)))
        return 1;
     }
 
@@ -485,17 +491,15 @@ rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT size,
     case SYMBOL_REF:
       if (SYMBOL_REF_WEAK (x))
        return 1;
-      if (!CONSTANT_POOL_ADDRESS_P (x))
+      if (!CONSTANT_POOL_ADDRESS_P (x) && !SYMBOL_REF_FUNCTION_P (x))
        {
          tree decl;
-         HOST_WIDE_INT decl_size;
+         poly_int64 decl_size;
 
-         if (offset < 0)
+         if (maybe_lt (offset, 0))
            return 1;
-         if (size == 0)
-           size = GET_MODE_SIZE (mode);
-         if (size == 0)
-           return offset != 0;
+         if (!known_size_p (size))
+           return maybe_ne (offset, 0);
 
          /* If the size of the access or of the symbol is unknown,
             assume the worst.  */
@@ -506,9 +510,10 @@ rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT size,
          if (!decl)
            decl_size = -1;
          else if (DECL_P (decl) && DECL_SIZE_UNIT (decl))
-           decl_size = (tree_fits_shwi_p (DECL_SIZE_UNIT (decl))
-                        ? tree_to_shwi (DECL_SIZE_UNIT (decl))
-                        : -1);
+           {
+             if (!poly_int_tree_p (DECL_SIZE_UNIT (decl), &decl_size))
+               decl_size = -1;
+           }
          else if (TREE_CODE (decl) == STRING_CST)
            decl_size = TREE_STRING_LENGTH (decl);
          else if (TYPE_SIZE_UNIT (TREE_TYPE (decl)))
@@ -516,7 +521,9 @@ rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT size,
          else
            decl_size = -1;
 
-         return (decl_size <= 0 ? offset != 0 : offset + size > decl_size);
+         return (!known_size_p (decl_size) || known_eq (decl_size, 0)
+                 ? maybe_ne (offset, 0)
+                 : !known_subrange_p (offset, size, 0, decl_size));
         }
 
       return 0;
@@ -533,38 +540,35 @@ rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT size,
         || (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM]))
        {
 #ifdef RED_ZONE_SIZE
-         HOST_WIDE_INT red_zone_size = RED_ZONE_SIZE;
+         poly_int64 red_zone_size = RED_ZONE_SIZE;
 #else
-         HOST_WIDE_INT red_zone_size = 0;
+         poly_int64 red_zone_size = 0;
 #endif
-         HOST_WIDE_INT stack_boundary = PREFERRED_STACK_BOUNDARY
-                                        / BITS_PER_UNIT;
-         HOST_WIDE_INT low_bound, high_bound;
+         poly_int64 stack_boundary = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
+         poly_int64 low_bound, high_bound;
 
-         if (size == 0)
-           size = GET_MODE_SIZE (mode);
-         if (size == 0)
+         if (!known_size_p (size))
            return 1;
 
          if (x == frame_pointer_rtx)
            {
              if (FRAME_GROWS_DOWNWARD)
                {
-                 high_bound = STARTING_FRAME_OFFSET;
+                 high_bound = targetm.starting_frame_offset ();
                  low_bound  = high_bound - get_frame_size ();
                }
              else
                {
-                 low_bound  = STARTING_FRAME_OFFSET;
+                 low_bound  = targetm.starting_frame_offset ();
                  high_bound = low_bound + get_frame_size ();
                }
            }
          else if (x == hard_frame_pointer_rtx)
            {
-             HOST_WIDE_INT sp_offset
+             poly_int64 sp_offset
                = get_initial_register_offset (STACK_POINTER_REGNUM,
                                               HARD_FRAME_POINTER_REGNUM);
-             HOST_WIDE_INT ap_offset
+             poly_int64 ap_offset
                = get_initial_register_offset (ARG_POINTER_REGNUM,
                                               HARD_FRAME_POINTER_REGNUM);
 
@@ -588,7 +592,7 @@ rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT size,
            }
          else if (x == stack_pointer_rtx)
            {
-             HOST_WIDE_INT ap_offset
+             poly_int64 ap_offset
                = get_initial_register_offset (ARG_POINTER_REGNUM,
                                               STACK_POINTER_REGNUM);
 
@@ -628,7 +632,8 @@ rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT size,
 #endif
            }
 
-         if (offset >= low_bound && offset <= high_bound - size)
+         if (known_ge (offset, low_bound)
+             && known_le (offset, high_bound - size))
            return 0;
          return 1;
        }
@@ -644,13 +649,16 @@ rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT size,
 
     case PLUS:
       /* An address is assumed not to trap if:
-         - it is the pic register plus a constant.  */
-      if (XEXP (x, 0) == pic_offset_table_rtx && CONSTANT_P (XEXP (x, 1)))
+        - it is the pic register plus a const unspec without offset.  */
+      if (XEXP (x, 0) == pic_offset_table_rtx
+         && GET_CODE (XEXP (x, 1)) == CONST
+         && GET_CODE (XEXP (XEXP (x, 1), 0)) == UNSPEC
+         && known_eq (offset, 0))
        return 0;
 
       /* - or it is an address that can't trap plus a constant integer.  */
-      if (CONST_INT_P (XEXP (x, 1))
-         && !rtx_addr_can_trap_p_1 (XEXP (x, 0), offset + INTVAL (XEXP (x, 1)),
+      if (poly_int_rtx_p (XEXP (x, 1), &const_x1)
+         && !rtx_addr_can_trap_p_1 (XEXP (x, 0), offset + const_x1,
                                     size, mode, unaligned_mems))
        return 0;
 
@@ -682,7 +690,20 @@ rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT size,
 int
 rtx_addr_can_trap_p (const_rtx x)
 {
-  return rtx_addr_can_trap_p_1 (x, 0, 0, VOIDmode, false);
+  return rtx_addr_can_trap_p_1 (x, 0, -1, BLKmode, false);
+}
+
+/* Return true if X contains a MEM subrtx.  */
+
+bool
+contains_mem_rtx_p (rtx x)
+{
+  subrtx_iterator::array_type array;
+  FOR_EACH_SUBRTX (iter, array, x, ALL)
+    if (MEM_P (*iter))
+      return true;
+
+  return false;
 }
 
 /* Return true if X is an address that is known to not be zero.  */
@@ -792,10 +813,9 @@ rtx_addr_varies_p (const_rtx x, bool for_alias)
 /* Return the CALL in X if there is one.  */
 
 rtx
-get_call_rtx_from (rtx x)
+get_call_rtx_from (const rtx_insn *insn)
 {
-  if (INSN_P (x))
-    x = PATTERN (x);
+  rtx x = PATTERN (insn);
   if (GET_CODE (x) == PARALLEL)
     x = XVECEXP (x, 0, 0);
   if (GET_CODE (x) == SET)
@@ -804,6 +824,24 @@ get_call_rtx_from (rtx x)
     return x;
   return NULL_RTX;
 }
+
+/* Get the declaration of the function called by INSN.  */
+
+tree
+get_call_fndecl (const rtx_insn *insn)
+{
+  rtx note, datum;
+
+  note = find_reg_note (insn, REG_CALL_DECL, NULL_RTX);
+  if (note == NULL_RTX)
+    return NULL_TREE;
+
+  datum = XEXP (note, 0);
+  if (datum != NULL_RTX)
+    return SYMBOL_REF_DECL (datum);
+
+  return NULL_TREE;
+}
 \f
 /* Return the value of the integer term in X, if one is apparent;
    otherwise return 0.
@@ -898,6 +936,37 @@ split_const (rtx x, rtx *base_out, rtx *offset_out)
   *base_out = x;
   *offset_out = const0_rtx;
 }
+
+/* Express integer value X as some value Y plus a polynomial offset,
+   where Y is either const0_rtx, X or something within X (as opposed
+   to a new rtx).  Return the Y and store the offset in *OFFSET_OUT.  */
+
+rtx
+strip_offset (rtx x, poly_int64_pod *offset_out)
+{
+  rtx base = const0_rtx;
+  rtx test = x;
+  if (GET_CODE (test) == CONST)
+    test = XEXP (test, 0);
+  if (GET_CODE (test) == PLUS)
+    {
+      base = XEXP (test, 0);
+      test = XEXP (test, 1);
+    }
+  if (poly_int_rtx_p (test, offset_out))
+    return base;
+  *offset_out = 0;
+  return x;
+}
+
+/* Return the argument size in REG_ARGS_SIZE note X.  */
+
+poly_int64
+get_args_size (const_rtx x)
+{
+  gcc_checking_assert (REG_NOTE_KIND (x) == REG_ARGS_SIZE);
+  return rtx_to_poly_int64 (XEXP (x, 0));
+}
 \f
 /* Return the number of places FIND appears within X.  If COUNT_DEST is
    zero, we do not count occurrences inside the destination of a SET.  */
@@ -1107,10 +1176,7 @@ reg_referenced_p (const_rtx x, const_rtx body)
          && !REG_P (SET_DEST (body))
          && ! (GET_CODE (SET_DEST (body)) == SUBREG
                && REG_P (SUBREG_REG (SET_DEST (body)))
-               && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (body))))
-                     + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
-                   == ((GET_MODE_SIZE (GET_MODE (SET_DEST (body)))
-                        + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))
+               && !read_modify_subreg_p (SET_DEST (body)))
          && reg_overlap_mentioned_p (x, SET_DEST (body)))
        return 1;
       return 0;
@@ -1202,12 +1268,30 @@ reg_set_p (const_rtx reg, const_rtx insn)
          || (CALL_P (insn)
              && ((REG_P (reg)
                   && REGNO (reg) < FIRST_PSEUDO_REGISTER
-                  && overlaps_hard_reg_set_p (regs_invalidated_by_call,
-                                              GET_MODE (reg), REGNO (reg)))
+                  && (insn_callee_abi (as_a<const rtx_insn *> (insn))
+                      .clobbers_reg_p (GET_MODE (reg), REGNO (reg))))
                  || MEM_P (reg)
                  || find_reg_fusage (insn, CLOBBER, reg)))))
     return true;
 
+  /* There are no REG_INC notes for SP autoinc.  */
+  if (reg == stack_pointer_rtx && INSN_P (insn))
+    {
+      subrtx_var_iterator::array_type array;
+      FOR_EACH_SUBRTX_VAR (iter, array, PATTERN (insn), NONCONST)
+       {
+         rtx mem = *iter;
+         if (mem
+             && MEM_P (mem)
+             && GET_RTX_CLASS (GET_CODE (XEXP (mem, 0))) == RTX_AUTOINC)
+           {
+             if (XEXP (XEXP (mem, 0), 0) == stack_pointer_rtx)
+               return true;
+             iter.skip_subrtxes ();
+           }
+       }
+    }
+
   return set_of (reg, insn) != NULL_RTX;
 }
 
@@ -1323,6 +1407,25 @@ modified_in_p (const_rtx x, const_rtx insn)
 
   return 0;
 }
+
+/* Return true if X is a SUBREG and if storing a value to X would
+   preserve some of its SUBREG_REG.  For example, on a normal 32-bit
+   target, using a SUBREG to store to one half of a DImode REG would
+   preserve the other half.  */
+
+bool
+read_modify_subreg_p (const_rtx x)
+{
+  if (GET_CODE (x) != SUBREG)
+    return false;
+  poly_uint64 isize = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
+  poly_uint64 osize = GET_MODE_SIZE (GET_MODE (x));
+  poly_uint64 regsize = REGMODE_NATURAL_SIZE (GET_MODE (SUBREG_REG (x)));
+  /* The inner and outer modes of a subreg must be ordered, so that we
+     can tell whether they're paradoxical or partial.  */
+  gcc_checking_assert (ordered_p (isize, osize));
+  return (maybe_gt (isize, osize) && maybe_gt (isize, regsize));
+}
 \f
 /* Helper function for set_of.  */
 struct set_of_data
@@ -1348,10 +1451,45 @@ set_of (const_rtx pat, const_rtx insn)
   struct set_of_data data;
   data.found = NULL_RTX;
   data.pat = pat;
-  note_stores (INSN_P (insn) ? PATTERN (insn) : insn, set_of_1, &data);
+  note_pattern_stores (INSN_P (insn) ? PATTERN (insn) : insn, set_of_1, &data);
   return data.found;
 }
 
+/* Check whether instruction pattern PAT contains a SET with the following
+   properties:
+
+   - the SET is executed unconditionally; and
+   - either:
+     - the destination of the SET is a REG that contains REGNO; or
+     - both:
+       - the destination of the SET is a SUBREG of such a REG; and
+       - writing to the subreg clobbers all of the SUBREG_REG
+        (in other words, read_modify_subreg_p is false).
+
+   If PAT does have a SET like that, return the set, otherwise return null.
+
+   This is intended to be an alternative to single_set for passes that
+   can handle patterns with multiple_sets.  */
+rtx
+simple_regno_set (rtx pat, unsigned int regno)
+{
+  if (GET_CODE (pat) == PARALLEL)
+    {
+      int last = XVECLEN (pat, 0) - 1;
+      for (int i = 0; i < last; ++i)
+       if (rtx set = simple_regno_set (XVECEXP (pat, 0, i), regno))
+         return set;
+
+      pat = XVECEXP (pat, 0, last);
+    }
+
+  if (GET_CODE (pat) == SET
+      && covers_regno_no_parallel_p (SET_DEST (pat), regno))
+    return pat;
+
+  return nullptr;
+}
+
 /* Add all hard register in X to *PSET.  */
 void
 find_all_hard_regs (const_rtx x, HARD_REG_SET *pset)
@@ -1377,22 +1515,20 @@ record_hard_reg_sets (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
 }
 
 /* Examine INSN, and compute the set of hard registers written by it.
-   Store it in *PSET.  Should only be called after reload.  */
+   Store it in *PSET.  Should only be called after reload.
+
+   IMPLICIT is true if we should include registers that are fully-clobbered
+   by calls.  This should be used with caution, since it doesn't include
+   partially-clobbered registers.  */
 void
 find_all_hard_reg_sets (const rtx_insn *insn, HARD_REG_SET *pset, bool implicit)
 {
   rtx link;
 
   CLEAR_HARD_REG_SET (*pset);
-  note_stores (PATTERN (insn), record_hard_reg_sets, pset);
-  if (CALL_P (insn))
-    {
-      if (implicit)
-       IOR_HARD_REG_SET (*pset, call_used_reg_set);
-
-      for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
-       record_hard_reg_sets (XEXP (link, 0), NULL, pset);
-    }
+  note_stores (insn, record_hard_reg_sets, pset);
+  if (CALL_P (insn) && implicit)
+    *pset |= insn_callee_abi (insn).full_reg_clobbers ();
   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
     if (REG_NOTE_KIND (link) == REG_INC)
       record_hard_reg_sets (XEXP (link, 0), NULL, pset);
@@ -1515,10 +1651,14 @@ set_noop_p (const_rtx set)
 
   if (GET_CODE (src) == SUBREG && GET_CODE (dst) == SUBREG)
     {
-      if (SUBREG_BYTE (src) != SUBREG_BYTE (dst))
+      if (maybe_ne (SUBREG_BYTE (src), SUBREG_BYTE (dst)))
        return 0;
       src = SUBREG_REG (src);
       dst = SUBREG_REG (dst);
+      if (GET_MODE (src) != GET_MODE (dst))
+       /* It is hard to tell whether subregs refer to the same bits, so act
+          conservatively and return 0.  */
+       return 0;
     }
 
   /* It is a NOOP if destination overlaps with selected src vector
@@ -1531,15 +1671,22 @@ set_noop_p (const_rtx set)
       int i;
       rtx par = XEXP (src, 1);
       rtx src0 = XEXP (src, 0);
-      int c0 = INTVAL (XVECEXP (par, 0, 0));
-      HOST_WIDE_INT offset = GET_MODE_UNIT_SIZE (GET_MODE (src0)) * c0;
+      poly_int64 c0;
+      if (!poly_int_rtx_p (XVECEXP (par, 0, 0), &c0))
+       return 0;
+      poly_int64 offset = GET_MODE_UNIT_SIZE (GET_MODE (src0)) * c0;
 
       for (i = 1; i < XVECLEN (par, 0); i++)
-       if (INTVAL (XVECEXP (par, 0, i)) != c0 + i)
-         return 0;
+       {
+         poly_int64 c0i;
+         if (!poly_int_rtx_p (XVECEXP (par, 0, i), &c0i)
+             || maybe_ne (c0i, c0 + i))
+           return 0;
+       }
       return
-       simplify_subreg_regno (REGNO (src0), GET_MODE (src0),
-                              offset, GET_MODE (dst)) == (int) REGNO (dst);
+       REG_CAN_CHANGE_MODE_P (REGNO (dst), GET_MODE (src0), GET_MODE (dst))
+       && simplify_subreg_regno (REGNO (src0), GET_MODE (src0),
+                                 offset, GET_MODE (dst)) == (int) REGNO (dst);
     }
 
   return (REG_P (src) && REG_P (dst)
@@ -1557,10 +1704,6 @@ noop_move_p (const rtx_insn *insn)
   if (INSN_CODE (insn) == NOOP_MOVE_INSN_CODE)
     return 1;
 
-  /* Insns carrying these notes are useful later on.  */
-  if (find_reg_note (insn, REG_EQUAL, NULL_RTX))
-    return 0;
-
   /* Check the code to be executed for COND_EXEC.  */
   if (GET_CODE (pat) == COND_EXEC)
     pat = COND_EXEC_CODE (pat);
@@ -1577,8 +1720,7 @@ noop_move_p (const rtx_insn *insn)
        {
          rtx tem = XVECEXP (pat, 0, i);
 
-         if (GET_CODE (tem) == USE
-             || GET_CODE (tem) == CLOBBER)
+         if (GET_CODE (tem) == USE || GET_CODE (tem) == CLOBBER)
            continue;
 
          if (GET_CODE (tem) != SET || ! set_noop_p (tem))
@@ -1711,7 +1853,7 @@ reg_overlap_mentioned_p (const_rtx x, const_rtx in)
 {
   unsigned int regno, endregno;
 
-  /* If either argument is a constant, then modifying X can not
+  /* If either argument is a constant, then modifying X cannot
      affect IN.  Here we look at IN, we can profitably combine
      CONSTANT_P (x) with the switch statement below.  */
   if (CONSTANT_P (in))
@@ -1720,6 +1862,7 @@ reg_overlap_mentioned_p (const_rtx x, const_rtx in)
  recurse:
   switch (GET_CODE (x))
     {
+    case CLOBBER:
     case STRICT_LOW_PART:
     case ZERO_EXTRACT:
     case SIGN_EXTRACT:
@@ -1803,7 +1946,8 @@ reg_overlap_mentioned_p (const_rtx x, const_rtx in)
   the SUBREG will be passed.  */
 
 void
-note_stores (const_rtx x, void (*fun) (rtx, const_rtx, void *), void *data)
+note_pattern_stores (const_rtx x,
+                    void (*fun) (rtx, const_rtx, void *), void *data)
 {
   int i;
 
@@ -1835,7 +1979,22 @@ note_stores (const_rtx x, void (*fun) (rtx, const_rtx, void *), void *data)
 
   else if (GET_CODE (x) == PARALLEL)
     for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
-      note_stores (XVECEXP (x, 0, i), fun, data);
+      note_pattern_stores (XVECEXP (x, 0, i), fun, data);
+}
+
+/* Same, but for an instruction.  If the instruction is a call, include
+   any CLOBBERs in its CALL_INSN_FUNCTION_USAGE.  */
+
+void
+note_stores (const rtx_insn *insn,
+            void (*fun) (rtx, const_rtx, void *), void *data)
+{
+  if (CALL_P (insn))
+    for (rtx link = CALL_INSN_FUNCTION_USAGE (insn);
+        link; link = XEXP (link, 1))
+      if (GET_CODE (XEXP (link, 0)) == CLOBBER)
+       note_pattern_stores (XEXP (link, 0), fun, data);
+  note_pattern_stores (PATTERN (insn), fun, data);
 }
 \f
 /* Like notes_stores, but call FUN for each expression that is being
@@ -1926,6 +2085,287 @@ note_uses (rtx *pbody, void (*fun) (rtx *, void *), void *data)
       return;
     }
 }
+
+/* Try to add a description of REG X to this object, stopping once
+   the REF_END limit has been reached.  FLAGS is a bitmask of
+   rtx_obj_reference flags that describe the context.  */
+
+void
+rtx_properties::try_to_add_reg (const_rtx x, unsigned int flags)
+{
+  if (REG_NREGS (x) != 1)
+    flags |= rtx_obj_flags::IS_MULTIREG;
+  machine_mode mode = GET_MODE (x);
+  unsigned int start_regno = REGNO (x);
+  unsigned int end_regno = END_REGNO (x);
+  for (unsigned int regno = start_regno; regno < end_regno; ++regno)
+    if (ref_iter != ref_end)
+      *ref_iter++ = rtx_obj_reference (regno, flags, mode,
+                                      regno - start_regno);
+}
+
+/* Add a description of destination X to this object.  FLAGS is a bitmask
+   of rtx_obj_reference flags that describe the context.
+
+   This routine accepts all rtxes that can legitimately appear in a
+   SET_DEST.  */
+
+void
+rtx_properties::try_to_add_dest (const_rtx x, unsigned int flags)
+{
+  /* If we have a PARALLEL, SET_DEST is a list of EXPR_LIST expressions,
+     each of whose first operand is a register.  */
+  if (__builtin_expect (GET_CODE (x) == PARALLEL, 0))
+    {
+      for (int i = XVECLEN (x, 0) - 1; i >= 0; --i)
+       if (rtx dest = XEXP (XVECEXP (x, 0, i), 0))
+         try_to_add_dest (dest, flags);
+      return;
+    }
+
+  unsigned int base_flags = flags & rtx_obj_flags::STICKY_FLAGS;
+  flags |= rtx_obj_flags::IS_WRITE;
+  for (;;)
+    if (GET_CODE (x) == ZERO_EXTRACT)
+      {
+       try_to_add_src (XEXP (x, 1), base_flags);
+       try_to_add_src (XEXP (x, 2), base_flags);
+       flags |= rtx_obj_flags::IS_READ;
+       x = XEXP (x, 0);
+      }
+    else if (GET_CODE (x) == STRICT_LOW_PART)
+      {
+       flags |= rtx_obj_flags::IS_READ;
+       x = XEXP (x, 0);
+      }
+    else if (GET_CODE (x) == SUBREG)
+      {
+       flags |= rtx_obj_flags::IN_SUBREG;
+       if (read_modify_subreg_p (x))
+         flags |= rtx_obj_flags::IS_READ;
+       x = SUBREG_REG (x);
+      }
+    else
+      break;
+
+  if (MEM_P (x))
+    {
+      if (ref_iter != ref_end)
+       *ref_iter++ = rtx_obj_reference (MEM_REGNO, flags, GET_MODE (x));
+
+      unsigned int addr_flags = base_flags | rtx_obj_flags::IN_MEM_STORE;
+      if (flags & rtx_obj_flags::IS_READ)
+       addr_flags |= rtx_obj_flags::IN_MEM_LOAD;
+      try_to_add_src (XEXP (x, 0), addr_flags);
+      return;
+    }
+
+  if (__builtin_expect (REG_P (x), 1))
+    {
+      /* We want to keep sp alive everywhere -  by making all
+        writes to sp also use sp. */
+      if (REGNO (x) == STACK_POINTER_REGNUM)
+       flags |= rtx_obj_flags::IS_READ;
+      try_to_add_reg (x, flags);
+      return;
+    }
+}
+
+/* Try to add a description of source X to this object, stopping once
+   the REF_END limit has been reached.  FLAGS is a bitmask of
+   rtx_obj_reference flags that describe the context.
+
+   This routine accepts all rtxes that can legitimately appear in a SET_SRC.  */
+
+void
+rtx_properties::try_to_add_src (const_rtx x, unsigned int flags)
+{
+  unsigned int base_flags = flags & rtx_obj_flags::STICKY_FLAGS;
+  subrtx_iterator::array_type array;
+  FOR_EACH_SUBRTX (iter, array, x, NONCONST)
+    {
+      const_rtx x = *iter;
+      rtx_code code = GET_CODE (x);
+      if (code == REG)
+       try_to_add_reg (x, flags | rtx_obj_flags::IS_READ);
+      else if (code == MEM)
+       {
+         if (MEM_VOLATILE_P (x))
+           has_volatile_refs = true;
+
+         if (!MEM_READONLY_P (x) && ref_iter != ref_end)
+           {
+             auto mem_flags = flags | rtx_obj_flags::IS_READ;
+             *ref_iter++ = rtx_obj_reference (MEM_REGNO, mem_flags,
+                                              GET_MODE (x));
+           }
+
+         try_to_add_src (XEXP (x, 0),
+                         base_flags | rtx_obj_flags::IN_MEM_LOAD);
+         iter.skip_subrtxes ();
+       }
+      else if (code == SUBREG)
+       {
+         try_to_add_src (SUBREG_REG (x), flags | rtx_obj_flags::IN_SUBREG);
+         iter.skip_subrtxes ();
+       }
+      else if (code == UNSPEC_VOLATILE)
+       has_volatile_refs = true;
+      else if (code == ASM_INPUT || code == ASM_OPERANDS)
+       {
+         has_asm = true;
+         if (MEM_VOLATILE_P (x))
+           has_volatile_refs = true;
+       }
+      else if (code == PRE_INC
+              || code == PRE_DEC
+              || code == POST_INC
+              || code == POST_DEC
+              || code == PRE_MODIFY
+              || code == POST_MODIFY)
+       {
+         has_pre_post_modify = true;
+
+         unsigned int addr_flags = (base_flags
+                                    | rtx_obj_flags::IS_PRE_POST_MODIFY
+                                    | rtx_obj_flags::IS_READ);
+         try_to_add_dest (XEXP (x, 0), addr_flags);
+         if (code == PRE_MODIFY || code == POST_MODIFY)
+           iter.substitute (XEXP (XEXP (x, 1), 1));
+         else
+           iter.skip_subrtxes ();
+       }
+      else if (code == CALL)
+       has_call = true;
+    }
+}
+
+/* Try to add a description of instruction pattern PAT to this object,
+   stopping once the REF_END limit has been reached.  */
+
+void
+rtx_properties::try_to_add_pattern (const_rtx pat)
+{
+  switch (GET_CODE (pat))
+    {
+    case COND_EXEC:
+      try_to_add_src (COND_EXEC_TEST (pat));
+      try_to_add_pattern (COND_EXEC_CODE (pat));
+      break;
+
+    case PARALLEL:
+      {
+       int last = XVECLEN (pat, 0) - 1;
+       for (int i = 0; i < last; ++i)
+         try_to_add_pattern (XVECEXP (pat, 0, i));
+       try_to_add_pattern (XVECEXP (pat, 0, last));
+       break;
+      }
+
+    case ASM_OPERANDS:
+      for (int i = 0, len = ASM_OPERANDS_INPUT_LENGTH (pat); i < len; ++i)
+       try_to_add_src (ASM_OPERANDS_INPUT (pat, i));
+      break;
+
+    case CLOBBER:
+      try_to_add_dest (XEXP (pat, 0), rtx_obj_flags::IS_CLOBBER);
+      break;
+
+    case SET:
+      try_to_add_dest (SET_DEST (pat));
+      try_to_add_src (SET_SRC (pat));
+      break;
+
+    default:
+      /* All the other possibilities never store and can use a normal
+        rtx walk.  This includes:
+
+        - USE
+        - TRAP_IF
+        - PREFETCH
+        - UNSPEC
+        - UNSPEC_VOLATILE.  */
+      try_to_add_src (pat);
+      break;
+    }
+}
+
+/* Try to add a description of INSN to this object, stopping once
+   the REF_END limit has been reached.  INCLUDE_NOTES is true if the
+   description should include REG_EQUAL and REG_EQUIV notes; all such
+   references will then be marked with rtx_obj_flags::IN_NOTE.
+
+   For calls, this description includes all accesses in
+   CALL_INSN_FUNCTION_USAGE.  It also include all implicit accesses
+   to global registers by the target function.  However, it does not
+   include clobbers performed by the target function; callers that want
+   this information should instead use the function_abi interface.  */
+
+void
+rtx_properties::try_to_add_insn (const rtx_insn *insn, bool include_notes)
+{
+  if (CALL_P (insn))
+    {
+      /* Adding the global registers first removes a situation in which
+        a fixed-form clobber of register R could come before a real set
+        of register R.  */
+      if (!hard_reg_set_empty_p (global_reg_set))
+       {
+         unsigned int flags = (rtx_obj_flags::IS_READ
+                               | rtx_obj_flags::IS_WRITE);
+         for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
+           if (global_regs[regno] && ref_iter != ref_end)
+             *ref_iter++ = rtx_obj_reference (regno, flags,
+                                              reg_raw_mode[regno], 0);
+       }
+      if (ref_iter != ref_end && !RTL_CONST_CALL_P (insn))
+       {
+         auto mem_flags = rtx_obj_flags::IS_READ;
+         if (!RTL_PURE_CALL_P (insn))
+           mem_flags |= rtx_obj_flags::IS_WRITE;
+         *ref_iter++ = rtx_obj_reference (MEM_REGNO, mem_flags, BLKmode);
+       }
+      try_to_add_pattern (PATTERN (insn));
+      for (rtx link = CALL_INSN_FUNCTION_USAGE (insn); link;
+          link = XEXP (link, 1))
+       {
+         rtx x = XEXP (link, 0);
+         if (GET_CODE (x) == CLOBBER)
+           try_to_add_dest (XEXP (x, 0), rtx_obj_flags::IS_CLOBBER);
+         else if (GET_CODE (x) == USE)
+           try_to_add_src (XEXP (x, 0));
+       }
+    }
+  else
+    try_to_add_pattern (PATTERN (insn));
+
+  if (include_notes)
+    for (rtx note = REG_NOTES (insn); note; note = XEXP (note, 1))
+      if (REG_NOTE_KIND (note) == REG_EQUAL
+         || REG_NOTE_KIND (note) == REG_EQUIV)
+       try_to_add_note (XEXP (note, 0));
+}
+
+/* Grow the storage by a bit while keeping the contents of the first
+   START elements.  */
+
+void
+vec_rtx_properties_base::grow (ptrdiff_t start)
+{
+  /* The same heuristic that vec uses.  */
+  ptrdiff_t new_elems = (ref_end - ref_begin) * 3 / 2;
+  if (ref_begin == m_storage)
+    {
+      ref_begin = XNEWVEC (rtx_obj_reference, new_elems);
+      if (start)
+       memcpy (ref_begin, m_storage, start * sizeof (rtx_obj_reference));
+    }
+  else
+    ref_begin = reinterpret_cast<rtx_obj_reference *>
+      (xrealloc (ref_begin, new_elems * sizeof (rtx_obj_reference)));
+  ref_iter = ref_begin + start;
+  ref_end = ref_begin + new_elems;
+}
 \f
 /* Return nonzero if X's old contents don't survive after INSN.
    This will be true if X is (cc0) or if X is a register and
@@ -1945,7 +2385,7 @@ note_uses (rtx *pbody, void (*fun) (rtx *, void *), void *data)
    by INSN.  */
 
 int
-dead_or_set_p (const_rtx insn, const_rtx x)
+dead_or_set_p (const rtx_insn *insn, const_rtx x)
 {
   unsigned int regno, end_regno;
   unsigned int i;
@@ -1965,20 +2405,16 @@ dead_or_set_p (const_rtx insn, const_rtx x)
   return 1;
 }
 
-/* Return TRUE iff DEST is a register or subreg of a register and
-   doesn't change the number of words of the inner register, and any
-   part of the register is TEST_REGNO.  */
+/* Return TRUE iff DEST is a register or subreg of a register, is a
+   complete rather than read-modify-write destination, and contains
+   register TEST_REGNO.  */
 
 static bool
 covers_regno_no_parallel_p (const_rtx dest, unsigned int test_regno)
 {
   unsigned int regno, endregno;
 
-  if (GET_CODE (dest) == SUBREG
-      && (((GET_MODE_SIZE (GET_MODE (dest))
-           + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
-         == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
-              + UNITS_PER_WORD - 1) / UNITS_PER_WORD)))
+  if (GET_CODE (dest) == SUBREG && !read_modify_subreg_p (dest))
     dest = SUBREG_REG (dest);
 
   if (!REG_P (dest))
@@ -2019,7 +2455,7 @@ covers_regno_p (const_rtx dest, unsigned int test_regno)
 /* Utility function for dead_or_set_p to check an individual register. */
 
 int
-dead_or_set_regno_p (const_rtx insn, unsigned int test_regno)
+dead_or_set_regno_p (const rtx_insn *insn, unsigned int test_regno)
 {
   const_rtx pattern;
 
@@ -2037,7 +2473,7 @@ dead_or_set_regno_p (const_rtx insn, unsigned int test_regno)
   if (GET_CODE (pattern) == COND_EXEC)
     return 0;
 
-  if (GET_CODE (pattern) == SET)
+  if (GET_CODE (pattern) == SET || GET_CODE (pattern) == CLOBBER)
     return covers_regno_p (SET_DEST (pattern), test_regno);
   else if (GET_CODE (pattern) == PARALLEL)
     {
@@ -2288,13 +2724,22 @@ add_reg_note (rtx insn, enum reg_note kind, rtx datum)
 /* Add an integer register note with kind KIND and datum DATUM to INSN.  */
 
 void
-add_int_reg_note (rtx insn, enum reg_note kind, int datum)
+add_int_reg_note (rtx_insn *insn, enum reg_note kind, int datum)
 {
   gcc_checking_assert (int_reg_note_p (kind));
   REG_NOTES (insn) = gen_rtx_INT_LIST ((machine_mode) kind,
                                       datum, REG_NOTES (insn));
 }
 
+/* Add a REG_ARGS_SIZE note to INSN with value VALUE.  */
+
+void
+add_args_size_note (rtx_insn *insn, poly_int64 value)
+{
+  gcc_checking_assert (!find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX));
+  add_reg_note (insn, REG_ARGS_SIZE, gen_int_mode (value, Pmode));
+}
+
 /* Add a register note like NOTE to INSN.  */
 
 void
@@ -2351,22 +2796,31 @@ remove_note (rtx_insn *insn, const_rtx note)
     }
 }
 
-/* Remove REG_EQUAL and/or REG_EQUIV notes if INSN has such notes.  */
+/* Remove REG_EQUAL and/or REG_EQUIV notes if INSN has such notes.
+   If NO_RESCAN is false and any notes were removed, call
+   df_notes_rescan.  Return true if any note has been removed.  */
 
-void
-remove_reg_equal_equiv_notes (rtx_insn *insn)
+bool
+remove_reg_equal_equiv_notes (rtx_insn *insn, bool no_rescan)
 {
   rtx *loc;
+  bool ret = false;
 
   loc = &REG_NOTES (insn);
   while (*loc)
     {
       enum reg_note kind = REG_NOTE_KIND (*loc);
       if (kind == REG_EQUAL || kind == REG_EQUIV)
-       *loc = XEXP (*loc, 1);
+       {
+         *loc = XEXP (*loc, 1);
+         ret = true;
+       }
       else
        loc = &XEXP (*loc, 1);
     }
+  if (ret && !no_rescan)
+    df_notes_rescan (insn);
+  return ret;
 }
 
 /* Remove all REG_EQUAL and REG_EQUIV notes referring to REGNO.  */
@@ -2723,7 +3177,7 @@ may_trap_p_1 (const_rtx x, unsigned flags)
          code_changed
          || !MEM_NOTRAP_P (x))
        {
-         HOST_WIDE_INT size = MEM_SIZE_KNOWN_P (x) ? MEM_SIZE (x) : 0;
+         poly_int64 size = MEM_SIZE_KNOWN_P (x) ? MEM_SIZE (x) : -1;
          return rtx_addr_can_trap_p_1 (XEXP (x, 0), 0, size,
                                        GET_MODE (x), code_changed);
        }
@@ -2737,10 +3191,28 @@ may_trap_p_1 (const_rtx x, unsigned flags)
     case UMOD:
       if (HONOR_SNANS (x))
        return 1;
-      if (SCALAR_FLOAT_MODE_P (GET_MODE (x)))
+      if (FLOAT_MODE_P (GET_MODE (x)))
        return flag_trapping_math;
       if (!CONSTANT_P (XEXP (x, 1)) || (XEXP (x, 1) == const0_rtx))
        return 1;
+      if (GET_CODE (XEXP (x, 1)) == CONST_VECTOR)
+       {
+         /* For CONST_VECTOR, return 1 if any element is or might be zero.  */
+         unsigned int n_elts;
+         rtx op = XEXP (x, 1);
+         if (!GET_MODE_NUNITS (GET_MODE (op)).is_constant (&n_elts))
+           {
+             if (!CONST_VECTOR_DUPLICATE_P (op))
+               return 1;
+             for (unsigned i = 0; i < (unsigned int) XVECLEN (op, 0); i++)
+               if (CONST_VECTOR_ENCODED_ELT (op, i) == const0_rtx)
+                 return 1;
+           }
+         else
+           for (unsigned i = 0; i < n_elts; i++)
+             if (CONST_VECTOR_ELT (op, i) == const0_rtx)
+               return 1;
+       }
       break;
 
     case EXPR_LIST:
@@ -2789,12 +3261,16 @@ may_trap_p_1 (const_rtx x, unsigned flags)
     case NEG:
     case ABS:
     case SUBREG:
+    case VEC_MERGE:
+    case VEC_SELECT:
+    case VEC_CONCAT:
+    case VEC_DUPLICATE:
       /* These operations don't trap even with floating point.  */
       break;
 
     default:
       /* Any floating arithmetic may trap.  */
-      if (SCALAR_FLOAT_MODE_P (GET_MODE (x)) && flag_trapping_math)
+      if (FLOAT_MODE_P (GET_MODE (x)) && flag_trapping_math)
        return 1;
     }
 
@@ -2871,64 +3347,6 @@ may_trap_or_fault_p (const_rtx x)
   return may_trap_p_1 (x, 1);
 }
 \f
-/* Return nonzero if X contains a comparison that is not either EQ or NE,
-   i.e., an inequality.  */
-
-int
-inequality_comparisons_p (const_rtx x)
-{
-  const char *fmt;
-  int len, i;
-  const enum rtx_code code = GET_CODE (x);
-
-  switch (code)
-    {
-    case REG:
-    case SCRATCH:
-    case PC:
-    case CC0:
-    CASE_CONST_ANY:
-    case CONST:
-    case LABEL_REF:
-    case SYMBOL_REF:
-      return 0;
-
-    case LT:
-    case LTU:
-    case GT:
-    case GTU:
-    case LE:
-    case LEU:
-    case GE:
-    case GEU:
-      return 1;
-
-    default:
-      break;
-    }
-
-  len = GET_RTX_LENGTH (code);
-  fmt = GET_RTX_FORMAT (code);
-
-  for (i = 0; i < len; i++)
-    {
-      if (fmt[i] == 'e')
-       {
-         if (inequality_comparisons_p (XEXP (x, i)))
-           return 1;
-       }
-      else if (fmt[i] == 'E')
-       {
-         int j;
-         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-           if (inequality_comparisons_p (XVECEXP (x, i, j)))
-             return 1;
-       }
-    }
-
-  return 0;
-}
-\f
 /* Replace any occurrence of FROM in X with TO.  The function does
    not enter into CONST_DOUBLE for the replace.
 
@@ -3141,6 +3559,23 @@ tablejump_p (const rtx_insn *insn, rtx_insn **labelp,
   return true;
 }
 
+/* For INSN known to satisfy tablejump_p, determine if it actually is a
+   CASESI.  Return the insn pattern if so, NULL_RTX otherwise.  */
+
+rtx
+tablejump_casesi_pattern (const rtx_insn *insn)
+{
+  rtx tmp;
+
+  if ((tmp = single_set (insn)) != NULL
+      && SET_DEST (tmp) == pc_rtx
+      && GET_CODE (SET_SRC (tmp)) == IF_THEN_ELSE
+      && GET_CODE (XEXP (SET_SRC (tmp), 2)) == LABEL_REF)
+    return tmp;
+
+  return NULL_RTX;
+}
+
 /* A subroutine of computed_jump_p, return 1 if X contains a REG or MEM or
    constant that is not in the constant pool and not in the condition
    of an IF_THEN_ELSE.  */
@@ -3253,7 +3688,7 @@ for_each_inc_dec_find_inc_dec (rtx mem, for_each_inc_dec_fn fn, void *data)
     case PRE_INC:
     case POST_INC:
       {
-       int size = GET_MODE_SIZE (GET_MODE (mem));
+       poly_int64 size = GET_MODE_SIZE (GET_MODE (mem));
        rtx r1 = XEXP (x, 0);
        rtx c = gen_int_mode (size, GET_MODE (r1));
        return fn (mem, x, r1, r1, c, data);
@@ -3262,7 +3697,7 @@ for_each_inc_dec_find_inc_dec (rtx mem, for_each_inc_dec_fn fn, void *data)
     case PRE_DEC:
     case POST_DEC:
       {
-       int size = GET_MODE_SIZE (GET_MODE (mem));
+       poly_int64 size = GET_MODE_SIZE (GET_MODE (mem));
        rtx r1 = XEXP (x, 0);
        rtx c = gen_int_mode (-size, GET_MODE (r1));
        return fn (mem, x, r1, r1, c, data);
@@ -3355,13 +3790,15 @@ commutative_operand_precedence (rtx op)
 
   /* Constants always become the second operand.  Prefer "nice" constants.  */
   if (code == CONST_INT)
-    return -8;
+    return -10;
   if (code == CONST_WIDE_INT)
-    return -7;
+    return -9;
+  if (code == CONST_POLY_INT)
+    return -8;
   if (code == CONST_DOUBLE)
-    return -7;
+    return -8;
   if (code == CONST_FIXED)
-    return -7;
+    return -8;
   op = avoid_constant_pool_reference (op);
   code = GET_CODE (op);
 
@@ -3369,13 +3806,15 @@ commutative_operand_precedence (rtx op)
     {
     case RTX_CONST_OBJ:
       if (code == CONST_INT)
-        return -6;
+       return -7;
       if (code == CONST_WIDE_INT)
-        return -6;
+       return -6;
+      if (code == CONST_POLY_INT)
+       return -5;
       if (code == CONST_DOUBLE)
-        return -5;
+       return -5;
       if (code == CONST_FIXED)
-        return -5;
+       return -5;
       return -4;
 
     case RTX_EXTRA:
@@ -3476,58 +3915,107 @@ loc_mentioned_in_p (rtx *loc, const_rtx in)
   return 0;
 }
 
-/* Helper function for subreg_lsb.  Given a subreg's OUTER_MODE, INNER_MODE,
-   and SUBREG_BYTE, return the bit offset where the subreg begins
-   (counting from the least significant bit of the operand).  */
+/* Reinterpret a subreg as a bit extraction from an integer and return
+   the position of the least significant bit of the extracted value.
+   In other words, if the extraction were performed as a shift right
+   and mask, return the number of bits to shift right.
 
-unsigned int
-subreg_lsb_1 (machine_mode outer_mode,
-             machine_mode inner_mode,
-             unsigned int subreg_byte)
+   The outer value of the subreg has OUTER_BYTES bytes and starts at
+   byte offset SUBREG_BYTE within an inner value of INNER_BYTES bytes.  */
+
+poly_uint64
+subreg_size_lsb (poly_uint64 outer_bytes,
+                poly_uint64 inner_bytes,
+                poly_uint64 subreg_byte)
 {
-  unsigned int bitpos;
-  unsigned int byte;
-  unsigned int word;
+  poly_uint64 subreg_end, trailing_bytes, byte_pos;
 
   /* A paradoxical subreg begins at bit position 0.  */
-  if (GET_MODE_PRECISION (outer_mode) > GET_MODE_PRECISION (inner_mode))
-    return 0;
-
-  if (WORDS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
-    /* If the subreg crosses a word boundary ensure that
-       it also begins and ends on a word boundary.  */
-    gcc_assert (!((subreg_byte % UNITS_PER_WORD
-                 + GET_MODE_SIZE (outer_mode)) > UNITS_PER_WORD
-                 && (subreg_byte % UNITS_PER_WORD
-                     || GET_MODE_SIZE (outer_mode) % UNITS_PER_WORD)));
-
-  if (WORDS_BIG_ENDIAN)
-    word = (GET_MODE_SIZE (inner_mode)
-           - (subreg_byte + GET_MODE_SIZE (outer_mode))) / UNITS_PER_WORD;
-  else
-    word = subreg_byte / UNITS_PER_WORD;
-  bitpos = word * BITS_PER_WORD;
+  gcc_checking_assert (ordered_p (outer_bytes, inner_bytes));
+  if (maybe_gt (outer_bytes, inner_bytes))
+    {
+      gcc_checking_assert (known_eq (subreg_byte, 0U));
+      return 0;
+    }
 
-  if (BYTES_BIG_ENDIAN)
-    byte = (GET_MODE_SIZE (inner_mode)
-           - (subreg_byte + GET_MODE_SIZE (outer_mode))) % UNITS_PER_WORD;
+  subreg_end = subreg_byte + outer_bytes;
+  trailing_bytes = inner_bytes - subreg_end;
+  if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
+    byte_pos = trailing_bytes;
+  else if (!WORDS_BIG_ENDIAN && !BYTES_BIG_ENDIAN)
+    byte_pos = subreg_byte;
   else
-    byte = subreg_byte % UNITS_PER_WORD;
-  bitpos += byte * BITS_PER_UNIT;
+    {
+      /* When bytes and words have opposite endianness, we must be able
+        to split offsets into words and bytes at compile time.  */
+      poly_uint64 leading_word_part
+       = force_align_down (subreg_byte, UNITS_PER_WORD);
+      poly_uint64 trailing_word_part
+       = force_align_down (trailing_bytes, UNITS_PER_WORD);
+      /* If the subreg crosses a word boundary ensure that
+        it also begins and ends on a word boundary.  */
+      gcc_assert (known_le (subreg_end - leading_word_part,
+                           (unsigned int) UNITS_PER_WORD)
+                 || (known_eq (leading_word_part, subreg_byte)
+                     && known_eq (trailing_word_part, trailing_bytes)));
+      if (WORDS_BIG_ENDIAN)
+       byte_pos = trailing_word_part + (subreg_byte - leading_word_part);
+      else
+       byte_pos = leading_word_part + (trailing_bytes - trailing_word_part);
+    }
 
-  return bitpos;
+  return byte_pos * BITS_PER_UNIT;
 }
 
 /* Given a subreg X, return the bit offset where the subreg begins
    (counting from the least significant bit of the reg).  */
 
-unsigned int
+poly_uint64
 subreg_lsb (const_rtx x)
 {
   return subreg_lsb_1 (GET_MODE (x), GET_MODE (SUBREG_REG (x)),
                       SUBREG_BYTE (x));
 }
 
+/* Return the subreg byte offset for a subreg whose outer value has
+   OUTER_BYTES bytes, whose inner value has INNER_BYTES bytes, and where
+   there are LSB_SHIFT *bits* between the lsb of the outer value and the
+   lsb of the inner value.  This is the inverse of the calculation
+   performed by subreg_lsb_1 (which converts byte offsets to bit shifts).  */
+
+poly_uint64
+subreg_size_offset_from_lsb (poly_uint64 outer_bytes, poly_uint64 inner_bytes,
+                            poly_uint64 lsb_shift)
+{
+  /* A paradoxical subreg begins at bit position 0.  */
+  gcc_checking_assert (ordered_p (outer_bytes, inner_bytes));
+  if (maybe_gt (outer_bytes, inner_bytes))
+    {
+      gcc_checking_assert (known_eq (lsb_shift, 0U));
+      return 0;
+    }
+
+  poly_uint64 lower_bytes = exact_div (lsb_shift, BITS_PER_UNIT);
+  poly_uint64 upper_bytes = inner_bytes - (lower_bytes + outer_bytes);
+  if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
+    return upper_bytes;
+  else if (!WORDS_BIG_ENDIAN && !BYTES_BIG_ENDIAN)
+    return lower_bytes;
+  else
+    {
+      /* When bytes and words have opposite endianness, we must be able
+        to split offsets into words and bytes at compile time.  */
+      poly_uint64 lower_word_part = force_align_down (lower_bytes,
+                                                     UNITS_PER_WORD);
+      poly_uint64 upper_word_part = force_align_down (upper_bytes,
+                                                     UNITS_PER_WORD);
+      if (WORDS_BIG_ENDIAN)
+       return upper_word_part + (lower_bytes - lower_word_part);
+      else
+       return lower_word_part + (upper_bytes - upper_word_part);
+    }
+}
+
 /* Fill in information about a subreg of a hard register.
    xregno - A regno of an inner hard subreg_reg (or what will become one).
    xmode  - The mode of xregno.
@@ -3541,42 +4029,45 @@ subreg_lsb (const_rtx x)
    function does not check whether adding INFO->offset to XREGNO gives
    a valid hard register; even if INFO->offset + XREGNO is out of range,
    there might be another register of the same type that is in range.
-   Likewise it doesn't check whether HARD_REGNO_MODE_OK accepts the new
-   register, since that can depend on things like whether the final
+   Likewise it doesn't check whether targetm.hard_regno_mode_ok accepts
+   the new register, since that can depend on things like whether the final
    register number is even or odd.  Callers that want to check whether
    this particular subreg can be replaced by a simple (reg ...) should
    use simplify_subreg_regno.  */
 
 void
 subreg_get_info (unsigned int xregno, machine_mode xmode,
-                unsigned int offset, machine_mode ymode,
+                poly_uint64 offset, machine_mode ymode,
                 struct subreg_info *info)
 {
-  int nregs_xmode, nregs_ymode;
-  int mode_multiple, nregs_multiple;
-  int offset_adj, y_offset, y_offset_adj;
-  int regsize_xmode, regsize_ymode;
-  bool rknown;
+  unsigned int nregs_xmode, nregs_ymode;
 
   gcc_assert (xregno < FIRST_PSEUDO_REGISTER);
 
-  rknown = false;
+  poly_uint64 xsize = GET_MODE_SIZE (xmode);
+  poly_uint64 ysize = GET_MODE_SIZE (ymode);
+
+  bool rknown = false;
 
-  /* If there are holes in a non-scalar mode in registers, we expect
-     that it is made up of its units concatenated together.  */
+  /* If the register representation of a non-scalar mode has holes in it,
+     we expect the scalar units to be concatenated together, with the holes
+     distributed evenly among the scalar units.  Each scalar unit must occupy
+     at least one register.  */
   if (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode))
     {
-      machine_mode xmode_unit;
-
+      /* As a consequence, we must be dealing with a constant number of
+        scalars, and thus a constant offset and number of units.  */
+      HOST_WIDE_INT coffset = offset.to_constant ();
+      HOST_WIDE_INT cysize = ysize.to_constant ();
       nregs_xmode = HARD_REGNO_NREGS_WITH_PADDING (xregno, xmode);
-      xmode_unit = GET_MODE_INNER (xmode);
+      unsigned int nunits = GET_MODE_NUNITS (xmode).to_constant ();
+      scalar_mode xmode_unit = GET_MODE_INNER (xmode);
       gcc_assert (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode_unit));
       gcc_assert (nregs_xmode
-                 == (GET_MODE_NUNITS (xmode)
+                 == (nunits
                      * HARD_REGNO_NREGS_WITH_PADDING (xregno, xmode_unit)));
-      gcc_assert (hard_regno_nregs[xregno][xmode]
-                 == (hard_regno_nregs[xregno][xmode_unit]
-                     * GET_MODE_NUNITS (xmode)));
+      gcc_assert (hard_regno_nregs (xregno, xmode)
+                 == hard_regno_nregs (xregno, xmode_unit) * nunits);
 
       /* You can only ask for a SUBREG of a value with holes in the middle
         if you don't cross the holes.  (Such a SUBREG should be done by
@@ -3586,34 +4077,38 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
         3 for each part, but in memory it's two 128-bit parts.
         Padding is assumed to be at the end (not necessarily the 'high part')
         of each unit.  */
-      if ((offset / GET_MODE_SIZE (xmode_unit) + 1
-          < GET_MODE_NUNITS (xmode))
-         && (offset / GET_MODE_SIZE (xmode_unit)
-             != ((offset + GET_MODE_SIZE (ymode) - 1)
-                 / GET_MODE_SIZE (xmode_unit))))
+      if ((coffset / GET_MODE_SIZE (xmode_unit) + 1 < nunits)
+         && (coffset / GET_MODE_SIZE (xmode_unit)
+             != ((coffset + cysize - 1) / GET_MODE_SIZE (xmode_unit))))
        {
          info->representable_p = false;
          rknown = true;
        }
     }
   else
-    nregs_xmode = hard_regno_nregs[xregno][xmode];
+    nregs_xmode = hard_regno_nregs (xregno, xmode);
+
+  nregs_ymode = hard_regno_nregs (xregno, ymode);
 
-  nregs_ymode = hard_regno_nregs[xregno][ymode];
+  /* Subreg sizes must be ordered, so that we can tell whether they are
+     partial, paradoxical or complete.  */
+  gcc_checking_assert (ordered_p (xsize, ysize));
 
   /* Paradoxical subregs are otherwise valid.  */
-  if (!rknown
-      && offset == 0
-      && GET_MODE_PRECISION (ymode) > GET_MODE_PRECISION (xmode))
+  if (!rknown && known_eq (offset, 0U) && maybe_gt (ysize, xsize))
     {
       info->representable_p = true;
       /* If this is a big endian paradoxical subreg, which uses more
         actual hard registers than the original register, we must
         return a negative offset so that we find the proper highpart
-        of the register.  */
-      if (GET_MODE_SIZE (ymode) > UNITS_PER_WORD
-         ? REG_WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN)
-       info->offset = nregs_xmode - nregs_ymode;
+        of the register.
+
+        We assume that the ordering of registers within a multi-register
+        value has a consistent endianness: if bytes and register words
+        have different endianness, the hard registers that make up a
+        multi-register value must be at least word-sized.  */
+      if (REG_WORDS_BIG_ENDIAN)
+       info->offset = (int) nregs_xmode - (int) nregs_ymode;
       else
        info->offset = 0;
       info->nregs = nregs_ymode;
@@ -3622,37 +4117,34 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
 
   /* If registers store different numbers of bits in the different
      modes, we cannot generally form this subreg.  */
+  poly_uint64 regsize_xmode, regsize_ymode;
   if (!HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode)
       && !HARD_REGNO_NREGS_HAS_PADDING (xregno, ymode)
-      && (GET_MODE_SIZE (xmode) % nregs_xmode) == 0
-      && (GET_MODE_SIZE (ymode) % nregs_ymode) == 0)
+      && multiple_p (xsize, nregs_xmode, &regsize_xmode)
+      && multiple_p (ysize, nregs_ymode, &regsize_ymode))
     {
-      regsize_xmode = GET_MODE_SIZE (xmode) / nregs_xmode;
-      regsize_ymode = GET_MODE_SIZE (ymode) / nregs_ymode;
-      if (!rknown && regsize_xmode > regsize_ymode && nregs_ymode > 1)
-       {
-         info->representable_p = false;
-         info->nregs
-           = (GET_MODE_SIZE (ymode) + regsize_xmode - 1) / regsize_xmode;
-         info->offset = offset / regsize_xmode;
-         return;
-       }
-      if (!rknown && regsize_ymode > regsize_xmode && nregs_xmode > 1)
+      if (!rknown
+         && ((nregs_ymode > 1 && maybe_gt (regsize_xmode, regsize_ymode))
+             || (nregs_xmode > 1 && maybe_gt (regsize_ymode, regsize_xmode))))
        {
          info->representable_p = false;
-         info->nregs
-           = (GET_MODE_SIZE (ymode) + regsize_xmode - 1) / regsize_xmode;
-         info->offset = offset / regsize_xmode;
+         if (!can_div_away_from_zero_p (ysize, regsize_xmode, &info->nregs)
+             || !can_div_trunc_p (offset, regsize_xmode, &info->offset))
+           /* Checked by validate_subreg.  We must know at compile time
+              which inner registers are being accessed.  */
+           gcc_unreachable ();
          return;
        }
       /* It's not valid to extract a subreg of mode YMODE at OFFSET that
         would go outside of XMODE.  */
-      if (!rknown
-         && GET_MODE_SIZE (ymode) + offset > GET_MODE_SIZE (xmode))
+      if (!rknown && maybe_gt (ysize + offset, xsize))
        {
          info->representable_p = false;
          info->nregs = nregs_ymode;
-         info->offset = offset / regsize_xmode;
+         if (!can_div_trunc_p (offset, regsize_xmode, &info->offset))
+           /* Checked by validate_subreg.  We must know at compile time
+              which inner registers are being accessed.  */
+           gcc_unreachable ();
          return;
        }
       /* Quick exit for the simple and common case of extracting whole
@@ -3660,26 +4152,27 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
       /* ??? It would be better to integrate this into the code below,
         if we can generalize the concept enough and figure out how
         odd-sized modes can coexist with the other weird cases we support.  */
+      HOST_WIDE_INT count;
       if (!rknown
          && WORDS_BIG_ENDIAN == REG_WORDS_BIG_ENDIAN
-         && regsize_xmode == regsize_ymode
-         && (offset % regsize_ymode) == 0)
+         && known_eq (regsize_xmode, regsize_ymode)
+         && constant_multiple_p (offset, regsize_ymode, &count))
        {
          info->representable_p = true;
          info->nregs = nregs_ymode;
-         info->offset = offset / regsize_ymode;
-         gcc_assert (info->offset + info->nregs <= nregs_xmode);
+         info->offset = count;
+         gcc_assert (info->offset + info->nregs <= (int) nregs_xmode);
          return;
        }
     }
 
   /* Lowpart subregs are otherwise valid.  */
-  if (!rknown && offset == subreg_lowpart_offset (ymode, xmode))
+  if (!rknown && known_eq (offset, subreg_lowpart_offset (ymode, xmode)))
     {
       info->representable_p = true;
       rknown = true;
 
-      if (offset == 0 || nregs_xmode == nregs_ymode)
+      if (known_eq (offset, 0U) || nregs_xmode == nregs_ymode)
        {
          info->offset = 0;
          info->nregs = nregs_ymode;
@@ -3687,47 +4180,51 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
        }
     }
 
-  /* This should always pass, otherwise we don't know how to verify
-     the constraint.  These conditions may be relaxed but
-     subreg_regno_offset would need to be redesigned.  */
-  gcc_assert ((GET_MODE_SIZE (xmode) % GET_MODE_SIZE (ymode)) == 0);
+  /* Set NUM_BLOCKS to the number of independently-representable YMODE
+     values there are in (reg:XMODE XREGNO).  We can view the register
+     as consisting of this number of independent "blocks", where each
+     block occupies NREGS_YMODE registers and contains exactly one
+     representable YMODE value.  */
   gcc_assert ((nregs_xmode % nregs_ymode) == 0);
-
-  if (WORDS_BIG_ENDIAN != REG_WORDS_BIG_ENDIAN
-      && GET_MODE_SIZE (xmode) > UNITS_PER_WORD)
-    {
-      HOST_WIDE_INT xsize = GET_MODE_SIZE (xmode);
-      HOST_WIDE_INT ysize = GET_MODE_SIZE (ymode);
-      HOST_WIDE_INT off_low = offset & (ysize - 1);
-      HOST_WIDE_INT off_high = offset & ~(ysize - 1);
-      offset = (xsize - ysize - off_high) | off_low;
-    }
-  /* The XMODE value can be seen as a vector of NREGS_XMODE
-     values.  The subreg must represent a lowpart of given field.
-     Compute what field it is.  */
-  offset_adj = offset;
-  offset_adj -= subreg_lowpart_offset (ymode,
-                                      mode_for_size (GET_MODE_BITSIZE (xmode)
-                                                     / nregs_xmode,
-                                                     MODE_INT, 0));
-
-  /* Size of ymode must not be greater than the size of xmode.  */
-  mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode);
-  gcc_assert (mode_multiple != 0);
-
-  y_offset = offset / GET_MODE_SIZE (ymode);
-  y_offset_adj = offset_adj / GET_MODE_SIZE (ymode);
-  nregs_multiple = nregs_xmode / nregs_ymode;
-
-  gcc_assert ((offset_adj % GET_MODE_SIZE (ymode)) == 0);
-  gcc_assert ((mode_multiple % nregs_multiple) == 0);
+  unsigned int num_blocks = nregs_xmode / nregs_ymode;
+
+  /* Calculate the number of bytes in each block.  This must always
+     be exact, otherwise we don't know how to verify the constraint.
+     These conditions may be relaxed but subreg_regno_offset would
+     need to be redesigned.  */
+  poly_uint64 bytes_per_block = exact_div (xsize, num_blocks);
+
+  /* Get the number of the first block that contains the subreg and the byte
+     offset of the subreg from the start of that block.  */
+  unsigned int block_number;
+  poly_uint64 subblock_offset;
+  if (!can_div_trunc_p (offset, bytes_per_block, &block_number,
+                       &subblock_offset))
+    /* Checked by validate_subreg.  We must know at compile time which
+       inner registers are being accessed.  */
+    gcc_unreachable ();
 
   if (!rknown)
     {
-      info->representable_p = (!(y_offset_adj % (mode_multiple / nregs_multiple)));
+      /* Only the lowpart of each block is representable.  */
+      info->representable_p
+       = known_eq (subblock_offset,
+                   subreg_size_lowpart_offset (ysize, bytes_per_block));
       rknown = true;
     }
-  info->offset = (y_offset / (mode_multiple / nregs_multiple)) * nregs_ymode;
+
+  /* We assume that the ordering of registers within a multi-register
+     value has a consistent endianness: if bytes and register words
+     have different endianness, the hard registers that make up a
+     multi-register value must be at least word-sized.  */
+  if (WORDS_BIG_ENDIAN != REG_WORDS_BIG_ENDIAN)
+    /* The block number we calculated above followed memory endianness.
+       Convert it to register endianness by counting back from the end.
+       (Note that, because of the assumption above, each block must be
+       at least word-sized.)  */
+    info->offset = (num_blocks - block_number - 1) * nregs_ymode;
+  else
+    info->offset = block_number * nregs_ymode;
   info->nregs = nregs_ymode;
 }
 
@@ -3739,7 +4236,7 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
    RETURN - The regno offset which would be used.  */
 unsigned int
 subreg_regno_offset (unsigned int xregno, machine_mode xmode,
-                    unsigned int offset, machine_mode ymode)
+                    poly_uint64 offset, machine_mode ymode)
 {
   struct subreg_info info;
   subreg_get_info (xregno, xmode, offset, ymode, &info);
@@ -3755,7 +4252,7 @@ subreg_regno_offset (unsigned int xregno, machine_mode xmode,
    RETURN - Whether the offset is representable.  */
 bool
 subreg_offset_representable_p (unsigned int xregno, machine_mode xmode,
-                              unsigned int offset, machine_mode ymode)
+                              poly_uint64 offset, machine_mode ymode)
 {
   struct subreg_info info;
   subreg_get_info (xregno, xmode, offset, ymode, &info);
@@ -3772,20 +4269,16 @@ subreg_offset_representable_p (unsigned int xregno, machine_mode xmode,
 
 int
 simplify_subreg_regno (unsigned int xregno, machine_mode xmode,
-                      unsigned int offset, machine_mode ymode)
+                      poly_uint64 offset, machine_mode ymode)
 {
   struct subreg_info info;
   unsigned int yregno;
 
-#ifdef CANNOT_CHANGE_MODE_CLASS
   /* Give the backend a chance to disallow the mode change.  */
   if (GET_MODE_CLASS (xmode) != MODE_COMPLEX_INT
       && GET_MODE_CLASS (xmode) != MODE_COMPLEX_FLOAT
-      && REG_CANNOT_CHANGE_MODE_P (xregno, xmode, ymode)
-      /* We can use mode change in LRA for some transformations.  */
-      && ! lra_in_progress)
+      && !REG_CAN_CHANGE_MODE_P (xregno, xmode, ymode))
     return -1;
-#endif
 
   /* We shouldn't simplify stack-related registers.  */
   if ((!reload_completed || frame_pointer_needed)
@@ -3817,8 +4310,8 @@ simplify_subreg_regno (unsigned int xregno, machine_mode xmode,
      ??? We allow invalid registers if (reg:XMODE XREGNO) is also invalid.
      This is a kludge to work around how complex FP arguments are passed
      on IA-64 and should be fixed.  See PR target/49226.  */
-  if (!HARD_REGNO_MODE_OK (yregno, ymode)
-      && HARD_REGNO_MODE_OK (xregno, xmode))
+  if (!targetm.hard_regno_mode_ok (yregno, ymode)
+      && targetm.hard_regno_mode_ok (xregno, xmode))
     return -1;
 
   return (int) yregno;
@@ -3940,7 +4433,7 @@ find_first_parameter_load (rtx_insn *call_insn, rtx_insn *boundary)
       if (INSN_P (before))
        {
          int nregs_old = parm.nregs;
-         note_stores (PATTERN (before), parms_set, &parm);
+         note_stores (before, parms_set, &parm);
          /* If we found something that did not set a parameter reg,
             we're done.  Do not keep going, as that might result
             in hoisting an insn before the setting of a pseudo
@@ -4040,18 +4533,23 @@ rtx_cost (rtx x, machine_mode mode, enum rtx_code outer_code,
   const char *fmt;
   int total;
   int factor;
+  unsigned mode_size;
 
   if (x == 0)
     return 0;
 
-  if (GET_MODE (x) != VOIDmode)
+  if (GET_CODE (x) == SET)
+    /* A SET doesn't have a mode, so let's look at the SET_DEST to get
+       the mode for the factor.  */
+    mode = GET_MODE (SET_DEST (x));
+  else if (GET_MODE (x) != VOIDmode)
     mode = GET_MODE (x);
 
+  mode_size = estimated_poly_value (GET_MODE_SIZE (mode));
+
   /* A size N times larger than UNITS_PER_WORD likely needs N times as
      many insns, taking N times as long.  */
-  factor = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
-  if (factor == 0)
-    factor = 1;
+  factor = mode_size > UNITS_PER_WORD ? mode_size / UNITS_PER_WORD : 1;
 
   /* Compute the default costs of certain things.
      Note that targetm.rtx_costs can override the defaults.  */
@@ -4076,14 +4574,6 @@ rtx_cost (rtx x, machine_mode mode, enum rtx_code outer_code,
       /* Used in combine.c as a marker.  */
       total = 0;
       break;
-    case SET:
-      /* A SET doesn't have a mode, so let's look at the SET_DEST to get
-        the mode for the factor.  */
-      mode = GET_MODE (SET_DEST (x));
-      factor = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
-      if (factor == 0)
-       factor = 1;
-      /* FALLTHRU */
     default:
       total = factor * COSTS_N_INSNS (1);
     }
@@ -4097,10 +4587,17 @@ rtx_cost (rtx x, machine_mode mode, enum rtx_code outer_code,
       total = 0;
       /* If we can't tie these modes, make this expensive.  The larger
         the mode, the more expensive it is.  */
-      if (! MODES_TIEABLE_P (mode, GET_MODE (SUBREG_REG (x))))
+      if (!targetm.modes_tieable_p (mode, GET_MODE (SUBREG_REG (x))))
        return COSTS_N_INSNS (2 + factor);
       break;
 
+    case TRUNCATE:
+      if (targetm.modes_tieable_p (mode, GET_MODE (XEXP (x, 0))))
+       {
+         total = 0;
+         break;
+       }
+      /* FALLTHRU */
     default:
       if (targetm.rtx_costs (x, mode, outer_code, opno, &total, speed))
        return total;
@@ -4164,13 +4661,23 @@ default_address_cost (rtx x, machine_mode, addr_space_t, bool speed)
 unsigned HOST_WIDE_INT
 nonzero_bits (const_rtx x, machine_mode mode)
 {
-  return cached_nonzero_bits (x, mode, NULL_RTX, VOIDmode, 0);
+  if (mode == VOIDmode)
+    mode = GET_MODE (x);
+  scalar_int_mode int_mode;
+  if (!is_a <scalar_int_mode> (mode, &int_mode))
+    return GET_MODE_MASK (mode);
+  return cached_nonzero_bits (x, int_mode, NULL_RTX, VOIDmode, 0);
 }
 
 unsigned int
 num_sign_bit_copies (const_rtx x, machine_mode mode)
 {
-  return cached_num_sign_bit_copies (x, mode, NULL_RTX, VOIDmode, 0);
+  if (mode == VOIDmode)
+    mode = GET_MODE (x);
+  scalar_int_mode int_mode;
+  if (!is_a <scalar_int_mode> (mode, &int_mode))
+    return 1;
+  return cached_num_sign_bit_copies (x, int_mode, NULL_RTX, VOIDmode, 0);
 }
 
 /* Return true if nonzero_bits1 might recurse into both operands
@@ -4208,7 +4715,7 @@ nonzero_bits_binary_arith_p (const_rtx x)
    identical subexpressions on the first or the second level.  */
 
 static unsigned HOST_WIDE_INT
-cached_nonzero_bits (const_rtx x, machine_mode mode, const_rtx known_x,
+cached_nonzero_bits (const_rtx x, scalar_int_mode mode, const_rtx known_x,
                     machine_mode known_mode,
                     unsigned HOST_WIDE_INT known_ret)
 {
@@ -4261,27 +4768,40 @@ cached_nonzero_bits (const_rtx x, machine_mode mode, const_rtx known_x,
    an arithmetic operation, we can do better.  */
 
 static unsigned HOST_WIDE_INT
-nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
+nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
               machine_mode known_mode,
               unsigned HOST_WIDE_INT known_ret)
 {
   unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode);
   unsigned HOST_WIDE_INT inner_nz;
-  enum rtx_code code;
+  enum rtx_code code = GET_CODE (x);
   machine_mode inner_mode;
+  unsigned int inner_width;
+  scalar_int_mode xmode;
+
   unsigned int mode_width = GET_MODE_PRECISION (mode);
 
-  /* For floating-point and vector values, assume all bits are needed.  */
-  if (FLOAT_MODE_P (GET_MODE (x)) || FLOAT_MODE_P (mode)
-      || VECTOR_MODE_P (GET_MODE (x)) || VECTOR_MODE_P (mode))
+  if (CONST_INT_P (x))
+    {
+      if (SHORT_IMMEDIATES_SIGN_EXTEND
+         && INTVAL (x) > 0
+         && mode_width < BITS_PER_WORD
+         && (UINTVAL (x) & (HOST_WIDE_INT_1U << (mode_width - 1))) != 0)
+       return UINTVAL (x) | (HOST_WIDE_INT_M1U << mode_width);
+
+      return UINTVAL (x);
+    }
+
+  if (!is_a <scalar_int_mode> (GET_MODE (x), &xmode))
     return nonzero;
+  unsigned int xmode_width = GET_MODE_PRECISION (xmode);
 
   /* If X is wider than MODE, use its mode instead.  */
-  if (GET_MODE_PRECISION (GET_MODE (x)) > mode_width)
+  if (xmode_width > mode_width)
     {
-      mode = GET_MODE (x);
+      mode = xmode;
       nonzero = GET_MODE_MASK (mode);
-      mode_width = GET_MODE_PRECISION (mode);
+      mode_width = xmode_width;
     }
 
   if (mode_width > HOST_BITS_PER_WIDE_INT)
@@ -4290,28 +4810,25 @@ nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
     return nonzero;
 
   /* If MODE is wider than X, but both are a single word for both the host
-     and target machines, we can compute this from which bits of the
-     object might be nonzero in its own mode, taking into account the fact
-     that on many CISC machines, accessing an object in a wider mode
-     causes the high-order bits to become undefined.  So they are
-     not known to be zero.  */
-
-  if (!WORD_REGISTER_OPERATIONS
-      && GET_MODE (x) != VOIDmode
-      && GET_MODE (x) != mode
-      && GET_MODE_PRECISION (GET_MODE (x)) <= BITS_PER_WORD
-      && GET_MODE_PRECISION (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
-      && GET_MODE_PRECISION (mode) > GET_MODE_PRECISION (GET_MODE (x)))
+     and target machines, we can compute this from which bits of the object
+     might be nonzero in its own mode, taking into account the fact that, on
+     CISC machines, accessing an object in a wider mode generally causes the
+     high-order bits to become undefined, so they are not known to be zero.
+     We extend this reasoning to RISC machines for operations that might not
+     operate on the full registers.  */
+  if (mode_width > xmode_width
+      && xmode_width <= BITS_PER_WORD
+      && xmode_width <= HOST_BITS_PER_WIDE_INT
+      && !(WORD_REGISTER_OPERATIONS && word_register_operation_p (x)))
     {
-      nonzero &= cached_nonzero_bits (x, GET_MODE (x),
+      nonzero &= cached_nonzero_bits (x, xmode,
                                      known_x, known_mode, known_ret);
-      nonzero |= GET_MODE_MASK (mode) & ~GET_MODE_MASK (GET_MODE (x));
+      nonzero |= GET_MODE_MASK (mode) & ~GET_MODE_MASK (xmode);
       return nonzero;
     }
 
   /* Please keep nonzero_bits_binary_arith_p above in sync with
      the code in the switch below.  */
-  code = GET_CODE (x);
   switch (code)
     {
     case REG:
@@ -4322,7 +4839,8 @@ nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
         we can do this only if the target does not support different pointer
         or address modes depending on the address space.  */
       if (target_default_pointer_address_modes_p ()
-         && POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
+         && POINTERS_EXTEND_UNSIGNED
+         && xmode == Pmode
          && REG_POINTER (x)
          && !targetm.have_ptr_extend ())
        nonzero &= GET_MODE_MASK (ptr_mode);
@@ -4345,8 +4863,10 @@ nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
             stack to be momentarily aligned only to that amount,
             so we pick the least alignment.  */
          if (x == stack_pointer_rtx && PUSH_ARGS)
-           alignment = MIN ((unsigned HOST_WIDE_INT) PUSH_ROUNDING (1),
-                            alignment);
+           {
+             poly_uint64 rounded_1 = PUSH_ROUNDING (poly_int64 (1));
+             alignment = MIN (known_alignment (rounded_1), alignment);
+           }
 #endif
 
          nonzero &= ~(alignment - 1);
@@ -4354,9 +4874,8 @@ nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
 
       {
        unsigned HOST_WIDE_INT nonzero_for_hook = nonzero;
-       rtx new_rtx = rtl_hooks.reg_nonzero_bits (x, mode, known_x,
-                                             known_mode, known_ret,
-                                             &nonzero_for_hook);
+       rtx new_rtx = rtl_hooks.reg_nonzero_bits (x, xmode, mode,
+                                                 &nonzero_for_hook);
 
        if (new_rtx)
          nonzero_for_hook &= cached_nonzero_bits (new_rtx, mode, known_x,
@@ -4365,22 +4884,12 @@ nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
        return nonzero_for_hook;
       }
 
-    case CONST_INT:
-      /* If X is negative in MODE, sign-extend the value.  */
-      if (SHORT_IMMEDIATES_SIGN_EXTEND && INTVAL (x) > 0
-         && mode_width < BITS_PER_WORD
-         && (UINTVAL (x) & (HOST_WIDE_INT_1U << (mode_width - 1)))
-            != 0)
-       return UINTVAL (x) | (HOST_WIDE_INT_M1U << mode_width);
-
-      return UINTVAL (x);
-
     case MEM:
       /* In many, if not most, RISC machines, reading a byte from memory
         zeros the rest of the register.  Noticing that fact saves a lot
         of extra zero-extends.  */
-      if (load_extend_op (GET_MODE (x)) == ZERO_EXTEND)
-       nonzero &= GET_MODE_MASK (GET_MODE (x));
+      if (load_extend_op (xmode) == ZERO_EXTEND)
+       nonzero &= GET_MODE_MASK (xmode);
       break;
 
     case EQ:  case NE:
@@ -4397,7 +4906,7 @@ nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
         operation in, and not the actual operation mode.  We can wind
         up with (subreg:DI (gt:V4HI x y)), and we don't have anything
         that describes the results of a vector compare.  */
-      if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT
+      if (GET_MODE_CLASS (xmode) == MODE_INT
          && mode_width <= HOST_BITS_PER_WIDE_INT)
        nonzero = STORE_FLAG_VALUE;
       break;
@@ -4406,21 +4915,19 @@ nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
 #if 0
       /* Disabled to avoid exponential mutual recursion between nonzero_bits
         and num_sign_bit_copies.  */
-      if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
-         == GET_MODE_PRECISION (GET_MODE (x)))
+      if (num_sign_bit_copies (XEXP (x, 0), xmode) == xmode_width)
        nonzero = 1;
 #endif
 
-      if (GET_MODE_PRECISION (GET_MODE (x)) < mode_width)
-       nonzero |= (GET_MODE_MASK (mode) & ~GET_MODE_MASK (GET_MODE (x)));
+      if (xmode_width < mode_width)
+       nonzero |= (GET_MODE_MASK (mode) & ~GET_MODE_MASK (xmode));
       break;
 
     case ABS:
 #if 0
       /* Disabled to avoid exponential mutual recursion between nonzero_bits
         and num_sign_bit_copies.  */
-      if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
-         == GET_MODE_PRECISION (GET_MODE (x)))
+      if (num_sign_bit_copies (XEXP (x, 0), xmode) == xmode_width)
        nonzero = 1;
 #endif
       break;
@@ -4493,7 +5000,7 @@ nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
        unsigned HOST_WIDE_INT nz1
          = cached_nonzero_bits (XEXP (x, 1), mode,
                                 known_x, known_mode, known_ret);
-       int sign_index = GET_MODE_PRECISION (GET_MODE (x)) - 1;
+       int sign_index = xmode_width - 1;
        int width0 = floor_log2 (nz0) + 1;
        int width1 = floor_log2 (nz1) + 1;
        int low0 = ctz_or_zero (nz0);
@@ -4565,44 +5072,48 @@ nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
         been zero-extended, we know that at least the high-order bits
         are zero, though others might be too.  */
       if (SUBREG_PROMOTED_VAR_P (x) && SUBREG_PROMOTED_UNSIGNED_P (x))
-       nonzero = GET_MODE_MASK (GET_MODE (x))
-                 & cached_nonzero_bits (SUBREG_REG (x), GET_MODE (x),
+       nonzero = GET_MODE_MASK (xmode)
+                 & cached_nonzero_bits (SUBREG_REG (x), xmode,
                                         known_x, known_mode, known_ret);
 
       /* If the inner mode is a single word for both the host and target
         machines, we can compute this from which bits of the inner
         object might be nonzero.  */
       inner_mode = GET_MODE (SUBREG_REG (x));
-      if (GET_MODE_PRECISION (inner_mode) <= BITS_PER_WORD
-         && GET_MODE_PRECISION (inner_mode) <= HOST_BITS_PER_WIDE_INT)
+      if (GET_MODE_PRECISION (inner_mode).is_constant (&inner_width)
+         && inner_width <= BITS_PER_WORD
+         && inner_width <= HOST_BITS_PER_WIDE_INT)
        {
          nonzero &= cached_nonzero_bits (SUBREG_REG (x), mode,
                                          known_x, known_mode, known_ret);
 
-          /* On many CISC machines, accessing an object in a wider mode
+          /* On a typical CISC machine, accessing an object in a wider mode
             causes the high-order bits to become undefined.  So they are
-            not known to be zero.  */
+            not known to be zero.
+
+            On a typical RISC machine, we only have to worry about the way
+            loads are extended.  Otherwise, if we get a reload for the inner
+            part, it may be loaded from the stack, and then we may lose all
+            the zero bits that existed before the store to the stack.  */
          rtx_code extend_op;
          if ((!WORD_REGISTER_OPERATIONS
-              /* If this is a typical RISC machine, we only have to worry
-                 about the way loads are extended.  */
               || ((extend_op = load_extend_op (inner_mode)) == SIGN_EXTEND
                   ? val_signbit_known_set_p (inner_mode, nonzero)
                   : extend_op != ZERO_EXTEND)
-              || (!MEM_P (SUBREG_REG (x)) && !REG_P (SUBREG_REG (x))))
-             && GET_MODE_PRECISION (GET_MODE (x))
-                 > GET_MODE_PRECISION (inner_mode))
+              || !MEM_P (SUBREG_REG (x)))
+             && xmode_width > inner_width)
            nonzero
              |= (GET_MODE_MASK (GET_MODE (x)) & ~GET_MODE_MASK (inner_mode));
        }
       break;
 
+    case ASHIFT:
     case ASHIFTRT:
     case LSHIFTRT:
-    case ASHIFT:
     case ROTATE:
+    case ROTATERT:
       /* The nonzero bits are in two classes: any bits within MODE
-        that aren't in GET_MODE (x) are always significant.  The rest of the
+        that aren't in xmode are always significant.  The rest of the
         nonzero bits are those that are significant in the operand of
         the shift when shifted the appropriate number of bits.  This
         shows that high-order bits are cleared by the right shift and
@@ -4610,39 +5121,55 @@ nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
       if (CONST_INT_P (XEXP (x, 1))
          && INTVAL (XEXP (x, 1)) >= 0
          && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT
-         && INTVAL (XEXP (x, 1)) < GET_MODE_PRECISION (GET_MODE (x)))
+         && INTVAL (XEXP (x, 1)) < xmode_width)
        {
-         machine_mode inner_mode = GET_MODE (x);
-         unsigned int width = GET_MODE_PRECISION (inner_mode);
          int count = INTVAL (XEXP (x, 1));
-         unsigned HOST_WIDE_INT mode_mask = GET_MODE_MASK (inner_mode);
+         unsigned HOST_WIDE_INT mode_mask = GET_MODE_MASK (xmode);
          unsigned HOST_WIDE_INT op_nonzero
            = cached_nonzero_bits (XEXP (x, 0), mode,
                                   known_x, known_mode, known_ret);
          unsigned HOST_WIDE_INT inner = op_nonzero & mode_mask;
          unsigned HOST_WIDE_INT outer = 0;
 
-         if (mode_width > width)
+         if (mode_width > xmode_width)
            outer = (op_nonzero & nonzero & ~mode_mask);
 
-         if (code == LSHIFTRT)
-           inner >>= count;
-         else if (code == ASHIFTRT)
+         switch (code)
            {
+           case ASHIFT:
+             inner <<= count;
+             break;
+
+           case LSHIFTRT:
+             inner >>= count;
+             break;
+
+           case ASHIFTRT:
              inner >>= count;
 
              /* If the sign bit may have been nonzero before the shift, we
                 need to mark all the places it could have been copied to
                 by the shift as possibly nonzero.  */
-             if (inner & (HOST_WIDE_INT_1U << (width - 1 - count)))
-               inner |= ((HOST_WIDE_INT_1U << count) - 1)
-                          << (width - count);
+             if (inner & (HOST_WIDE_INT_1U << (xmode_width - 1 - count)))
+               inner |= (((HOST_WIDE_INT_1U << count) - 1)
+                         << (xmode_width - count));
+             break;
+
+           case ROTATE:
+             inner = (inner << (count % xmode_width)
+                      | (inner >> (xmode_width - (count % xmode_width))))
+                     & mode_mask;
+             break;
+
+           case ROTATERT:
+             inner = (inner >> (count % xmode_width)
+                      | (inner << (xmode_width - (count % xmode_width))))
+                     & mode_mask;
+             break;
+
+           default:
+             gcc_unreachable ();
            }
-         else if (code == ASHIFT)
-           inner <<= count;
-         else
-           inner = ((inner << (count % width)
-                     | (inner >> (width - (count % width)))) & mode_mask);
 
          nonzero &= (outer | inner);
        }
@@ -4741,8 +5268,8 @@ num_sign_bit_copies_binary_arith_p (const_rtx x)
    first or the second level.  */
 
 static unsigned int
-cached_num_sign_bit_copies (const_rtx x, machine_mode mode, const_rtx known_x,
-                           machine_mode known_mode,
+cached_num_sign_bit_copies (const_rtx x, scalar_int_mode mode,
+                           const_rtx known_x, machine_mode known_mode,
                            unsigned int known_ret)
 {
   if (x == known_x && mode == known_mode)
@@ -4787,54 +5314,59 @@ cached_num_sign_bit_copies (const_rtx x, machine_mode mode, const_rtx known_x,
 }
 
 /* Return the number of bits at the high-order end of X that are known to
-   be equal to the sign bit.  X will be used in mode MODE; if MODE is
-   VOIDmode, X will be used in its own mode.  The returned value  will always
-   be between 1 and the number of bits in MODE.  */
+   be equal to the sign bit.  X will be used in mode MODE.  The returned
+   value will always be between 1 and the number of bits in MODE.  */
 
 static unsigned int
-num_sign_bit_copies1 (const_rtx x, machine_mode mode, const_rtx known_x,
+num_sign_bit_copies1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
                      machine_mode known_mode,
                      unsigned int known_ret)
 {
   enum rtx_code code = GET_CODE (x);
-  machine_mode inner_mode;
+  unsigned int bitwidth = GET_MODE_PRECISION (mode);
   int num0, num1, result;
   unsigned HOST_WIDE_INT nonzero;
 
-  /* If we weren't given a mode, use the mode of X.  If the mode is still
-     VOIDmode, we don't know anything.  Likewise if one of the modes is
-     floating-point.  */
+  if (CONST_INT_P (x))
+    {
+      /* If the constant is negative, take its 1's complement and remask.
+        Then see how many zero bits we have.  */
+      nonzero = UINTVAL (x) & GET_MODE_MASK (mode);
+      if (bitwidth <= HOST_BITS_PER_WIDE_INT
+         && (nonzero & (HOST_WIDE_INT_1U << (bitwidth - 1))) != 0)
+       nonzero = (~nonzero) & GET_MODE_MASK (mode);
 
-  if (mode == VOIDmode)
-    mode = GET_MODE (x);
+      return (nonzero == 0 ? bitwidth : bitwidth - floor_log2 (nonzero) - 1);
+    }
 
-  if (mode == VOIDmode || FLOAT_MODE_P (mode) || FLOAT_MODE_P (GET_MODE (x))
-      || VECTOR_MODE_P (GET_MODE (x)) || VECTOR_MODE_P (mode))
+  scalar_int_mode xmode, inner_mode;
+  if (!is_a <scalar_int_mode> (GET_MODE (x), &xmode))
     return 1;
 
+  unsigned int xmode_width = GET_MODE_PRECISION (xmode);
+
   /* For a smaller mode, just ignore the high bits.  */
-  unsigned int bitwidth = GET_MODE_PRECISION (mode);
-  if (bitwidth < GET_MODE_PRECISION (GET_MODE (x)))
+  if (bitwidth < xmode_width)
     {
-      num0 = cached_num_sign_bit_copies (x, GET_MODE (x),
+      num0 = cached_num_sign_bit_copies (x, xmode,
                                         known_x, known_mode, known_ret);
-      return MAX (1,
-                 num0 - (int) (GET_MODE_PRECISION (GET_MODE (x)) - bitwidth));
+      return MAX (1, num0 - (int) (xmode_width - bitwidth));
     }
 
-  if (GET_MODE (x) != VOIDmode && bitwidth > GET_MODE_PRECISION (GET_MODE (x)))
+  if (bitwidth > xmode_width)
     {
       /* If this machine does not do all register operations on the entire
         register and MODE is wider than the mode of X, we can say nothing
-        at all about the high-order bits.  */
-      if (!WORD_REGISTER_OPERATIONS)
+        at all about the high-order bits.  We extend this reasoning to RISC
+        machines for operations that might not operate on full registers.  */
+      if (!(WORD_REGISTER_OPERATIONS && word_register_operation_p (x)))
        return 1;
 
       /* Likewise on machines that do, if the mode of the object is smaller
         than a word and loads of that size don't sign extend, we can say
         nothing about the high order bits.  */
-      if (GET_MODE_PRECISION (GET_MODE (x)) < BITS_PER_WORD
-         && load_extend_op (GET_MODE (x)) != SIGN_EXTEND)
+      if (xmode_width < BITS_PER_WORD
+         && load_extend_op (xmode) != SIGN_EXTEND)
        return 1;
     }
 
@@ -4851,7 +5383,7 @@ num_sign_bit_copies1 (const_rtx x, machine_mode mode, const_rtx known_x,
         we can do this only if the target does not support different pointer
         or address modes depending on the address space.  */
       if (target_default_pointer_address_modes_p ()
-         && ! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
+         && ! POINTERS_EXTEND_UNSIGNED && xmode == Pmode
          && mode == Pmode && REG_POINTER (x)
          && !targetm.have_ptr_extend ())
        return GET_MODE_PRECISION (Pmode) - GET_MODE_PRECISION (ptr_mode) + 1;
@@ -4859,9 +5391,8 @@ num_sign_bit_copies1 (const_rtx x, machine_mode mode, const_rtx known_x,
 
       {
        unsigned int copies_for_hook = 1, copies = 1;
-       rtx new_rtx = rtl_hooks.reg_num_sign_bit_copies (x, mode, known_x,
-                                                    known_mode, known_ret,
-                                                    &copies_for_hook);
+       rtx new_rtx = rtl_hooks.reg_num_sign_bit_copies (x, xmode, mode,
+                                                        &copies_for_hook);
 
        if (new_rtx)
          copies = cached_num_sign_bit_copies (new_rtx, mode, known_x,
@@ -4876,21 +5407,10 @@ num_sign_bit_copies1 (const_rtx x, machine_mode mode, const_rtx known_x,
 
     case MEM:
       /* Some RISC machines sign-extend all loads of smaller than a word.  */
-      if (load_extend_op (GET_MODE (x)) == SIGN_EXTEND)
-       return MAX (1, ((int) bitwidth
-                       - (int) GET_MODE_PRECISION (GET_MODE (x)) + 1));
+      if (load_extend_op (xmode) == SIGN_EXTEND)
+       return MAX (1, ((int) bitwidth - (int) xmode_width + 1));
       break;
 
-    case CONST_INT:
-      /* If the constant is negative, take its 1's complement and remask.
-        Then see how many zero bits we have.  */
-      nonzero = UINTVAL (x) & GET_MODE_MASK (mode);
-      if (bitwidth <= HOST_BITS_PER_WIDE_INT
-         && (nonzero & (HOST_WIDE_INT_1U << (bitwidth - 1))) != 0)
-       nonzero = (~nonzero) & GET_MODE_MASK (mode);
-
-      return (nonzero == 0 ? bitwidth : bitwidth - floor_log2 (nonzero) - 1);
-
     case SUBREG:
       /* If this is a SUBREG for a promoted object that is sign-extended
         and we are looking at it in a wider mode, we know that at least the
@@ -4900,37 +5420,37 @@ num_sign_bit_copies1 (const_rtx x, machine_mode mode, const_rtx known_x,
        {
          num0 = cached_num_sign_bit_copies (SUBREG_REG (x), mode,
                                             known_x, known_mode, known_ret);
-         return MAX ((int) bitwidth
-                     - (int) GET_MODE_PRECISION (GET_MODE (x)) + 1,
-                     num0);
+         return MAX ((int) bitwidth - (int) xmode_width + 1, num0);
        }
 
-      /* For a smaller object, just ignore the high bits.  */
-      inner_mode = GET_MODE (SUBREG_REG (x));
-      if (bitwidth <= GET_MODE_PRECISION (inner_mode))
+      if (is_a <scalar_int_mode> (GET_MODE (SUBREG_REG (x)), &inner_mode))
        {
-         num0 = cached_num_sign_bit_copies (SUBREG_REG (x), VOIDmode,
-                                            known_x, known_mode, known_ret);
-         return
-           MAX (1, num0 - (int) (GET_MODE_PRECISION (inner_mode) - bitwidth));
-       }
+         /* For a smaller object, just ignore the high bits.  */
+         if (bitwidth <= GET_MODE_PRECISION (inner_mode))
+           {
+             num0 = cached_num_sign_bit_copies (SUBREG_REG (x), inner_mode,
+                                                known_x, known_mode,
+                                                known_ret);
+             return MAX (1, num0 - (int) (GET_MODE_PRECISION (inner_mode)
+                                          - bitwidth));
+           }
 
-      /* For paradoxical SUBREGs on machines where all register operations
-        affect the entire register, just look inside.  Note that we are
-        passing MODE to the recursive call, so the number of sign bit copies
-        will remain relative to that mode, not the inner mode.  */
-
-      /* This works only if loads sign extend.  Otherwise, if we get a
-        reload for the inner part, it may be loaded from the stack, and
-        then we lose all sign bit copies that existed before the store
-        to the stack.  */
-
-      if (WORD_REGISTER_OPERATIONS
-         && load_extend_op (inner_mode) == SIGN_EXTEND
-         && paradoxical_subreg_p (x)
-         && (MEM_P (SUBREG_REG (x)) || REG_P (SUBREG_REG (x))))
-       return cached_num_sign_bit_copies (SUBREG_REG (x), mode,
-                                          known_x, known_mode, known_ret);
+         /* For paradoxical SUBREGs on machines where all register operations
+            affect the entire register, just look inside.  Note that we are
+            passing MODE to the recursive call, so the number of sign bit
+            copies will remain relative to that mode, not the inner mode.
+
+            This works only if loads sign extend.  Otherwise, if we get a
+            reload for the inner part, it may be loaded from the stack, and
+            then we lose all sign bit copies that existed before the store
+            to the stack.  */
+         if (WORD_REGISTER_OPERATIONS
+             && load_extend_op (inner_mode) == SIGN_EXTEND
+             && paradoxical_subreg_p (x)
+             && MEM_P (SUBREG_REG (x)))
+           return cached_num_sign_bit_copies (SUBREG_REG (x), mode,
+                                              known_x, known_mode, known_ret);
+       }
       break;
 
     case SIGN_EXTRACT:
@@ -4939,15 +5459,18 @@ num_sign_bit_copies1 (const_rtx x, machine_mode mode, const_rtx known_x,
       break;
 
     case SIGN_EXTEND:
-      return (bitwidth - GET_MODE_PRECISION (GET_MODE (XEXP (x, 0)))
-             + cached_num_sign_bit_copies (XEXP (x, 0), VOIDmode,
-                                           known_x, known_mode, known_ret));
+      if (is_a <scalar_int_mode> (GET_MODE (XEXP (x, 0)), &inner_mode))
+       return (bitwidth - GET_MODE_PRECISION (inner_mode)
+               + cached_num_sign_bit_copies (XEXP (x, 0), inner_mode,
+                                             known_x, known_mode, known_ret));
+      break;
 
     case TRUNCATE:
       /* For a smaller object, just ignore the high bits.  */
-      num0 = cached_num_sign_bit_copies (XEXP (x, 0), VOIDmode,
+      inner_mode = as_a <scalar_int_mode> (GET_MODE (XEXP (x, 0)));
+      num0 = cached_num_sign_bit_copies (XEXP (x, 0), inner_mode,
                                         known_x, known_mode, known_ret);
-      return MAX (1, (num0 - (int) (GET_MODE_PRECISION (GET_MODE (XEXP (x, 0)))
+      return MAX (1, (num0 - (int) (GET_MODE_PRECISION (inner_mode)
                                    - bitwidth)));
 
     case NOT:
@@ -5124,7 +5647,7 @@ num_sign_bit_copies1 (const_rtx x, machine_mode mode, const_rtx known_x,
                                         known_x, known_mode, known_ret);
       if (CONST_INT_P (XEXP (x, 1))
          && INTVAL (XEXP (x, 1)) > 0
-         && INTVAL (XEXP (x, 1)) < GET_MODE_PRECISION (GET_MODE (x)))
+         && INTVAL (XEXP (x, 1)) < xmode_width)
        num0 = MIN ((int) bitwidth, num0 + INTVAL (XEXP (x, 1)));
 
       return num0;
@@ -5134,7 +5657,7 @@ num_sign_bit_copies1 (const_rtx x, machine_mode mode, const_rtx known_x,
       if (!CONST_INT_P (XEXP (x, 1))
          || INTVAL (XEXP (x, 1)) < 0
          || INTVAL (XEXP (x, 1)) >= (int) bitwidth
-         || INTVAL (XEXP (x, 1)) >= GET_MODE_PRECISION (GET_MODE (x)))
+         || INTVAL (XEXP (x, 1)) >= xmode_width)
        return 1;
 
       num0 = cached_num_sign_bit_copies (XEXP (x, 0), mode,
@@ -5179,32 +5702,50 @@ num_sign_bit_copies1 (const_rtx x, machine_mode mode, const_rtx known_x,
         ? 1 : bitwidth - floor_log2 (nonzero) - 1;
 }
 
-/* Calculate the rtx_cost of a single instruction.  A return value of
+/* Calculate the rtx_cost of a single instruction pattern.  A return value of
    zero indicates an instruction pattern without a known cost.  */
 
 int
-insn_rtx_cost (rtx pat, bool speed)
+pattern_cost (rtx pat, bool speed)
 {
   int i, cost;
   rtx set;
 
-  /* Extract the single set rtx from the instruction pattern.
-     We can't use single_set since we only have the pattern.  */
+  /* Extract the single set rtx from the instruction pattern.  We
+     can't use single_set since we only have the pattern.  We also
+     consider PARALLELs of a normal set and a single comparison.  In
+     that case we use the cost of the non-comparison SET operation,
+     which is most-likely to be the real cost of this operation.  */
   if (GET_CODE (pat) == SET)
     set = pat;
   else if (GET_CODE (pat) == PARALLEL)
     {
       set = NULL_RTX;
+      rtx comparison = NULL_RTX;
+
       for (i = 0; i < XVECLEN (pat, 0); i++)
        {
          rtx x = XVECEXP (pat, 0, i);
          if (GET_CODE (x) == SET)
            {
-             if (set)
-               return 0;
-             set = x;
+             if (GET_CODE (SET_SRC (x)) == COMPARE)
+               {
+                 if (comparison)
+                   return 0;
+                 comparison = x;
+               }
+             else
+               {
+                 if (set)
+                   return 0;
+                 set = x;
+               }
            }
        }
+
+      if (!set && comparison)
+       set = comparison;
+
       if (!set)
        return 0;
     }
@@ -5215,6 +5756,18 @@ insn_rtx_cost (rtx pat, bool speed)
   return cost > 0 ? cost : COSTS_N_INSNS (1);
 }
 
+/* Calculate the cost of a single instruction.  A return value of zero
+   indicates an instruction pattern without a known cost.  */
+
+int
+insn_cost (rtx_insn *insn, bool speed)
+{
+  if (targetm.insn_cost)
+    return targetm.insn_cost (insn, speed);
+
+  return pattern_cost (PATTERN (insn), speed);
+}
+
 /* Returns estimate on cost of computing SEQ.  */
 
 unsigned
@@ -5228,8 +5781,14 @@ seq_cost (const rtx_insn *seq, bool speed)
       set = single_set (seq);
       if (set)
         cost += set_rtx_cost (set, speed);
-      else
-        cost++;
+      else if (NONDEBUG_INSN_P (seq))
+       {
+         int this_cost = insn_cost (CONST_CAST_RTX_INSN (seq), speed);
+         if (this_cost > 0)
+           cost += this_cost;
+         else
+           cost++;
+       }
     }
 
   return cost;
@@ -5466,40 +6025,39 @@ canonicalize_condition (rtx_insn *insn, rtx cond, int reverse,
      if we can do computations in the relevant mode and we do not
      overflow.  */
 
-  if (GET_MODE_CLASS (GET_MODE (op0)) != MODE_CC
-      && CONST_INT_P (op1)
-      && GET_MODE (op0) != VOIDmode
-      && GET_MODE_PRECISION (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
+  scalar_int_mode op0_mode;
+  if (CONST_INT_P (op1)
+      && is_a <scalar_int_mode> (GET_MODE (op0), &op0_mode)
+      && GET_MODE_PRECISION (op0_mode) <= HOST_BITS_PER_WIDE_INT)
     {
       HOST_WIDE_INT const_val = INTVAL (op1);
       unsigned HOST_WIDE_INT uconst_val = const_val;
       unsigned HOST_WIDE_INT max_val
-       = (unsigned HOST_WIDE_INT) GET_MODE_MASK (GET_MODE (op0));
+       = (unsigned HOST_WIDE_INT) GET_MODE_MASK (op0_mode);
 
       switch (code)
        {
        case LE:
          if ((unsigned HOST_WIDE_INT) const_val != max_val >> 1)
-           code = LT, op1 = gen_int_mode (const_val + 1, GET_MODE (op0));
+           code = LT, op1 = gen_int_mode (const_val + 1, op0_mode);
          break;
 
        /* When cross-compiling, const_val might be sign-extended from
           BITS_PER_WORD to HOST_BITS_PER_WIDE_INT */
        case GE:
          if ((const_val & max_val)
-             != (HOST_WIDE_INT_1U
-                 << (GET_MODE_PRECISION (GET_MODE (op0)) - 1)))
-           code = GT, op1 = gen_int_mode (const_val - 1, GET_MODE (op0));
+             != (HOST_WIDE_INT_1U << (GET_MODE_PRECISION (op0_mode) - 1)))
+           code = GT, op1 = gen_int_mode (const_val - 1, op0_mode);
          break;
 
        case LEU:
          if (uconst_val < max_val)
-           code = LTU, op1 = gen_int_mode (uconst_val + 1, GET_MODE (op0));
+           code = LTU, op1 = gen_int_mode (uconst_val + 1, op0_mode);
          break;
 
        case GEU:
          if (uconst_val != 0)
-           code = GTU, op1 = gen_int_mode (uconst_val - 1, GET_MODE (op0));
+           code = GTU, op1 = gen_int_mode (uconst_val - 1, op0_mode);
          break;
 
        default:
@@ -5511,7 +6069,11 @@ canonicalize_condition (rtx_insn *insn, rtx cond, int reverse,
   if (CC0_P (op0))
     return 0;
 
-  return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
+  /* We promised to return a comparison.  */
+  rtx ret = gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
+  if (COMPARISON_P (ret))
+    return ret;
+  return 0;
 }
 
 /* Given a jump insn JUMP, return the condition that will cause it to branch
@@ -5568,25 +6130,27 @@ get_condition (rtx_insn *jump, rtx_insn **earliest, int allow_cc_mode,
 static void
 init_num_sign_bit_copies_in_rep (void)
 {
-  machine_mode mode, in_mode;
+  opt_scalar_int_mode in_mode_iter;
+  scalar_int_mode mode;
 
-  for (in_mode = GET_CLASS_NARROWEST_MODE (MODE_INT); in_mode != VOIDmode;
-       in_mode = GET_MODE_WIDER_MODE (mode))
-    for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != in_mode;
-        mode = GET_MODE_WIDER_MODE (mode))
+  FOR_EACH_MODE_IN_CLASS (in_mode_iter, MODE_INT)
+    FOR_EACH_MODE_UNTIL (mode, in_mode_iter.require ())
       {
-       machine_mode i;
+       scalar_int_mode in_mode = in_mode_iter.require ();
+       scalar_int_mode i;
 
        /* Currently, it is assumed that TARGET_MODE_REP_EXTENDED
           extends to the next widest mode.  */
        gcc_assert (targetm.mode_rep_extended (mode, in_mode) == UNKNOWN
-                   || GET_MODE_WIDER_MODE (mode) == in_mode);
+                   || GET_MODE_WIDER_MODE (mode).require () == in_mode);
 
        /* We are in in_mode.  Count how many bits outside of mode
           have to be copies of the sign-bit.  */
-       for (i = mode; i != in_mode; i = GET_MODE_WIDER_MODE (i))
+       FOR_EACH_MODE (i, mode, in_mode)
          {
-           machine_mode wider = GET_MODE_WIDER_MODE (i);
+           /* This must always exist (for the last iteration it will be
+              IN_MODE).  */
+           scalar_int_mode wider = GET_MODE_WIDER_MODE (i).require ();
 
            if (targetm.mode_rep_extended (i, wider) == SIGN_EXTEND
                /* We can only check sign-bit copies starting from the
@@ -5689,7 +6253,7 @@ low_bitmask_len (machine_mode mode, unsigned HOST_WIDE_INT m)
 {
   if (mode != VOIDmode)
     {
-      if (GET_MODE_PRECISION (mode) > HOST_BITS_PER_WIDE_INT)
+      if (!HWI_COMPUTABLE_MODE_P (mode))
        return -1;
       m &= GET_MODE_MASK (mode);
     }
@@ -5699,7 +6263,7 @@ low_bitmask_len (machine_mode mode, unsigned HOST_WIDE_INT m)
 
 /* Return the mode of MEM's address.  */
 
-machine_mode
+scalar_int_mode
 get_address_mode (rtx mem)
 {
   machine_mode mode;
@@ -5707,7 +6271,7 @@ get_address_mode (rtx mem)
   gcc_assert (MEM_P (mem));
   mode = GET_MODE (XEXP (mem, 0));
   if (mode != VOIDmode)
-    return mode;
+    return as_a <scalar_int_mode> (mode);
   return targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem));
 }
 \f
@@ -5882,8 +6446,9 @@ lsb_bitfield_op_p (rtx x)
       machine_mode mode = GET_MODE (XEXP (x, 0));
       HOST_WIDE_INT len = INTVAL (XEXP (x, 1));
       HOST_WIDE_INT pos = INTVAL (XEXP (x, 2));
+      poly_int64 remaining_bits = GET_MODE_PRECISION (mode) - len;
 
-      return (pos == (BITS_BIG_ENDIAN ? GET_MODE_PRECISION (mode) - len : 0));
+      return known_eq (pos, BITS_BIG_ENDIAN ? remaining_bits : 0);
     }
   return false;
 }
@@ -6315,6 +6880,20 @@ contains_symbolic_reference_p (const_rtx x)
   return false;
 }
 
+/* Return true if RTL X contains a constant pool address.  */
+
+bool
+contains_constant_pool_address_p (const_rtx x)
+{
+  subrtx_iterator::array_type array;
+  FOR_EACH_SUBRTX (iter, array, x, ALL)
+    if (SYMBOL_REF_P (*iter) && CONSTANT_POOL_ADDRESS_P (*iter))
+      return true;
+
+  return false;
+}
+
+
 /* Return true if X contains a thread-local symbol.  */
 
 bool
@@ -6329,3 +6908,41 @@ tls_referenced_p (const_rtx x)
       return true;
   return false;
 }
+
+/* Process recursively X of INSN and add REG_INC notes if necessary.  */
+void
+add_auto_inc_notes (rtx_insn *insn, rtx x)
+{
+  enum rtx_code code = GET_CODE (x);
+  const char *fmt;
+  int i, j;
+
+  if (code == MEM && auto_inc_p (XEXP (x, 0)))
+    {
+      add_reg_note (insn, REG_INC, XEXP (XEXP (x, 0), 0));
+      return;
+    }
+
+  /* Scan all X sub-expressions.  */
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       add_auto_inc_notes (insn, XEXP (x, i));
+      else if (fmt[i] == 'E')
+       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         add_auto_inc_notes (insn, XVECEXP (x, i, j));
+    }
+}
+
+/* Return true if X is register asm.  */
+
+bool
+register_asm_p (const_rtx x)
+{
+  return (REG_P (x)
+         && REG_EXPR (x) != NULL_TREE
+         && HAS_DECL_ASSEMBLER_NAME_P (REG_EXPR (x))
+         && DECL_ASSEMBLER_NAME_SET_P (REG_EXPR (x))
+         && DECL_REGISTER (REG_EXPR (x)));
+}