diff gcc/rtlanal.c @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents 04ced10e8804
children 1830386684a0
line wrap: on
line diff
--- a/gcc/rtlanal.c	Fri Oct 27 22:46:09 2017 +0900
+++ b/gcc/rtlanal.c	Thu Oct 25 07:37:49 2018 +0900
@@ -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.
 
@@ -35,6 +35,7 @@
 #include "recog.h"
 #include "addresses.h"
 #include "rtl-iter.h"
+#include "hard-reg-set.h"
 
 /* Forward declarations */
 static void set_of_1 (rtx, const_rtx, void *);
@@ -344,7 +345,7 @@
    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 +353,7 @@
     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 +458,18 @@
    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
@@ -477,7 +480,7 @@
 	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 +492,12 @@
       if (!CONSTANT_POOL_ADDRESS_P (x) && !SYMBOL_REF_FUNCTION_P (x))
 	{
 	  tree decl;
-	  HOST_WIDE_INT decl_size;
-
-	  if (offset < 0)
+	  poly_int64 decl_size;
+
+	  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 +508,10 @@
 	  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 +519,9 @@
 	  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 +538,14 @@
 	 || (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;
-
-	  if (size == 0)
-	    size = GET_MODE_SIZE (mode);
-	  if (size == 0)
+	  poly_int64 stack_boundary = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
+	  poly_int64 low_bound, high_bound;
+
+	  if (!known_size_p (size))
 	    return 1;
 
 	  if (x == frame_pointer_rtx)
@@ -562,10 +563,10 @@
 	    }
 	  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 +590,7 @@
 	    }
 	  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 +630,8 @@
 #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,12 +651,12 @@
       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.  */
-      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;
 
@@ -686,7 +688,7 @@
 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 +917,37 @@
   *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));
+}
 
 /* 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.  */
@@ -1165,6 +1198,10 @@
 	  return 1;
       return 0;
 
+    case CLOBBER_HIGH:
+      gcc_assert (REG_P (XEXP (body, 0)));
+      return 0;
+
     case COND_EXEC:
       if (reg_overlap_mentioned_p (x, COND_EXEC_TEST (body)))
 	return 1;
@@ -1364,13 +1401,15 @@
 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));
 }
 
 /* Helper function for set_of.  */
@@ -1385,7 +1424,11 @@
 {
   struct set_of_data *const data = (struct set_of_data *) (data1);
   if (rtx_equal_p (x, data->pat)
-      || (!MEM_P (x) && reg_overlap_mentioned_p (data->pat, x)))
+      || (GET_CODE (pat) == CLOBBER_HIGH
+	  && REGNO(data->pat) == REGNO(XEXP (pat, 0))
+	  && reg_is_clobbered_by_clobber_high (data->pat, XEXP (pat, 0)))
+      || (GET_CODE (pat) != CLOBBER_HIGH && !MEM_P (x)
+	  && reg_overlap_mentioned_p (data->pat, x)))
     data->found = pat;
 }
 
@@ -1474,6 +1517,7 @@
 	    {
 	    case USE:
 	    case CLOBBER:
+	    case CLOBBER_HIGH:
 	      break;
 
 	    case SET:
@@ -1564,7 +1608,7 @@
 
   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);
@@ -1580,15 +1624,16 @@
       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 = rtx_to_poly_int64 (XVECEXP (par, 0, 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)
+	if (maybe_ne (rtx_to_poly_int64 (XVECEXP (par, 0, i)), 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)
@@ -1627,7 +1672,8 @@
 	  rtx tem = XVECEXP (pat, 0, i);
 
 	  if (GET_CODE (tem) == USE
-	      || GET_CODE (tem) == CLOBBER)
+	      || GET_CODE (tem) == CLOBBER
+	      || GET_CODE (tem) == CLOBBER_HIGH)
 	    continue;
 
 	  if (GET_CODE (tem) != SET || ! set_noop_p (tem))
@@ -1769,6 +1815,7 @@
  recurse:
   switch (GET_CODE (x))
     {
+    case CLOBBER:
     case STRICT_LOW_PART:
     case ZERO_EXTRACT:
     case SIGN_EXTRACT:
@@ -1859,7 +1906,9 @@
   if (GET_CODE (x) == COND_EXEC)
     x = COND_EXEC_CODE (x);
 
-  if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
+  if (GET_CODE (x) == SET
+      || GET_CODE (x) == CLOBBER
+      || GET_CODE (x) == CLOBBER_HIGH)
     {
       rtx dest = SET_DEST (x);
 
@@ -2082,7 +2131,7 @@
   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)
     {
@@ -2340,6 +2389,15 @@
 				       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
@@ -2774,7 +2832,7 @@
 	  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);
 	}
@@ -3304,7 +3362,7 @@
     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);
@@ -3313,7 +3371,7 @@
     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);
@@ -3406,13 +3464,15 @@
 
   /* 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);
 
@@ -3420,13 +3480,15 @@
     {
     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:
@@ -3531,48 +3593,50 @@
    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;
+  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
-    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;
-  else
-    byte = subreg_byte % UNITS_PER_WORD;
-  bitpos += byte * BITS_PER_UNIT;
-
-  return bitpos;
+    {
+      /* 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 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)),
@@ -3585,29 +3649,32 @@
    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
@@ -3636,15 +3703,16 @@
 
 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,
@@ -3653,8 +3721,12 @@
      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
@@ -3671,9 +3743,9 @@
 	 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;
@@ -3684,8 +3756,12 @@
 
   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
@@ -3707,29 +3783,34 @@
 
   /* 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
@@ -3737,26 +3818,27 @@
       /* ??? 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;
@@ -3776,20 +3858,24 @@
      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;
     }
 
@@ -3816,7 +3902,7 @@
    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);
@@ -3832,7 +3918,7 @@
    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);
@@ -3849,7 +3935,7 @@
 
 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;
@@ -4124,7 +4210,7 @@
 
   /* 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;
 
@@ -4155,7 +4241,7 @@
       /* 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 */
@@ -4359,8 +4445,9 @@
 {
   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);
@@ -4394,16 +4481,16 @@
     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);
@@ -4413,7 +4500,6 @@
 
   /* 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:
@@ -4448,8 +4534,10 @@
 	     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);
@@ -4663,8 +4751,9 @@
 	 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);
@@ -4680,15 +4769,17 @@
 		   ? 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
@@ -4711,10 +4802,17 @@
 	  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
@@ -4723,13 +4821,23 @@
 	      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);
 	}
@@ -4917,8 +5025,10 @@
     {
       /* 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
@@ -5007,7 +5117,7 @@
 	  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);
 	}
@@ -5341,8 +5451,14 @@
       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;
@@ -5623,7 +5739,11 @@
   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
@@ -5996,8 +6116,9 @@
       machine_mode mode = GET_MODE (XEXP (x, 0));
       HOST_WIDE_INT len = INTVAL (XEXP (x, 1));
       HOST_WIDE_INT pos = INTVAL (XEXP (x, 2));
-
-      return (pos == (BITS_BIG_ENDIAN ? GET_MODE_PRECISION (mode) - len : 0));
+      poly_int64 remaining_bits = GET_MODE_PRECISION (mode) - len;
+
+      return known_eq (pos, BITS_BIG_ENDIAN ? remaining_bits : 0);
     }
   return false;
 }
@@ -6443,3 +6564,32 @@
       return true;
   return false;
 }
+
+/* Return true if reg REGNO with mode REG_MODE would be clobbered by the
+   clobber_high operand in CLOBBER_HIGH_OP.  */
+
+bool
+reg_is_clobbered_by_clobber_high (unsigned int regno, machine_mode reg_mode,
+				  const_rtx clobber_high_op)
+{
+  unsigned int clobber_regno = REGNO (clobber_high_op);
+  machine_mode clobber_mode = GET_MODE (clobber_high_op);
+  unsigned char regno_nregs = hard_regno_nregs (regno, reg_mode);
+
+  /* Clobber high should always span exactly one register.  */
+  gcc_assert (REG_NREGS (clobber_high_op) == 1);
+
+  /* Clobber high needs to match with one of the registers in X.  */
+  if (clobber_regno < regno || clobber_regno >= regno + regno_nregs)
+    return false;
+
+  gcc_assert (reg_mode != BLKmode && clobber_mode != BLKmode);
+
+  if (reg_mode == VOIDmode)
+    return clobber_mode != VOIDmode;
+
+  /* Clobber high will clobber if its size might be greater than the size of
+     register regno.  */
+  return maybe_gt (exact_div (GET_MODE_SIZE (reg_mode), regno_nregs),
+		 GET_MODE_SIZE (clobber_mode));
+}