]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/explow.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / explow.c
index 496e02ab8b3f11a6e9f42e67108141c8ed56e086..b6da277f6896a75e66319ad326ec3d84f89fa073 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for manipulating rtx's in semantically interesting ways.
-   Copyright (C) 1987-2016 Free Software Foundation, Inc.
+   Copyright (C) 1987-2021 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -25,9 +25,11 @@ along with GCC; see the file COPYING3.  If not see
 #include "function.h"
 #include "rtl.h"
 #include "tree.h"
+#include "memmodel.h"
 #include "tm_p.h"
-#include "expmed.h"
 #include "optabs.h"
+#include "expmed.h"
+#include "profile-count.h"
 #include "emit-rtl.h"
 #include "recog.h"
 #include "diagnostic-core.h"
@@ -36,6 +38,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dojump.h"
 #include "explow.h"
 #include "expr.h"
+#include "stringpool.h"
 #include "common/common-target.h"
 #include "output.h"
 
@@ -47,14 +50,15 @@ static rtx break_out_memory_refs (rtx);
 HOST_WIDE_INT
 trunc_int_for_mode (HOST_WIDE_INT c, machine_mode mode)
 {
-  int width = GET_MODE_PRECISION (mode);
+  /* Not scalar_int_mode because we also allow pointer bound modes.  */
+  scalar_mode smode = as_a <scalar_mode> (mode);
+  int width = GET_MODE_PRECISION (smode);
 
   /* You want to truncate to a _what_?  */
-  gcc_assert (SCALAR_INT_MODE_P (mode)
-             || POINTER_BOUNDS_MODE_P (mode));
+  gcc_assert (SCALAR_INT_MODE_P (mode));
 
   /* Canonicalize BImode to 0 and STORE_FLAG_VALUE.  */
-  if (mode == BImode)
+  if (smode == BImode)
     return c & 1 ? STORE_FLAG_VALUE : 0;
 
   /* Sign-extend for the requested mode.  */
@@ -71,13 +75,23 @@ trunc_int_for_mode (HOST_WIDE_INT c, machine_mode mode)
   return c;
 }
 
+/* Likewise for polynomial values, using the sign-extended representation
+   for each individual coefficient.  */
+
+poly_int64
+trunc_int_for_mode (poly_int64 x, machine_mode mode)
+{
+  for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
+    x.coeffs[i] = trunc_int_for_mode (x.coeffs[i], mode);
+  return x;
+}
+
 /* Return an rtx for the sum of X and the integer C, given that X has
    mode MODE.  INPLACE is true if X can be modified inplace or false
    if it must be treated as immutable.  */
 
 rtx
-plus_constant (machine_mode mode, rtx x, HOST_WIDE_INT c,
-              bool inplace)
+plus_constant (machine_mode mode, rtx x, poly_int64 c, bool inplace)
 {
   RTX_CODE code;
   rtx y;
@@ -86,7 +100,7 @@ plus_constant (machine_mode mode, rtx x, HOST_WIDE_INT c,
 
   gcc_assert (GET_MODE (x) == VOIDmode || GET_MODE (x) == mode);
 
-  if (c == 0)
+  if (known_eq (c, 0))
     return x;
 
  restart:
@@ -97,8 +111,7 @@ plus_constant (machine_mode mode, rtx x, HOST_WIDE_INT c,
   switch (code)
     {
     CASE_CONST_SCALAR_INT:
-      return immed_wide_int_const (wi::add (std::make_pair (x, mode), c),
-                                  mode);
+      return immed_wide_int_const (wi::add (rtx_mode_t (x, mode), c), mode);
     case MEM:
       /* If this is a reference to the constant pool, try replacing it with
         a reference to a new constant.  If the resulting address isn't
@@ -106,12 +119,26 @@ plus_constant (machine_mode mode, rtx x, HOST_WIDE_INT c,
       if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
          && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
        {
-         tem = plus_constant (mode, get_pool_constant (XEXP (x, 0)), c);
-         tem = force_const_mem (GET_MODE (x), tem);
-         /* Targets may disallow some constants in the constant pool, thus
-            force_const_mem may return NULL_RTX.  */
-         if (tem && memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
-           return tem;
+         rtx cst = get_pool_constant (XEXP (x, 0));
+
+         if (GET_CODE (cst) == CONST_VECTOR
+             && GET_MODE_INNER (GET_MODE (cst)) == mode)
+           {
+             cst = gen_lowpart (mode, cst);
+             gcc_assert (cst);
+           }
+         else if (GET_MODE (cst) == VOIDmode
+                  && get_pool_mode (XEXP (x, 0)) != mode)
+           break;
+         if (GET_MODE (cst) == VOIDmode || GET_MODE (cst) == mode)
+           {
+             tem = plus_constant (mode, cst, c);
+             tem = force_const_mem (GET_MODE (x), tem);
+             /* Targets may disallow some constants in the constant pool, thus
+                force_const_mem may return NULL_RTX.  */
+             if (tem && memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
+               return tem;
+           }
        }
       break;
 
@@ -164,10 +191,12 @@ plus_constant (machine_mode mode, rtx x, HOST_WIDE_INT c,
       break;
 
     default:
+      if (CONST_POLY_INT_P (x))
+       return immed_wide_int_const (const_poly_int_value (x) + c, mode);
       break;
     }
 
-  if (c != 0)
+  if (maybe_ne (c, 0))
     x = gen_rtx_PLUS (mode, x, gen_int_mode (c, mode));
 
   if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
@@ -194,8 +223,8 @@ eliminate_constant_term (rtx x, rtx *constptr)
 
   /* First handle constants appearing at this level explicitly.  */
   if (CONST_INT_P (XEXP (x, 1))
-      && 0 != (tem = simplify_binary_operation (PLUS, GET_MODE (x), *constptr,
-                                               XEXP (x, 1)))
+      && (tem = simplify_binary_operation (PLUS, GET_MODE (x), *constptr,
+                                          XEXP (x, 1))) != 0
       && CONST_INT_P (tem))
     {
       *constptr = tem;
@@ -206,8 +235,8 @@ eliminate_constant_term (rtx x, rtx *constptr)
   x0 = eliminate_constant_term (XEXP (x, 0), &tem);
   x1 = eliminate_constant_term (XEXP (x, 1), &tem);
   if ((x1 != XEXP (x, 1) || x0 != XEXP (x, 0))
-      && 0 != (tem = simplify_binary_operation (PLUS, GET_MODE (x),
-                                               *constptr, tem))
+      && (tem = simplify_binary_operation (PLUS, GET_MODE (x),
+                                          *constptr, tem)) != 0
       && CONST_INT_P (tem))
     {
       *constptr = tem;
@@ -259,18 +288,20 @@ break_out_memory_refs (rtx x)
    which way).  We take advantage of the fact that pointers are not allowed to
    overflow by commuting arithmetic operations over conversions so that address
    arithmetic insns can be used. IN_CONST is true if this conversion is inside
-   a CONST.  */
+   a CONST. NO_EMIT is true if no insns should be emitted, and instead
+   it should return NULL if it can't be simplified without emitting insns.  */
 
-static rtx
-convert_memory_address_addr_space_1 (machine_mode to_mode ATTRIBUTE_UNUSED,
+rtx
+convert_memory_address_addr_space_1 (scalar_int_mode to_mode ATTRIBUTE_UNUSED,
                                     rtx x, addr_space_t as ATTRIBUTE_UNUSED,
-                                    bool in_const ATTRIBUTE_UNUSED)
+                                    bool in_const ATTRIBUTE_UNUSED,
+                                    bool no_emit ATTRIBUTE_UNUSED)
 {
 #ifndef POINTERS_EXTEND_UNSIGNED
   gcc_assert (GET_MODE (x) == to_mode || GET_MODE (x) == VOIDmode);
   return x;
 #else /* defined(POINTERS_EXTEND_UNSIGNED) */
-  machine_mode pointer_mode, address_mode, from_mode;
+  scalar_int_mode pointer_mode, address_mode, from_mode;
   rtx temp;
   enum rtx_code code;
 
@@ -307,22 +338,19 @@ convert_memory_address_addr_space_1 (machine_mode to_mode ATTRIBUTE_UNUSED,
       break;
 
     case LABEL_REF:
-      temp = gen_rtx_LABEL_REF (to_mode, LABEL_REF_LABEL (x));
+      temp = gen_rtx_LABEL_REF (to_mode, label_ref_label (x));
       LABEL_REF_NONLOCAL_P (temp) = LABEL_REF_NONLOCAL_P (x);
       return temp;
-      break;
 
     case SYMBOL_REF:
       temp = shallow_copy_rtx (x);
       PUT_MODE (temp, to_mode);
       return temp;
-      break;
 
     case CONST:
-      return gen_rtx_CONST (to_mode,
-                           convert_memory_address_addr_space_1
-                             (to_mode, XEXP (x, 0), as, true));
-      break;
+      temp = convert_memory_address_addr_space_1 (to_mode, XEXP (x, 0), as,
+                                                 true, no_emit);
+      return temp ? gen_rtx_CONST (to_mode, temp) : temp;
 
     case PLUS:
     case MULT:
@@ -338,18 +366,45 @@ convert_memory_address_addr_space_1 (machine_mode to_mode ATTRIBUTE_UNUSED,
              && CONST_INT_P (XEXP (x, 1))
              && ((in_const && POINTERS_EXTEND_UNSIGNED != 0)
                  || XEXP (x, 1) == convert_memory_address_addr_space_1
-                                    (to_mode, XEXP (x, 1), as, in_const)
+                                    (to_mode, XEXP (x, 1), as, in_const,
+                                     no_emit)
                   || POINTERS_EXTEND_UNSIGNED < 0)))
-       return gen_rtx_fmt_ee (GET_CODE (x), to_mode,
-                              convert_memory_address_addr_space_1
-                                (to_mode, XEXP (x, 0), as, in_const),
-                              XEXP (x, 1));
+       {
+         temp = convert_memory_address_addr_space_1 (to_mode, XEXP (x, 0),
+                                                     as, in_const, no_emit);
+         return (temp ? gen_rtx_fmt_ee (GET_CODE (x), to_mode,
+                                        temp, XEXP (x, 1))
+                      : temp);
+       }
+      break;
+
+    case UNSPEC:
+      /* Assume that all UNSPECs in a constant address can be converted
+        operand-by-operand.  We could add a target hook if some targets
+        require different behavior.  */
+      if (in_const && GET_MODE (x) == from_mode)
+       {
+         unsigned int n = XVECLEN (x, 0);
+         rtvec v = gen_rtvec (n);
+         for (unsigned int i = 0; i < n; ++i)
+           {
+             rtx op = XVECEXP (x, 0, i);
+             if (GET_MODE (op) == from_mode)
+               op = convert_memory_address_addr_space_1 (to_mode, op, as,
+                                                         in_const, no_emit);
+             RTVEC_ELT (v, i) = op;
+           }
+         return gen_rtx_UNSPEC (to_mode, v, XINT (x, 1));
+       }
       break;
 
     default:
       break;
     }
 
+  if (no_emit)
+    return NULL_RTX;
+
   return convert_modes (to_mode, from_mode,
                        x, POINTERS_EXTEND_UNSIGNED);
 #endif /* defined(POINTERS_EXTEND_UNSIGNED) */
@@ -362,9 +417,10 @@ convert_memory_address_addr_space_1 (machine_mode to_mode ATTRIBUTE_UNUSED,
    arithmetic insns can be used.  */
 
 rtx
-convert_memory_address_addr_space (machine_mode to_mode, rtx x, addr_space_t as)
+convert_memory_address_addr_space (scalar_int_mode to_mode, rtx x,
+                                  addr_space_t as)
 {
-  return convert_memory_address_addr_space_1 (to_mode, x, as, false);
+  return convert_memory_address_addr_space_1 (to_mode, x, as, false, false);
 }
 \f
 
@@ -376,7 +432,7 @@ rtx
 memory_address_addr_space (machine_mode mode, rtx x, addr_space_t as)
 {
   rtx oldx = x;
-  machine_mode address_mode = targetm.addr_space.address_mode (as);
+  scalar_int_mode address_mode = targetm.addr_space.address_mode (as);
 
   x = convert_memory_address_addr_space (address_mode, x, as);
 
@@ -478,9 +534,8 @@ memory_address_addr_space (machine_mode mode, rtx x, addr_space_t as)
   return x;
 }
 
-/* If REF is a MEM with an invalid address, change it into a valid address.
-   Pass through anything else unchanged.  REF must be an unshared rtx and
-   the function may modify it in-place.  */
+/* Convert a mem ref into one with a valid memory address.
+   Pass through anything else unchanged.  */
 
 rtx
 validize_mem (rtx ref)
@@ -492,7 +547,8 @@ validize_mem (rtx ref)
                                   MEM_ADDR_SPACE (ref)))
     return ref;
 
-  return replace_equiv_address (ref, XEXP (ref, 0), true);
+  /* Don't alter REF itself, since that is probably a stack slot.  */
+  return replace_equiv_address (ref, XEXP (ref, 0));
 }
 
 /* If X is a memory reference to a member of an object block, try rewriting
@@ -766,6 +822,7 @@ promote_mode (const_tree type ATTRIBUTE_UNUSED, machine_mode mode,
 #ifdef PROMOTE_MODE
   enum tree_code code;
   int unsignedp;
+  scalar_mode smode;
 #endif
 
   /* For libcalls this is invoked without TYPE from the backends
@@ -785,10 +842,11 @@ promote_mode (const_tree type ATTRIBUTE_UNUSED, machine_mode mode,
     {
     case INTEGER_TYPE:   case ENUMERAL_TYPE:   case BOOLEAN_TYPE:
     case REAL_TYPE:      case OFFSET_TYPE:     case FIXED_POINT_TYPE:
-      PROMOTE_MODE (mode, unsignedp, type);
+      /* Values of these types always have scalar mode.  */
+      smode = as_a <scalar_mode> (mode);
+      PROMOTE_MODE (smode, unsignedp, type);
       *punsignedp = unsignedp;
-      return mode;
-      break;
+      return smode;
 
 #ifdef POINTERS_EXTEND_UNSIGNED
     case REFERENCE_TYPE:
@@ -796,7 +854,6 @@ promote_mode (const_tree type ATTRIBUTE_UNUSED, machine_mode mode,
       *punsignedp = POINTERS_EXTEND_UNSIGNED;
       return targetm.addr_space.address_mode
               (TYPE_ADDR_SPACE (TREE_TYPE (type)));
-      break;
 #endif
 
     default:
@@ -857,16 +914,7 @@ promote_ssa_mode (const_tree name, int *punsignedp)
 
   tree type = TREE_TYPE (name);
   int unsignedp = TYPE_UNSIGNED (type);
-  machine_mode mode = TYPE_MODE (type);
-
-  /* Bypass TYPE_MODE when it maps vector modes to BLKmode.  */
-  if (mode == BLKmode)
-    {
-      gcc_assert (VECTOR_TYPE_P (type));
-      mode = type->type_common.mode;
-    }
-
-  machine_mode pmode = promote_mode (type, mode, &unsignedp);
+  machine_mode pmode = promote_mode (type, TYPE_MODE (type), &unsignedp);
   if (punsignedp)
     *punsignedp = unsignedp;
 
@@ -875,7 +923,7 @@ promote_ssa_mode (const_tree name, int *punsignedp)
 
 
 \f
-/* Controls the behaviour of {anti_,}adjust_stack.  */
+/* Controls the behavior of {anti_,}adjust_stack.  */
 static bool suppress_reg_args_size;
 
 /* A helper for adjust_stack and anti_adjust_stack.  */
@@ -905,7 +953,7 @@ adjust_stack_1 (rtx adjust, bool anti_p)
     }
 
   if (!suppress_reg_args_size)
-    add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta));
+    add_args_size_note (insn, stack_pointer_delta);
 }
 
 /* Adjust the stack pointer by ADJUST (an rtx for a number of bytes).
@@ -919,8 +967,9 @@ adjust_stack (rtx adjust)
 
   /* We expect all variable sized adjustments to be multiple of
      PREFERRED_STACK_BOUNDARY.  */
-  if (CONST_INT_P (adjust))
-    stack_pointer_delta -= INTVAL (adjust);
+  poly_int64 const_adjust;
+  if (poly_int_rtx_p (adjust, &const_adjust))
+    stack_pointer_delta -= const_adjust;
 
   adjust_stack_1 (adjust, false);
 }
@@ -936,8 +985,9 @@ anti_adjust_stack (rtx adjust)
 
   /* We expect all variable sized adjustments to be multiple of
      PREFERRED_STACK_BOUNDARY.  */
-  if (CONST_INT_P (adjust))
-    stack_pointer_delta += INTVAL (adjust);
+  poly_int64 const_adjust;
+  if (poly_int_rtx_p (adjust, &const_adjust))
+    stack_pointer_delta += const_adjust;
 
   adjust_stack_1 (adjust, true);
 }
@@ -1139,7 +1189,153 @@ record_new_stack_level (void)
   if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
     update_sjlj_context ();
 }
-\f
+
+/* Return an rtx doing runtime alignment to REQUIRED_ALIGN on TARGET.  */
+
+rtx
+align_dynamic_address (rtx target, unsigned required_align)
+{
+  /* CEIL_DIV_EXPR needs to worry about the addition overflowing,
+     but we know it can't.  So add ourselves and then do
+     TRUNC_DIV_EXPR.  */
+  target = expand_binop (Pmode, add_optab, target,
+                        gen_int_mode (required_align / BITS_PER_UNIT - 1,
+                                      Pmode),
+                        NULL_RTX, 1, OPTAB_LIB_WIDEN);
+  target = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, target,
+                         gen_int_mode (required_align / BITS_PER_UNIT,
+                                       Pmode),
+                         NULL_RTX, 1);
+  target = expand_mult (Pmode, target,
+                       gen_int_mode (required_align / BITS_PER_UNIT,
+                                     Pmode),
+                       NULL_RTX, 1);
+
+  return target;
+}
+
+/* Return an rtx through *PSIZE, representing the size of an area of memory to
+   be dynamically pushed on the stack.
+
+   *PSIZE is an rtx representing the size of the area.
+
+   SIZE_ALIGN is the alignment (in bits) that we know SIZE has.  This
+   parameter may be zero.  If so, a proper value will be extracted
+   from SIZE if it is constant, otherwise BITS_PER_UNIT will be assumed.
+
+   REQUIRED_ALIGN is the alignment (in bits) required for the region
+   of memory.
+
+   If PSTACK_USAGE_SIZE is not NULL it points to a value that is increased for
+   the additional size returned.  */
+void
+get_dynamic_stack_size (rtx *psize, unsigned size_align,
+                       unsigned required_align,
+                       HOST_WIDE_INT *pstack_usage_size)
+{
+  rtx size = *psize;
+
+  /* Ensure the size is in the proper mode.  */
+  if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)
+    size = convert_to_mode (Pmode, size, 1);
+
+  if (CONST_INT_P (size))
+    {
+      unsigned HOST_WIDE_INT lsb;
+
+      lsb = INTVAL (size);
+      lsb &= -lsb;
+
+      /* Watch out for overflow truncating to "unsigned".  */
+      if (lsb > UINT_MAX / BITS_PER_UNIT)
+       size_align = 1u << (HOST_BITS_PER_INT - 1);
+      else
+       size_align = (unsigned)lsb * BITS_PER_UNIT;
+    }
+  else if (size_align < BITS_PER_UNIT)
+    size_align = BITS_PER_UNIT;
+
+  /* We can't attempt to minimize alignment necessary, because we don't
+     know the final value of preferred_stack_boundary yet while executing
+     this code.  */
+  if (crtl->preferred_stack_boundary < PREFERRED_STACK_BOUNDARY)
+    crtl->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
+
+  /* We will need to ensure that the address we return is aligned to
+     REQUIRED_ALIGN.  At this point in the compilation, we don't always
+     know the final value of the STACK_DYNAMIC_OFFSET used in function.c
+     (it might depend on the size of the outgoing parameter lists, for
+     example), so we must preventively align the value.  We leave space
+     in SIZE for the hole that might result from the alignment operation.  */
+
+  unsigned known_align = REGNO_POINTER_ALIGN (VIRTUAL_STACK_DYNAMIC_REGNUM);
+  if (known_align == 0)
+    known_align = BITS_PER_UNIT;
+  if (required_align > known_align)
+    {
+      unsigned extra = (required_align - known_align) / BITS_PER_UNIT;
+      size = plus_constant (Pmode, size, extra);
+      size = force_operand (size, NULL_RTX);
+      if (size_align > known_align)
+       size_align = known_align;
+
+      if (flag_stack_usage_info && pstack_usage_size)
+       *pstack_usage_size += extra;
+    }
+
+  /* Round the size to a multiple of the required stack alignment.
+     Since the stack is presumed to be rounded before this allocation,
+     this will maintain the required alignment.
+
+     If the stack grows downward, we could save an insn by subtracting
+     SIZE from the stack pointer and then aligning the stack pointer.
+     The problem with this is that the stack pointer may be unaligned
+     between the execution of the subtraction and alignment insns and
+     some machines do not allow this.  Even on those that do, some
+     signal handlers malfunction if a signal should occur between those
+     insns.  Since this is an extremely rare event, we have no reliable
+     way of knowing which systems have this problem.  So we avoid even
+     momentarily mis-aligning the stack.  */
+  if (size_align % MAX_SUPPORTED_STACK_ALIGNMENT != 0)
+    {
+      size = round_push (size);
+
+      if (flag_stack_usage_info && pstack_usage_size)
+       {
+         int align = crtl->preferred_stack_boundary / BITS_PER_UNIT;
+         *pstack_usage_size =
+           (*pstack_usage_size + align - 1) / align * align;
+       }
+    }
+
+  *psize = size;
+}
+
+/* Return the number of bytes to "protect" on the stack for -fstack-check.
+
+   "protect" in the context of -fstack-check means how many bytes we need
+   to always ensure are available on the stack; as a consequence, this is
+   also how many bytes are first skipped when probing the stack.
+
+   On some targets we want to reuse the -fstack-check prologue support
+   to give a degree of protection against stack clashing style attacks.
+
+   In that scenario we do not want to skip bytes before probing as that
+   would render the stack clash protections useless.
+
+   So we never use STACK_CHECK_PROTECT directly.  Instead we indirectly
+   use it through this helper, which allows to provide different values
+   for -fstack-check and -fstack-clash-protection.  */
+
+HOST_WIDE_INT
+get_stack_check_protect (void)
+{
+  if (flag_stack_clash_protection)
+    return 0;
+
+ return STACK_CHECK_PROTECT;
+}
+
 /* Return an rtx representing the address of an area of memory dynamically
    pushed on the stack.
 
@@ -1148,12 +1344,15 @@ record_new_stack_level (void)
    SIZE is an rtx representing the size of the area.
 
    SIZE_ALIGN is the alignment (in bits) that we know SIZE has.  This
-   parameter may be zero.  If so, a proper value will be extracted 
+   parameter may be zero.  If so, a proper value will be extracted
    from SIZE if it is constant, otherwise BITS_PER_UNIT will be assumed.
 
    REQUIRED_ALIGN is the alignment (in bits) required for the region
    of memory.
 
+   MAX_SIZE is an upper bound for SIZE, if SIZE is not constant, or -1 if
+   no such upper bound is known.
+
    If CANNOT_ACCUMULATE is set to TRUE, the caller guarantees that the
    stack space allocated by the generated code cannot be added with itself
    in the course of the execution of the function.  It is always safe to
@@ -1163,13 +1362,13 @@ record_new_stack_level (void)
 
 rtx
 allocate_dynamic_stack_space (rtx size, unsigned size_align,
-                             unsigned required_align, bool cannot_accumulate)
+                             unsigned required_align,
+                             HOST_WIDE_INT max_size,
+                             bool cannot_accumulate)
 {
   HOST_WIDE_INT stack_usage_size = -1;
   rtx_code_label *final_label;
   rtx final_target, target;
-  unsigned extra_align = 0;
-  bool must_align;
 
   /* If we're asking for zero bytes, it doesn't matter what we point
      to since we can't dereference it.  But return a reasonable
@@ -1204,108 +1403,19 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
            }
        }
 
-      /* If the size is not constant, we can't say anything.  */
-      if (stack_usage_size == -1)
+      /* If the size is not constant, try the maximum size.  */
+      if (stack_usage_size < 0)
+       stack_usage_size = max_size;
+
+      /* If the size is still not constant, we can't say anything.  */
+      if (stack_usage_size < 0)
        {
          current_function_has_unbounded_dynamic_stack_size = 1;
          stack_usage_size = 0;
        }
     }
 
-  /* Ensure the size is in the proper mode.  */
-  if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)
-    size = convert_to_mode (Pmode, size, 1);
-
-  /* Adjust SIZE_ALIGN, if needed.  */
-  if (CONST_INT_P (size))
-    {
-      unsigned HOST_WIDE_INT lsb;
-
-      lsb = INTVAL (size);
-      lsb &= -lsb;
-
-      /* Watch out for overflow truncating to "unsigned".  */
-      if (lsb > UINT_MAX / BITS_PER_UNIT)
-       size_align = 1u << (HOST_BITS_PER_INT - 1);
-      else
-       size_align = (unsigned)lsb * BITS_PER_UNIT;
-    }
-  else if (size_align < BITS_PER_UNIT)
-    size_align = BITS_PER_UNIT;
-
-  /* We can't attempt to minimize alignment necessary, because we don't
-     know the final value of preferred_stack_boundary yet while executing
-     this code.  */
-  if (crtl->preferred_stack_boundary < PREFERRED_STACK_BOUNDARY)
-    crtl->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
-
-  /* We will need to ensure that the address we return is aligned to
-     REQUIRED_ALIGN.  If STACK_DYNAMIC_OFFSET is defined, we don't
-     always know its final value at this point in the compilation (it
-     might depend on the size of the outgoing parameter lists, for
-     example), so we must align the value to be returned in that case.
-     (Note that STACK_DYNAMIC_OFFSET will have a default nonzero value if
-     STACK_POINTER_OFFSET or ACCUMULATE_OUTGOING_ARGS are defined).
-     We must also do an alignment operation on the returned value if
-     the stack pointer alignment is less strict than REQUIRED_ALIGN.
-
-     If we have to align, we must leave space in SIZE for the hole
-     that might result from the alignment operation.  */
-
-  must_align = (crtl->preferred_stack_boundary < required_align);
-  if (must_align)
-    {
-      if (required_align > PREFERRED_STACK_BOUNDARY)
-       extra_align = PREFERRED_STACK_BOUNDARY;
-      else if (required_align > STACK_BOUNDARY)
-       extra_align = STACK_BOUNDARY;
-      else
-       extra_align = BITS_PER_UNIT;
-    }
-
-  /* ??? STACK_POINTER_OFFSET is always defined now.  */
-#if defined (STACK_DYNAMIC_OFFSET) || defined (STACK_POINTER_OFFSET)
-  must_align = true;
-  extra_align = BITS_PER_UNIT;
-#endif
-
-  if (must_align)
-    {
-      unsigned extra = (required_align - extra_align) / BITS_PER_UNIT;
-
-      size = plus_constant (Pmode, size, extra);
-      size = force_operand (size, NULL_RTX);
-
-      if (flag_stack_usage_info)
-       stack_usage_size += extra;
-
-      if (extra && size_align > extra_align)
-       size_align = extra_align;
-    }
-
-  /* Round the size to a multiple of the required stack alignment.
-     Since the stack if presumed to be rounded before this allocation,
-     this will maintain the required alignment.
-
-     If the stack grows downward, we could save an insn by subtracting
-     SIZE from the stack pointer and then aligning the stack pointer.
-     The problem with this is that the stack pointer may be unaligned
-     between the execution of the subtraction and alignment insns and
-     some machines do not allow this.  Even on those that do, some
-     signal handlers malfunction if a signal should occur between those
-     insns.  Since this is an extremely rare event, we have no reliable
-     way of knowing which systems have this problem.  So we avoid even
-     momentarily mis-aligning the stack.  */
-  if (size_align % MAX_SUPPORTED_STACK_ALIGNMENT != 0)
-    {
-      size = round_push (size);
-
-      if (flag_stack_usage_info)
-       {
-         int align = crtl->preferred_stack_boundary / BITS_PER_UNIT;
-         stack_usage_size = (stack_usage_size + align - 1) / align * align;
-       }
-    }
+  get_dynamic_stack_size (&size, size_align, required_align, &stack_usage_size);
 
   target = gen_reg_rtx (Pmode);
 
@@ -1321,6 +1431,8 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
        current_function_has_unbounded_dynamic_stack_size = 1;
     }
 
+  do_pending_stack_adjust ();
+
   final_label = NULL;
   final_target = NULL_RTX;
 
@@ -1355,18 +1467,15 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
       if (MALLOC_ABI_ALIGNMENT >= required_align)
        ask = size;
       else
-       {
-         ask = expand_binop (Pmode, add_optab, size,
-                             gen_int_mode (required_align / BITS_PER_UNIT - 1,
-                                           Pmode),
-                             NULL_RTX, 1, OPTAB_LIB_WIDEN);
-         must_align = true;
-       }
+       ask = expand_binop (Pmode, add_optab, size,
+                           gen_int_mode (required_align / BITS_PER_UNIT - 1,
+                                         Pmode),
+                           NULL_RTX, 1, OPTAB_LIB_WIDEN);
 
       func = init_one_libfunc ("__morestack_allocate_stack_space");
 
       space = emit_library_call_value (func, target, LCT_NORMAL, Pmode,
-                                      1, ask, Pmode);
+                                      ask, Pmode);
 
       if (available_label == NULL_RTX)
        return space;
@@ -1381,12 +1490,10 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
       emit_label (available_label);
     }
 
-  do_pending_stack_adjust ();
-
  /* We ought to be called always on the toplevel and stack ought to be aligned
     properly.  */
-  gcc_assert (!(stack_pointer_delta
-               % (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)));
+  gcc_assert (multiple_p (stack_pointer_delta,
+                         PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT));
 
   /* If needed, check that we have the required amount of stack.  Take into
      account what has already been checked.  */
@@ -1396,7 +1503,7 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
     probe_stack_range (STACK_OLD_CHECK_PROTECT + STACK_CHECK_MAX_FRAME_SIZE,
                       size);
   else if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
-    probe_stack_range (STACK_CHECK_PROTECT, size);
+    probe_stack_range (get_stack_check_protect (), size);
 
   /* Don't let anti_adjust_stack emit notes.  */
   suppress_reg_args_size = true;
@@ -1406,7 +1513,7 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
      stack pointer, such as acquiring the space by calling malloc().  */
   if (targetm.have_allocate_stack ())
     {
-      struct expand_operand ops[2];
+      class expand_operand ops[2];
       /* We don't have to check against the predicate for operand 0 since
         TARGET is known to be a pseudo of the proper mode, which must
         be valid for the operand.  */
@@ -1416,7 +1523,7 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
     }
   else
     {
-      int saved_stack_pointer_delta;
+      poly_int64 saved_stack_pointer_delta;
 
       if (!STACK_GROWS_DOWNWARD)
        emit_move_insn (target, virtual_stack_dynamic_rtx);
@@ -1447,8 +1554,12 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
 
       saved_stack_pointer_delta = stack_pointer_delta;
 
+      /* If stack checking or stack clash protection is requested,
+        then probe the stack while allocating space from it.  */
       if (flag_stack_check && STACK_CHECK_MOVING_SP)
        anti_adjust_stack_and_probe (size, false);
+      else if (flag_stack_clash_protection)
+       anti_adjust_stack_and_probe_stack_clash (size);
       else
        anti_adjust_stack (size);
 
@@ -1472,24 +1583,7 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
       target = final_target;
     }
 
-  if (must_align)
-    {
-      /* CEIL_DIV_EXPR needs to worry about the addition overflowing,
-        but we know it can't.  So add ourselves and then do
-        TRUNC_DIV_EXPR.  */
-      target = expand_binop (Pmode, add_optab, target,
-                            gen_int_mode (required_align / BITS_PER_UNIT - 1,
-                                          Pmode),
-                            NULL_RTX, 1, OPTAB_LIB_WIDEN);
-      target = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, target,
-                             gen_int_mode (required_align / BITS_PER_UNIT,
-                                           Pmode),
-                             NULL_RTX, 1);
-      target = expand_mult (Pmode, target,
-                           gen_int_mode (required_align / BITS_PER_UNIT,
-                                         Pmode),
-                           NULL_RTX, 1);
-    }
+  target = align_dynamic_address (target, required_align);
 
   /* Now that we've committed to a return value, mark its alignment.  */
   mark_reg_pointer (target, required_align);
@@ -1499,6 +1593,42 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
 
   return target;
 }
+
+/* Return an rtx representing the address of an area of memory already
+   statically pushed onto the stack in the virtual stack vars area.  (It is
+   assumed that the area is allocated in the function prologue.)
+
+   Any required stack pointer alignment is preserved.
+
+   OFFSET is the offset of the area into the virtual stack vars area.
+
+   REQUIRED_ALIGN is the alignment (in bits) required for the region
+   of memory.
+
+   BASE is the rtx of the base of this virtual stack vars area.
+   The only time this is not `virtual_stack_vars_rtx` is when tagging pointers
+   on the stack.  */
+
+rtx
+get_dynamic_stack_base (poly_int64 offset, unsigned required_align, rtx base)
+{
+  rtx target;
+
+  if (crtl->preferred_stack_boundary < PREFERRED_STACK_BOUNDARY)
+    crtl->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
+
+  target = gen_reg_rtx (Pmode);
+  emit_move_insn (target, base);
+  target = expand_binop (Pmode, add_optab, target,
+                        gen_int_mode (offset, Pmode),
+                        NULL_RTX, 1, OPTAB_LIB_WIDEN);
+  target = align_dynamic_address (target, required_align);
+
+  /* Now that we've committed to a return value, mark its alignment.  */
+  mark_reg_pointer (target, required_align);
+
+  return target;
+}
 \f
 /* A front end may want to override GCC's stack checking by providing a
    run-time routine to call to check the stack, so provide a mechanism for
@@ -1511,6 +1641,10 @@ set_stack_check_libfunc (const char *libfunc_name)
 {
   gcc_assert (stack_check_libfunc == NULL_RTX);
   stack_check_libfunc = gen_rtx_SYMBOL_REF (Pmode, libfunc_name);
+  tree decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
+                         get_identifier (libfunc_name), void_type_node);
+  DECL_EXTERNAL (decl) = 1;
+  SET_SYMBOL_REF_DECL (stack_check_libfunc, decl);
 }
 \f
 /* Emit one stack probe at ADDRESS, an address within the stack.  */
@@ -1519,18 +1653,25 @@ void
 emit_stack_probe (rtx address)
 {
   if (targetm.have_probe_stack_address ())
-    emit_insn (targetm.gen_probe_stack_address (address));
+    {
+      class expand_operand ops[1];
+      insn_code icode = targetm.code_for_probe_stack_address;
+      create_address_operand (ops, address);
+      maybe_legitimize_operands (icode, 0, 1, ops);
+      expand_insn (icode, 1, ops);
+    }
   else
     {
       rtx memref = gen_rtx_MEM (word_mode, address);
 
       MEM_VOLATILE_P (memref) = 1;
+      memref = validize_mem (memref);
 
       /* See if we have an insn to probe the stack.  */
       if (targetm.have_probe_stack ())
-        emit_insn (targetm.gen_probe_stack (memref));
+       emit_insn (targetm.gen_probe_stack (memref));
       else
-        emit_move_insn (memref, const0_rtx);
+       emit_move_insn (memref, const0_rtx);
     }
 }
 
@@ -1566,14 +1707,14 @@ probe_stack_range (HOST_WIDE_INT first, rtx size)
                                                 stack_pointer_rtx,
                                                 plus_constant (Pmode,
                                                                size, first)));
-      emit_library_call (stack_check_libfunc, LCT_NORMAL, VOIDmode, 1, addr,
-                        Pmode);
+      emit_library_call (stack_check_libfunc, LCT_THROW, VOIDmode,
+                        addr, Pmode);
     }
 
   /* Next see if we have an insn to check the stack.  */
   else if (targetm.have_check_stack ())
     {
-      struct expand_operand ops[1];
+      class expand_operand ops[1];
       rtx addr = memory_address (Pmode,
                                 gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
                                                 stack_pointer_rtx,
@@ -1709,6 +1850,255 @@ probe_stack_range (HOST_WIDE_INT first, rtx size)
   emit_insn (gen_blockage ());
 }
 
+/* Compute parameters for stack clash probing a dynamic stack
+   allocation of SIZE bytes.
+
+   We compute ROUNDED_SIZE, LAST_ADDR, RESIDUAL and PROBE_INTERVAL.
+
+   Additionally we conditionally dump the type of probing that will
+   be needed given the values computed.  */
+
+void
+compute_stack_clash_protection_loop_data (rtx *rounded_size, rtx *last_addr,
+                                         rtx *residual,
+                                         HOST_WIDE_INT *probe_interval,
+                                         rtx size)
+{
+  /* Round SIZE down to STACK_CLASH_PROTECTION_PROBE_INTERVAL */
+  *probe_interval
+    = 1 << param_stack_clash_protection_probe_interval;
+  *rounded_size = simplify_gen_binary (AND, Pmode, size,
+                                       GEN_INT (-*probe_interval));
+
+  /* Compute the value of the stack pointer for the last iteration.
+     It's just SP + ROUNDED_SIZE.  */
+  rtx rounded_size_op = force_operand (*rounded_size, NULL_RTX);
+  *last_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
+                                             stack_pointer_rtx,
+                                             rounded_size_op),
+                             NULL_RTX);
+
+  /* Compute any residuals not allocated by the loop above.  Residuals
+     are just the ROUNDED_SIZE - SIZE.  */
+  *residual = simplify_gen_binary (MINUS, Pmode, size, *rounded_size);
+
+  /* Dump key information to make writing tests easy.  */
+  if (dump_file)
+    {
+      if (*rounded_size == CONST0_RTX (Pmode))
+       fprintf (dump_file,
+                "Stack clash skipped dynamic allocation and probing loop.\n");
+      else if (CONST_INT_P (*rounded_size)
+              && INTVAL (*rounded_size) <= 4 * *probe_interval)
+       fprintf (dump_file,
+                "Stack clash dynamic allocation and probing inline.\n");
+      else if (CONST_INT_P (*rounded_size))
+       fprintf (dump_file,
+                "Stack clash dynamic allocation and probing in "
+                "rotated loop.\n");
+      else
+       fprintf (dump_file,
+                "Stack clash dynamic allocation and probing in loop.\n");
+
+      if (*residual != CONST0_RTX (Pmode))
+       fprintf (dump_file,
+                "Stack clash dynamic allocation and probing residuals.\n");
+      else
+       fprintf (dump_file,
+                "Stack clash skipped dynamic allocation and "
+                "probing residuals.\n");
+    }
+}
+
+/* Emit the start of an allocate/probe loop for stack
+   clash protection.
+
+   LOOP_LAB and END_LAB are returned for use when we emit the
+   end of the loop.
+
+   LAST addr is the value for SP which stops the loop.  */
+void
+emit_stack_clash_protection_probe_loop_start (rtx *loop_lab,
+                                             rtx *end_lab,
+                                             rtx last_addr,
+                                             bool rotated)
+{
+  /* Essentially we want to emit any setup code, the top of loop
+     label and the comparison at the top of the loop.  */
+  *loop_lab = gen_label_rtx ();
+  *end_lab = gen_label_rtx ();
+
+  emit_label (*loop_lab);
+  if (!rotated)
+    emit_cmp_and_jump_insns (stack_pointer_rtx, last_addr, EQ, NULL_RTX,
+                            Pmode, 1, *end_lab);
+}
+
+/* Emit the end of a stack clash probing loop.
+
+   This consists of just the jump back to LOOP_LAB and
+   emitting END_LOOP after the loop.  */
+
+void
+emit_stack_clash_protection_probe_loop_end (rtx loop_lab, rtx end_loop,
+                                           rtx last_addr, bool rotated)
+{
+  if (rotated)
+    emit_cmp_and_jump_insns (stack_pointer_rtx, last_addr, NE, NULL_RTX,
+                            Pmode, 1, loop_lab);
+  else
+    emit_jump (loop_lab);
+
+  emit_label (end_loop);
+
+}
+
+/* Adjust the stack pointer by minus SIZE (an rtx for a number of bytes)
+   while probing it.  This pushes when SIZE is positive.  SIZE need not
+   be constant.
+
+   This is subtly different than anti_adjust_stack_and_probe to try and
+   prevent stack-clash attacks
+
+     1. It must assume no knowledge of the probing state, any allocation
+       must probe.
+
+       Consider the case of a 1 byte alloca in a loop.  If the sum of the
+       allocations is large, then this could be used to jump the guard if
+       probes were not emitted.
+
+     2. It never skips probes, whereas anti_adjust_stack_and_probe will
+       skip the probe on the first PROBE_INTERVAL on the assumption it
+       was already done in the prologue and in previous allocations.
+
+     3. It only allocates and probes SIZE bytes, it does not need to
+       allocate/probe beyond that because this probing style does not
+       guarantee signal handling capability if the guard is hit.  */
+
+void
+anti_adjust_stack_and_probe_stack_clash (rtx size)
+{
+  /* First ensure SIZE is Pmode.  */
+  if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)
+    size = convert_to_mode (Pmode, size, 1);
+
+  /* We can get here with a constant size on some targets.  */
+  rtx rounded_size, last_addr, residual;
+  HOST_WIDE_INT probe_interval, probe_range;
+  bool target_probe_range_p = false;
+  compute_stack_clash_protection_loop_data (&rounded_size, &last_addr,
+                                           &residual, &probe_interval, size);
+
+  /* Get the back-end specific probe ranges.  */
+  probe_range = targetm.stack_clash_protection_alloca_probe_range ();
+  target_probe_range_p = probe_range != 0;
+  gcc_assert (probe_range >= 0);
+
+  /* If no back-end specific range defined, default to the top of the newly
+     allocated range.  */
+  if (probe_range == 0)
+    probe_range = probe_interval - GET_MODE_SIZE (word_mode);
+
+  if (rounded_size != CONST0_RTX (Pmode))
+    {
+      if (CONST_INT_P (rounded_size)
+         && INTVAL (rounded_size) <= 4 * probe_interval)
+       {
+         for (HOST_WIDE_INT i = 0;
+              i < INTVAL (rounded_size);
+              i += probe_interval)
+           {
+             anti_adjust_stack (GEN_INT (probe_interval));
+             /* The prologue does not probe residuals.  Thus the offset
+                here to probe just beyond what the prologue had already
+                allocated.  */
+             emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
+                                              probe_range));
+
+             emit_insn (gen_blockage ());
+           }
+       }
+      else
+       {
+         rtx loop_lab, end_loop;
+         bool rotate_loop = CONST_INT_P (rounded_size);
+         emit_stack_clash_protection_probe_loop_start (&loop_lab, &end_loop,
+                                                       last_addr, rotate_loop);
+
+         anti_adjust_stack (GEN_INT (probe_interval));
+
+         /* The prologue does not probe residuals.  Thus the offset here
+            to probe just beyond what the prologue had already
+            allocated.  */
+         emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
+                                          probe_range));
+
+         emit_stack_clash_protection_probe_loop_end (loop_lab, end_loop,
+                                                     last_addr, rotate_loop);
+         emit_insn (gen_blockage ());
+       }
+    }
+
+  if (residual != CONST0_RTX (Pmode))
+    {
+      rtx label = NULL_RTX;
+      /* RESIDUAL could be zero at runtime and in that case *sp could
+        hold live data.  Furthermore, we do not want to probe into the
+        red zone.
+
+        If TARGET_PROBE_RANGE_P then the target has promised it's safe to
+        probe at offset 0.  In which case we no longer have to check for
+        RESIDUAL == 0.  However we still need to probe at the right offset
+        when RESIDUAL > PROBE_RANGE, in which case we probe at PROBE_RANGE.
+
+        If !TARGET_PROBE_RANGE_P then go ahead and just guard the probe at *sp
+        on RESIDUAL != 0 at runtime if RESIDUAL is not a compile time constant.
+        */
+      anti_adjust_stack (residual);
+
+      if (!CONST_INT_P (residual))
+       {
+         label = gen_label_rtx ();
+         rtx_code op = target_probe_range_p ? LT : EQ;
+         rtx probe_cmp_value = target_probe_range_p
+           ? gen_rtx_CONST_INT (GET_MODE (residual), probe_range)
+           : CONST0_RTX (GET_MODE (residual));
+
+         if (target_probe_range_p)
+           emit_stack_probe (stack_pointer_rtx);
+
+         emit_cmp_and_jump_insns (residual, probe_cmp_value,
+                                  op, NULL_RTX, Pmode, 1, label);
+       }
+
+      rtx x = NULL_RTX;
+
+      /* If RESIDUAL isn't a constant and TARGET_PROBE_RANGE_P then we probe up
+        by the ABI defined safe value.  */
+      if (!CONST_INT_P (residual) && target_probe_range_p)
+       x = GEN_INT (probe_range);
+      /* If RESIDUAL is a constant but smaller than the ABI defined safe value,
+        we still want to probe up, but the safest amount if a word.  */
+      else if (target_probe_range_p)
+       {
+         if (INTVAL (residual) <= probe_range)
+           x = GEN_INT (GET_MODE_SIZE (word_mode));
+         else
+           x = GEN_INT (probe_range);
+       }
+      else
+      /* If nothing else, probe at the top of the new allocation.  */
+       x = plus_constant (Pmode, residual, -GET_MODE_SIZE (word_mode));
+
+      emit_stack_probe (gen_rtx_PLUS (Pmode, stack_pointer_rtx, x));
+
+      emit_insn (gen_blockage ());
+      if (!CONST_INT_P (residual))
+         emit_label (label);
+    }
+}
+
+
 /* Adjust the stack pointer by minus SIZE (an rtx for a number of bytes)
    while probing it.  This pushes when SIZE is positive.  SIZE need not
    be constant.  If ADJUST_BACK is true, adjust back the stack pointer
@@ -1856,26 +2246,21 @@ hard_function_value (const_tree valtype, const_tree func, const_tree fntype,
   if (REG_P (val)
       && GET_MODE (val) == BLKmode)
     {
-      unsigned HOST_WIDE_INT bytes = int_size_in_bytes (valtype);
-      machine_mode tmpmode;
+      unsigned HOST_WIDE_INT bytes = arg_int_size_in_bytes (valtype);
+      opt_scalar_int_mode tmpmode;
 
       /* int_size_in_bytes can return -1.  We don't need a check here
         since the value of bytes will then be large enough that no
         mode will match anyway.  */
 
-      for (tmpmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-          tmpmode != VOIDmode;
-          tmpmode = GET_MODE_WIDER_MODE (tmpmode))
+      FOR_EACH_MODE_IN_CLASS (tmpmode, MODE_INT)
        {
          /* Have we found a large enough mode?  */
-         if (GET_MODE_SIZE (tmpmode) >= bytes)
+         if (GET_MODE_SIZE (tmpmode.require ()) >= bytes)
            break;
        }
 
-      /* No suitable mode found.  */
-      gcc_assert (tmpmode != VOIDmode);
-
-      PUT_MODE (val, tmpmode);
+      PUT_MODE (val, tmpmode.require ());
     }
   return val;
 }