]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/explow.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / explow.c
index 638dc5f8f0fcadb4c71aa2727b4ad0a3a4a3209e..b6da277f6896a75e66319ad326ec3d84f89fa073 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for manipulating rtx's in semantically interesting ways.
-   Copyright (C) 1987-2017 Free Software Foundation, Inc.
+   Copyright (C) 1987-2021 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -27,9 +27,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "memmodel.h"
 #include "tm_p.h"
+#include "optabs.h"
 #include "expmed.h"
 #include "profile-count.h"
-#include "optabs.h"
 #include "emit-rtl.h"
 #include "recog.h"
 #include "diagnostic-core.h"
@@ -38,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"
 
@@ -54,8 +55,7 @@ trunc_int_for_mode (HOST_WIDE_INT c, machine_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 (smode == BImode)
@@ -75,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;
@@ -90,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:
@@ -117,6 +127,9 @@ plus_constant (machine_mode mode, rtx x, HOST_WIDE_INT c,
              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);
@@ -178,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)
@@ -208,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;
@@ -220,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;
@@ -363,6 +378,26 @@ convert_memory_address_addr_space_1 (scalar_int_mode to_mode ATTRIBUTE_UNUSED,
        }
       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;
     }
@@ -879,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;
 
@@ -927,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).
@@ -941,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);
 }
@@ -958,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);
 }
@@ -1161,9 +1189,10 @@ 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.  */
-static rtx
+
+rtx
 align_dynamic_address (rtx target, unsigned required_align)
 {
   /* CEIL_DIV_EXPR needs to worry about the addition overflowing,
@@ -1204,7 +1233,6 @@ 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.  */
@@ -1240,16 +1268,16 @@ get_dynamic_stack_size (rtx *psize, unsigned size_align,
      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)
+  unsigned known_align = REGNO_POINTER_ALIGN (VIRTUAL_STACK_DYNAMIC_REGNUM);
+  if (known_align == 0)
+    known_align = BITS_PER_UNIT;
+  if (required_align > known_align)
     {
-      extra = (required_align - STACK_BOUNDARY) / BITS_PER_UNIT;
+      unsigned extra = (required_align - known_align) / 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 (size_align > known_align)
+       size_align = known_align;
 
       if (flag_stack_usage_info && pstack_usage_size)
        *pstack_usage_size += extra;
@@ -1283,6 +1311,31 @@ get_dynamic_stack_size (rtx *psize, unsigned size_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.
 
@@ -1297,6 +1350,9 @@ get_dynamic_stack_size (rtx *psize, unsigned size_align,
    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
@@ -1306,7 +1362,9 @@ get_dynamic_stack_size (rtx *psize, unsigned size_align,
 
 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;
@@ -1345,8 +1403,12 @@ 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;
@@ -1430,8 +1492,8 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
 
  /* 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.  */
@@ -1441,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;
@@ -1451,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.  */
@@ -1461,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);
@@ -1492,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);
 
@@ -1537,10 +1603,14 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
    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.  */
+   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 (HOST_WIDE_INT offset, unsigned required_align)
+get_dynamic_stack_base (poly_int64 offset, unsigned required_align, rtx base)
 {
   rtx target;
 
@@ -1548,7 +1618,7 @@ get_dynamic_stack_base (HOST_WIDE_INT offset, unsigned required_align)
     crtl->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
 
   target = gen_reg_rtx (Pmode);
-  emit_move_insn (target, virtual_stack_vars_rtx);
+  emit_move_insn (target, base);
   target = expand_binop (Pmode, add_optab, target,
                         gen_int_mode (offset, Pmode),
                         NULL_RTX, 1, OPTAB_LIB_WIDEN);
@@ -1571,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.  */
@@ -1579,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);
     }
 }
 
@@ -1633,7 +1714,7 @@ probe_stack_range (HOST_WIDE_INT first, rtx size)
   /* 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,
@@ -1769,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
@@ -1916,7 +2246,7 @@ 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);
+      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