]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/explow.c
* asan.c (handle_builtin_alloca): Deal with all alloca variants.
[thirdparty/gcc.git] / gcc / explow.c
index e7768aeb77db3bd6c0851899c913c43ca7dac8a4..662865d2808beceafd28ce72def65c5964037a0b 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for manipulating rtx's in semantically interesting ways.
-   Copyright (C) 1987-2015 Free Software Foundation, Inc.
+   Copyright (C) 1987-2017 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -21,49 +21,29 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "diagnostic-core.h"
+#include "target.h"
+#include "function.h"
 #include "rtl.h"
-#include "hash-set.h"
-#include "machmode.h"
-#include "vec.h"
-#include "double-int.h"
-#include "input.h"
-#include "alias.h"
-#include "symtab.h"
-#include "wide-int.h"
-#include "inchash.h"
-#include "real.h"
 #include "tree.h"
-#include "stor-layout.h"
+#include "memmodel.h"
 #include "tm_p.h"
-#include "flags.h"
-#include "except.h"
-#include "hard-reg-set.h"
-#include "function.h"
-#include "hashtab.h"
-#include "statistics.h"
-#include "fixed-value.h"
-#include "insn-config.h"
 #include "expmed.h"
+#include "profile-count.h"
+#include "optabs.h"
+#include "emit-rtl.h"
+#include "recog.h"
+#include "diagnostic-core.h"
+#include "stor-layout.h"
+#include "except.h"
 #include "dojump.h"
 #include "explow.h"
-#include "calls.h"
-#include "emit-rtl.h"
-#include "varasm.h"
-#include "stmt.h"
 #include "expr.h"
-#include "insn-codes.h"
-#include "optabs.h"
-#include "libfuncs.h"
-#include "ggc.h"
-#include "recog.h"
-#include "langhooks.h"
-#include "target.h"
 #include "common/common-target.h"
 #include "output.h"
+#include "params.h"
 
 static rtx break_out_memory_refs (rtx);
+static void anti_adjust_stack_and_probe_stack_clash (rtx);
 
 
 /* Truncate and perhaps sign-extend C as appropriate for MODE.  */
@@ -71,14 +51,16 @@ 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));
 
   /* 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.  */
@@ -121,8 +103,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
@@ -130,10 +111,23 @@ 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);
-         if (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);
+           }
+         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;
 
@@ -281,18 +275,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;
 
@@ -329,22 +325,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:
@@ -360,18 +353,25 @@ 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;
 
     default:
       break;
     }
 
+  if (no_emit)
+    return NULL_RTX;
+
   return convert_modes (to_mode, from_mode,
                        x, POINTERS_EXTEND_UNSIGNED);
 #endif /* defined(POINTERS_EXTEND_UNSIGNED) */
@@ -384,9 +384,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
 
@@ -398,7 +399,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);
 
@@ -500,9 +501,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)
@@ -514,7 +514,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
@@ -788,6 +789,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
@@ -807,10 +809,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:
@@ -818,7 +821,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:
@@ -842,8 +844,10 @@ promote_decl_mode (const_tree decl, int *punsignedp)
   machine_mode mode = DECL_MODE (decl);
   machine_mode pmode;
 
-  if (TREE_CODE (decl) == RESULT_DECL
-      || TREE_CODE (decl) == PARM_DECL)
+  if (TREE_CODE (decl) == RESULT_DECL && !DECL_BY_REFERENCE (decl))
+    pmode = promote_function_mode (type, mode, &unsignedp,
+                                   TREE_TYPE (current_function_decl), 1);
+  else if (TREE_CODE (decl) == RESULT_DECL || TREE_CODE (decl) == PARM_DECL)
     pmode = promote_function_mode (type, mode, &unsignedp,
                                    TREE_TYPE (current_function_decl), 2);
   else
@@ -854,8 +858,48 @@ promote_decl_mode (const_tree decl, int *punsignedp)
   return pmode;
 }
 
+/* Return the promoted mode for name.  If it is a named SSA_NAME, it
+   is the same as promote_decl_mode.  Otherwise, it is the promoted
+   mode of a temp decl of same type as the SSA_NAME, if we had created
+   one.  */
+
+machine_mode
+promote_ssa_mode (const_tree name, int *punsignedp)
+{
+  gcc_assert (TREE_CODE (name) == SSA_NAME);
+
+  /* Partitions holding parms and results must be promoted as expected
+     by function.c.  */
+  if (SSA_NAME_VAR (name)
+      && (TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL
+         || TREE_CODE (SSA_NAME_VAR (name)) == RESULT_DECL))
+    {
+      machine_mode mode = promote_decl_mode (SSA_NAME_VAR (name), punsignedp);
+      if (mode != BLKmode)
+       return mode;
+    }
+
+  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);
+  if (punsignedp)
+    *punsignedp = unsignedp;
+
+  return pmode;
+}
+
+
 \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.  */
@@ -866,10 +910,9 @@ adjust_stack_1 (rtx adjust, bool anti_p)
   rtx temp;
   rtx_insn *insn;
 
-#ifndef STACK_GROWS_DOWNWARD
   /* Hereafter anti_p means subtract_p.  */
-  anti_p = !anti_p;
-#endif
+  if (!STACK_GROWS_DOWNWARD)
+    anti_p = !anti_p;
 
   temp = expand_binop (Pmode,
                       anti_p ? sub_optab : add_optab,
@@ -984,30 +1027,24 @@ emit_stack_save (enum save_level save_level, rtx *psave)
 {
   rtx sa = *psave;
   /* The default is that we use a move insn and save in a Pmode object.  */
-  rtx (*fcn) (rtx, rtx) = gen_move_insn;
+  rtx_insn *(*fcn) (rtx, rtx) = gen_move_insn;
   machine_mode mode = STACK_SAVEAREA_MODE (save_level);
 
   /* See if this machine has anything special to do for this kind of save.  */
   switch (save_level)
     {
-#ifdef HAVE_save_stack_block
     case SAVE_BLOCK:
-      if (HAVE_save_stack_block)
-       fcn = gen_save_stack_block;
+      if (targetm.have_save_stack_block ())
+       fcn = targetm.gen_save_stack_block;
       break;
-#endif
-#ifdef HAVE_save_stack_function
     case SAVE_FUNCTION:
-      if (HAVE_save_stack_function)
-       fcn = gen_save_stack_function;
+      if (targetm.have_save_stack_function ())
+       fcn = targetm.gen_save_stack_function;
       break;
-#endif
-#ifdef HAVE_save_stack_nonlocal
     case SAVE_NONLOCAL:
-      if (HAVE_save_stack_nonlocal)
-       fcn = gen_save_stack_nonlocal;
+      if (targetm.have_save_stack_nonlocal ())
+       fcn = targetm.gen_save_stack_nonlocal;
       break;
-#endif
     default:
       break;
     }
@@ -1039,7 +1076,7 @@ void
 emit_stack_restore (enum save_level save_level, rtx sa)
 {
   /* The default is that we use a move insn.  */
-  rtx (*fcn) (rtx, rtx) = gen_move_insn;
+  rtx_insn *(*fcn) (rtx, rtx) = gen_move_insn;
 
   /* If stack_realign_drap, the x86 backend emits a prologue that aligns both
      STACK_POINTER and HARD_FRAME_POINTER.
@@ -1058,24 +1095,18 @@ emit_stack_restore (enum save_level save_level, rtx sa)
   /* See if this machine has anything special to do for this kind of save.  */
   switch (save_level)
     {
-#ifdef HAVE_restore_stack_block
     case SAVE_BLOCK:
-      if (HAVE_restore_stack_block)
-       fcn = gen_restore_stack_block;
+      if (targetm.have_restore_stack_block ())
+       fcn = targetm.gen_restore_stack_block;
       break;
-#endif
-#ifdef HAVE_restore_stack_function
     case SAVE_FUNCTION:
-      if (HAVE_restore_stack_function)
-       fcn = gen_restore_stack_function;
+      if (targetm.have_restore_stack_function ())
+       fcn = targetm.gen_restore_stack_function;
       break;
-#endif
-#ifdef HAVE_restore_stack_nonlocal
     case SAVE_NONLOCAL:
-      if (HAVE_restore_stack_nonlocal)
-       fcn = gen_restore_stack_nonlocal;
+      if (targetm.have_restore_stack_nonlocal ())
+       fcn = targetm.gen_restore_stack_nonlocal;
       break;
-#endif
     default:
       break;
     }
@@ -1133,6 +1164,150 @@ record_new_stack_level (void)
     update_sjlj_context ();
 }
 \f
+/* Return an rtx doing runtime alignment to REQUIRED_ALIGN on TARGET.  */
+static 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)
+{
+  unsigned extra = 0;
+  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.  */
+
+  /* Since the stack is presumed to be aligned before this allocation,
+     we only need to increase the size of the allocation if the required
+     alignment is more than the stack alignment.  */
+  if (required_align > STACK_BOUNDARY)
+    {
+      extra = (required_align - STACK_BOUNDARY) / BITS_PER_UNIT;
+      size = plus_constant (Pmode, size, extra);
+      size = force_operand (size, NULL_RTX);
+      if (size_align > STACK_BOUNDARY)
+       size_align = STACK_BOUNDARY;
+
+      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
+   should always ensure are available on the stack.  More importantly
+   this is how many bytes are 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 indirect though
+   this helper which allows us 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.
 
@@ -1141,12 +1316,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
@@ -1156,13 +1334,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
@@ -1197,108 +1375,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);
 
@@ -1314,6 +1403,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;
 
@@ -1331,16 +1422,15 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
 
       available_label = NULL;
 
-#ifdef HAVE_split_stack_space_check
-      if (HAVE_split_stack_space_check)
+      if (targetm.have_split_stack_space_check ())
        {
          available_label = gen_label_rtx ();
 
          /* This instruction will branch to AVAILABLE_LABEL if there
             are SIZE bytes available on the stack.  */
-         emit_insn (gen_split_stack_space_check (size, available_label));
+         emit_insn (targetm.gen_split_stack_space_check
+                    (size, available_label));
        }
-#endif
 
       /* The __morestack_allocate_stack_space function will allocate
         memory using malloc.  If the alignment of the memory returned
@@ -1349,18 +1439,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;
@@ -1375,8 +1462,6 @@ 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
@@ -1390,7 +1475,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;
@@ -1398,8 +1483,7 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
   /* Perform the required allocation from the stack.  Some systems do
      this differently than simply incrementing/decrementing from the
      stack pointer, such as acquiring the space by calling malloc().  */
-#ifdef HAVE_allocate_stack
-  if (HAVE_allocate_stack)
+  if (targetm.have_allocate_stack ())
     {
       struct expand_operand ops[2];
       /* We don't have to check against the predicate for operand 0 since
@@ -1407,38 +1491,34 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
         be valid for the operand.  */
       create_fixed_operand (&ops[0], target);
       create_convert_operand_to (&ops[1], size, STACK_SIZE_MODE, true);
-      expand_insn (CODE_FOR_allocate_stack, 2, ops);
+      expand_insn (targetm.code_for_allocate_stack, 2, ops);
     }
   else
-#endif
     {
       int saved_stack_pointer_delta;
 
-#ifndef STACK_GROWS_DOWNWARD
-      emit_move_insn (target, virtual_stack_dynamic_rtx);
-#endif
+      if (!STACK_GROWS_DOWNWARD)
+       emit_move_insn (target, virtual_stack_dynamic_rtx);
 
       /* Check stack bounds if necessary.  */
       if (crtl->limit_stack)
        {
          rtx available;
          rtx_code_label *space_available = gen_label_rtx ();
-#ifdef STACK_GROWS_DOWNWARD
-         available = expand_binop (Pmode, sub_optab,
-                                   stack_pointer_rtx, stack_limit_rtx,
-                                   NULL_RTX, 1, OPTAB_WIDEN);
-#else
-         available = expand_binop (Pmode, sub_optab,
-                                   stack_limit_rtx, stack_pointer_rtx,
-                                   NULL_RTX, 1, OPTAB_WIDEN);
-#endif
+         if (STACK_GROWS_DOWNWARD)
+           available = expand_binop (Pmode, sub_optab,
+                                     stack_pointer_rtx, stack_limit_rtx,
+                                     NULL_RTX, 1, OPTAB_WIDEN);
+         else
+           available = expand_binop (Pmode, sub_optab,
+                                     stack_limit_rtx, stack_pointer_rtx,
+                                     NULL_RTX, 1, OPTAB_WIDEN);
+
          emit_cmp_and_jump_insns (available, size, GEU, NULL_RTX, Pmode, 1,
                                   space_available);
-#ifdef HAVE_trap
-         if (HAVE_trap)
-           emit_insn (gen_trap ());
+         if (targetm.have_trap ())
+           emit_insn (targetm.gen_trap ());
          else
-#endif
            error ("stack limits not supported on this target");
          emit_barrier ();
          emit_label (space_available);
@@ -1448,6 +1528,8 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
 
       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);
 
@@ -1456,9 +1538,8 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
         crtl->preferred_stack_boundary alignment.  */
       stack_pointer_delta = saved_stack_pointer_delta;
 
-#ifdef STACK_GROWS_DOWNWARD
-      emit_move_insn (target, virtual_stack_dynamic_rtx);
-#endif
+      if (STACK_GROWS_DOWNWARD)
+       emit_move_insn (target, virtual_stack_dynamic_rtx);
     }
 
   suppress_reg_args_size = false;
@@ -1472,24 +1553,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 +1563,38 @@ 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.  */
+
+rtx
+get_dynamic_stack_base (HOST_WIDE_INT offset, unsigned required_align)
+{
+  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, virtual_stack_vars_rtx);
+  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
@@ -1518,22 +1614,18 @@ set_stack_check_libfunc (const char *libfunc_name)
 void
 emit_stack_probe (rtx address)
 {
-#ifdef HAVE_probe_stack_address
-  if (HAVE_probe_stack_address)
-    emit_insn (gen_probe_stack_address (address));
+  if (targetm.have_probe_stack_address ())
+    emit_insn (targetm.gen_probe_stack_address (address));
   else
-#endif
     {
       rtx memref = gen_rtx_MEM (word_mode, address);
 
       MEM_VOLATILE_P (memref) = 1;
 
       /* See if we have an insn to probe the stack.  */
-#ifdef HAVE_probe_stack
-      if (HAVE_probe_stack)
-        emit_insn (gen_probe_stack (memref));
+      if (targetm.have_probe_stack ())
+        emit_insn (targetm.gen_probe_stack (memref));
       else
-#endif
         emit_move_insn (memref, const0_rtx);
     }
 }
@@ -1545,7 +1637,7 @@ emit_stack_probe (rtx address)
 
 #define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP)
 
-#ifdef STACK_GROWS_DOWNWARD
+#if STACK_GROWS_DOWNWARD
 #define STACK_GROW_OP MINUS
 #define STACK_GROW_OPTAB sub_optab
 #define STACK_GROW_OFF(off) -(off)
@@ -1570,13 +1662,12 @@ 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.  */
-#ifdef HAVE_check_stack
-  else if (HAVE_check_stack)
+  else if (targetm.have_check_stack ())
     {
       struct expand_operand ops[1];
       rtx addr = memory_address (Pmode,
@@ -1586,10 +1677,9 @@ probe_stack_range (HOST_WIDE_INT first, rtx size)
                                                                size, first)));
       bool success;
       create_input_operand (&ops[0], addr, Pmode);
-      success = maybe_expand_insn (CODE_FOR_check_stack, 1, ops);
+      success = maybe_expand_insn (targetm.code_for_check_stack, 1, ops);
       gcc_assert (success);
     }
-#endif
 
   /* Otherwise we have to generate explicit probes.  If we have a constant
      small number of them to generate, that's the easy case.  */
@@ -1715,6 +1805,220 @@ 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_VALUE (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 probes on the first couple PROBE_INTERVALs on the assumption
+       they're done elsewhere.
+
+     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.  */
+
+static 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;
+  compute_stack_clash_protection_loop_data (&rounded_size, &last_addr,
+                                           &residual, &probe_interval, size);
+
+  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_interval
+                                               - GET_MODE_SIZE (word_mode))));
+             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_interval
+                                           - GET_MODE_SIZE (word_mode))));
+
+         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 x = force_reg (Pmode, plus_constant (Pmode, residual,
+                                              -GET_MODE_SIZE (word_mode)));
+      anti_adjust_stack (residual);
+      emit_stack_probe (gen_rtx_PLUS (Pmode, stack_pointer_rtx, x));
+      emit_insn (gen_blockage ());
+    }
+
+  /* Some targets make optimistic assumptions in their prologues about
+     how the caller may have probed the stack.  Make sure we honor
+     those assumptions when needed.  */
+  if (size != CONST0_RTX (Pmode)
+      && targetm.stack_clash_protection_final_dynamic_probe (residual))
+    {
+      /* Ideally we would just probe at *sp.  However, if SIZE is not
+        a compile-time constant, but is zero at runtime, then *sp
+        might hold live data.  So probe at *sp if we know that
+        an allocation was made, otherwise probe into the red zone
+        which is obviously undesirable.  */
+      if (CONST_INT_P (size))
+       {
+         emit_stack_probe (stack_pointer_rtx);
+         emit_insn (gen_blockage ());
+       }
+      else
+       {
+         emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
+                                          -GET_MODE_SIZE (word_mode)));
+         emit_insn (gen_blockage ());
+       }
+    }
+}
+
+
 /* 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
@@ -1863,25 +2167,20 @@ hard_function_value (const_tree valtype, const_tree func, const_tree fntype,
       && GET_MODE (val) == BLKmode)
     {
       unsigned HOST_WIDE_INT bytes = int_size_in_bytes (valtype);
-      machine_mode tmpmode;
+      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;
 }
@@ -1896,7 +2195,7 @@ hard_libcall_value (machine_mode mode, rtx fun)
 }
 
 /* Look up the tree code for a given rtx code
-   to provide the arithmetic operation for REAL_ARITHMETIC.
+   to provide the arithmetic operation for real_arithmetic.
    The function returns an int because the caller may not know
    what `enum tree_code' means.  */