c-ada-spec.c (dump_ada_double_name): New case.
[gcc.git] / gcc / rtlanal.c
index 560bfd43c1cfa330c1756de641e5341ebc6003b6..ac3662de3ce0c9fcb58a042138f461c538fc1522 100644 (file)
@@ -1,5 +1,5 @@
 /* Analyze RTL for GNU compiler.
-   Copyright (C) 1987-2017 Free Software Foundation, Inc.
+   Copyright (C) 1987-2018 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -344,7 +344,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
@@ -352,7 +352,7 @@ 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)
@@ -457,16 +457,17 @@ 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));
 
   /* 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
@@ -477,7 +478,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;
     }
 
@@ -489,14 +490,12 @@ rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT size,
       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.  */
@@ -507,9 +506,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)))
@@ -517,7 +517,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)
+                 : maybe_gt (offset + size, decl_size));
         }
 
       return 0;
@@ -534,17 +536,14 @@ 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)
@@ -562,10 +561,10 @@ rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT 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);
 
@@ -589,7 +588,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);
 
@@ -629,7 +628,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;
        }
@@ -649,7 +649,7 @@ rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT size,
       if (XEXP (x, 0) == pic_offset_table_rtx
          && GET_CODE (XEXP (x, 1)) == CONST
          && GET_CODE (XEXP (XEXP (x, 1), 0)) == UNSPEC
-         && offset == 0)
+         && known_eq (offset, 0))
        return 0;
 
       /* - or it is an address that can't trap plus a constant integer.  */
@@ -686,7 +686,7 @@ 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.  */
@@ -915,6 +915,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.  */
@@ -1124,10 +1155,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;
@@ -1367,13 +1395,15 @@ modified_in_p (const_rtx x, const_rtx insn)
 bool
 read_modify_subreg_p (const_rtx x)
 {
-  unsigned int isize, osize;
   if (GET_CODE (x) != SUBREG)
     return false;
-  isize = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
-  osize = GET_MODE_SIZE (GET_MODE (x));
-  return isize > osize
-        && isize > REGMODE_NATURAL_SIZE (GET_MODE (SUBREG_REG (x)));
+  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.  */
@@ -1567,7 +1597,7 @@ 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);
@@ -2017,20 +2047,16 @@ dead_or_set_p (const rtx_insn *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))
@@ -2089,7 +2115,7 @@ dead_or_set_regno_p (const rtx_insn *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)
     {
@@ -2347,6 +2373,15 @@ add_int_reg_note (rtx_insn *insn, enum reg_note kind, int datum)
                                       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
@@ -2781,7 +2816,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);
        }
@@ -3311,7 +3346,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);
@@ -3320,7 +3355,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);
@@ -3413,13 +3448,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);
 
@@ -3427,13 +3464,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:
@@ -3538,48 +3577,50 @@ loc_mentioned_in_p (rtx *loc, const_rtx in)
    and SUBREG_BYTE, return the bit offset where the subreg begins
    (counting from the least significant bit of the operand).  */
 
-unsigned int
+poly_uint64
 subreg_lsb_1 (machine_mode outer_mode,
              machine_mode inner_mode,
-             unsigned int subreg_byte)
+             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 (paradoxical_subreg_p (outer_mode, 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;
-
-  if (BYTES_BIG_ENDIAN)
-    byte = (GET_MODE_SIZE (inner_mode)
-           - (subreg_byte + GET_MODE_SIZE (outer_mode))) % UNITS_PER_WORD;
+  subreg_end = subreg_byte + GET_MODE_SIZE (outer_mode);
+  trailing_bytes = GET_MODE_SIZE (inner_mode) - 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)),
@@ -3592,29 +3633,32 @@ subreg_lsb (const_rtx x)
    lsb of the inner value.  This is the inverse of the calculation
    performed by subreg_lsb_1 (which converts byte offsets to bit shifts).  */
 
-unsigned int
-subreg_size_offset_from_lsb (unsigned int outer_bytes,
-                            unsigned int inner_bytes,
-                            unsigned int lsb_shift)
+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.  */
-  if (outer_bytes > inner_bytes)
+  gcc_checking_assert (ordered_p (outer_bytes, inner_bytes));
+  if (maybe_gt (outer_bytes, inner_bytes))
     {
-      gcc_checking_assert (lsb_shift == 0);
+      gcc_checking_assert (known_eq (lsb_shift, 0U));
       return 0;
     }
 
-  gcc_assert (lsb_shift % BITS_PER_UNIT == 0);
-  unsigned int lower_bytes = lsb_shift / BITS_PER_UNIT;
-  unsigned int upper_bytes = inner_bytes - (lower_bytes + outer_bytes);
+  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
     {
-      unsigned int lower_word_part = lower_bytes & -UNITS_PER_WORD;
-      unsigned int upper_word_part = upper_bytes & -UNITS_PER_WORD;
+      /* 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
@@ -3643,15 +3687,16 @@ subreg_size_offset_from_lsb (unsigned int outer_bytes,
 
 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)
 {
   unsigned int nregs_xmode, nregs_ymode;
 
   gcc_assert (xregno < FIRST_PSEUDO_REGISTER);
 
-  unsigned int xsize = GET_MODE_SIZE (xmode);
-  unsigned int ysize = GET_MODE_SIZE (ymode);
+  poly_uint64 xsize = GET_MODE_SIZE (xmode);
+  poly_uint64 ysize = GET_MODE_SIZE (ymode);
+
   bool rknown = false;
 
   /* If the register representation of a non-scalar mode has holes in it,
@@ -3660,8 +3705,12 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
      at least one register.  */
   if (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode))
     {
+      /* 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);
-      unsigned int nunits = GET_MODE_NUNITS (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
@@ -3678,9 +3727,9 @@ 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 < nunits)
-         && (offset / GET_MODE_SIZE (xmode_unit)
-             != ((offset + ysize - 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;
@@ -3691,8 +3740,12 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
 
   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 && ysize > xsize)
+  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
@@ -3714,29 +3767,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)
-      && (xsize % nregs_xmode) == 0
-      && (ysize % nregs_ymode) == 0)
+      && multiple_p (xsize, nregs_xmode, &regsize_xmode)
+      && multiple_p (ysize, nregs_ymode, &regsize_ymode))
     {
-      int regsize_xmode = xsize / nregs_xmode;
-      int regsize_ymode = ysize / nregs_ymode;
       if (!rknown
-         && ((nregs_ymode > 1 && regsize_xmode > regsize_ymode)
-             || (nregs_xmode > 1 && regsize_ymode > regsize_xmode)))
+         && ((nregs_ymode > 1 && maybe_gt (regsize_xmode, regsize_ymode))
+             || (nregs_xmode > 1 && maybe_gt (regsize_ymode, regsize_xmode))))
        {
          info->representable_p = false;
-         info->nregs = CEIL (ysize, 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 && ysize + offset > xsize)
+      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
@@ -3744,26 +3802,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;
+         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;
@@ -3783,20 +3842,24 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
      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.  */
-  gcc_assert ((xsize % num_blocks) == 0);
-  unsigned int bytes_per_block = xsize / num_blocks;
+  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 = offset / bytes_per_block;
-  unsigned int subblock_offset = offset % bytes_per_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)
     {
       /* Only the lowpart of each block is representable.  */
       info->representable_p
-       = (subblock_offset
-          == subreg_size_lowpart_offset (ysize, bytes_per_block));
+       = known_eq (subblock_offset,
+                   subreg_size_lowpart_offset (ysize, bytes_per_block));
       rknown = true;
     }
 
@@ -3823,7 +3886,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);
@@ -3839,7 +3902,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);
@@ -3856,7 +3919,7 @@ 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;
@@ -4131,7 +4194,7 @@ rtx_cost (rtx x, machine_mode mode, enum rtx_code outer_code,
 
   /* 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;
+  factor = estimated_poly_value (GET_MODE_SIZE (mode)) / UNITS_PER_WORD;
   if (factor == 0)
     factor = 1;
 
@@ -4162,7 +4225,7 @@ rtx_cost (rtx x, machine_mode mode, enum rtx_code outer_code,
       /* 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;
+      factor = estimated_poly_value (GET_MODE_SIZE (mode)) / UNITS_PER_WORD;
       if (factor == 0)
        factor = 1;
       /* FALLTHRU */
@@ -4366,8 +4429,9 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
 {
   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);
@@ -4401,16 +4465,16 @@ nonzero_bits1 (const_rtx x, scalar_int_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
-      && mode_width > xmode_width
+     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 rotate operations since the
+     semantics of the operations in the larger mode is not well defined.  */
+  if (mode_width > xmode_width
       && xmode_width <= BITS_PER_WORD
-      && xmode_width <= HOST_BITS_PER_WIDE_INT)
+      && xmode_width <= HOST_BITS_PER_WIDE_INT
+      && (!WORD_REGISTER_OPERATIONS || code == ROTATE || code == ROTATERT))
     {
       nonzero &= cached_nonzero_bits (x, xmode,
                                      known_x, known_mode, known_ret);
@@ -4420,7 +4484,6 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
 
   /* 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:
@@ -4455,8 +4518,10 @@ nonzero_bits1 (const_rtx x, scalar_int_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);
@@ -4670,8 +4735,9 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
         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);
@@ -4687,15 +4753,17 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
                   ? val_signbit_known_set_p (inner_mode, nonzero)
                   : extend_op != ZERO_EXTEND)
               || (!MEM_P (SUBREG_REG (x)) && !REG_P (SUBREG_REG (x))))
-             && xmode_width > GET_MODE_PRECISION (inner_mode))
-           nonzero |= (GET_MODE_MASK (xmode) & ~GET_MODE_MASK (inner_mode));
+             && 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 xmode are always significant.  The rest of the
         nonzero bits are those that are significant in the operand of
@@ -4718,10 +4786,17 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
          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
@@ -4730,13 +4805,23 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
              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 % xmode_width)
-                     | (inner >> (xmode_width - (count % xmode_width))))
-                    & mode_mask);
 
          nonzero &= (outer | inner);
        }
@@ -4924,8 +5009,10 @@ num_sign_bit_copies1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
     {
       /* 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 every
+        machine for rotate operations since the semantics of the operations
+        in the larger mode is not well defined.  */
+      if (!WORD_REGISTER_OPERATIONS || code == ROTATE || code == ROTATERT)
        return 1;
 
       /* Likewise on machines that do, if the mode of the object is smaller
@@ -5014,7 +5101,7 @@ num_sign_bit_copies1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
          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))))
+             && MEM_P (SUBREG_REG (x)))
            return cached_num_sign_bit_copies (SUBREG_REG (x), mode,
                                               known_x, known_mode, known_ret);
        }
@@ -5348,8 +5435,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;
@@ -5630,7 +5723,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
@@ -6003,8 +6100,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;
 }