@@ -7245,6 +7245,10 @@ riscv_compute_frame_info (void)
frame = &cfun->machine->frame;
+ /* Adjust the outgoing arguments size if required. Keep it in sync with what
+ the mid-end is doing. */
+ crtl->outgoing_args_size = STACK_DYNAMIC_OFFSET (cfun);
+
/* In an interrupt function, there are two cases in which t0 needs to be used:
1, If we have a large frame, then we need to save/restore t0. We check for
this before clearing the frame struct.
@@ -11879,6 +11883,15 @@ riscv_c_mode_for_floating_type (enum tree_index ti)
return default_mode_for_floating_type (ti);
}
+/* On riscv we have an ABI defined safe buffer. This constant is used to
+ determining the probe offset for alloca. */
+
+static HOST_WIDE_INT
+riscv_stack_clash_protection_alloca_probe_range (void)
+{
+ return STACK_CLASH_CALLER_GUARD;
+}
+
/* Initialize the GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
@@ -12187,6 +12200,10 @@ riscv_c_mode_for_floating_type (enum tree_index ti)
#define TARGET_VECTORIZE_PREFERRED_VECTOR_ALIGNMENT \
riscv_vectorize_preferred_vector_alignment
+#undef TARGET_STACK_CLASH_PROTECTION_ALLOCA_PROBE_RANGE
+#define TARGET_STACK_CLASH_PROTECTION_ALLOCA_PROBE_RANGE \
+ riscv_stack_clash_protection_alloca_probe_range
+
/* Mode switching hooks. */
#undef TARGET_MODE_EMIT
@@ -1270,4 +1270,21 @@ extern void riscv_remove_unneeded_save_restore_calls (void);
generating stack clash probes. */
#define STACK_CLASH_MAX_UNROLL_PAGES 4
+/* This value represents the minimum amount of bytes we expect the function's
+ outgoing arguments to be when stack-clash is enabled. */
+#define STACK_CLASH_MIN_BYTES_OUTGOING_ARGS 8
+
+/* Allocate a minimum of STACK_CLASH_MIN_BYTES_OUTGOING_ARGS bytes for the
+ outgoing arguments if stack clash protection is enabled. This is essential
+ as the extra arg space allows us to skip a check in alloca. */
+#undef STACK_DYNAMIC_OFFSET
+#define STACK_DYNAMIC_OFFSET(FUNDECL) \
+ ((flag_stack_clash_protection \
+ && cfun->calls_alloca \
+ && known_lt (crtl->outgoing_args_size, \
+ STACK_CLASH_MIN_BYTES_OUTGOING_ARGS)) \
+ ? ROUND_UP (STACK_CLASH_MIN_BYTES_OUTGOING_ARGS, \
+ STACK_BOUNDARY / BITS_PER_UNIT) \
+ : (crtl->outgoing_args_size + STACK_POINTER_OFFSET))
+
#endif /* ! GCC_RISCV_H */
new file mode 100644
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+int t1(int);
+
+int t2(int x)
+{
+ char *p = __builtin_alloca (2048);
+ x = t1 (x);
+ return p[x];
+}
+
+
+/* This test has a constant sized alloca that is smaller than the
+ probe interval. Only one probe is required since the value is larger
+ than 1024 bytes but smaller than page size.
+
+ The form can change quite a bit so we just check for one
+ probe without looking at the actual address. */
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
+
+
+
new file mode 100644
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+int t1(int);
+
+int t2(int x)
+{
+ char *p = __builtin_alloca (x);
+ x = t1 (x);
+ return p[x];
+}
+
+
+/* This test has a variable sized alloca. It requires 3 probes.
+ One in the loop, one for the residual, one for when it's < 1024 and one for
+ when it's not.
+
+ The form can change quite a bit so we just check for three
+ probes without looking at the actual address. */
+/* { dg-final { scan-assembler-times {sd\tzero,} 3 } } */
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-require-effective-target alloca } */
+
+#define SIZE y
+#include "stack-check-alloca.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 2 } } */
+/* { dg-final { scan-assembler-times {sd\tzero,0\(sp\)} 1 } } */
+
+/* Dynamic alloca, expect loop, and 2 probes with 1kB offset and 1 at sp.
+ 1st probe is inside the loop for the full guard-size allocations, second
+ probe is for the case where residual is zero and the final probe for when
+ residiual is > 1024 bytes. */
new file mode 100644
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-require-effective-target alloca } */
+
+#define SIZE 127.5 * 3 * 1024
+#include "stack-check-alloca.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 2 } } */
+
+/* Large alloca of an amount which isn't a multiple of a guard-size, and
+ residiual is more than 1kB. Loop expected with one 1Kb probe offset and
+ one residual probe at offset 1kB. */
new file mode 100644
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-require-effective-target alloca } */
+
+#define SIZE 0
+#include "stack-check-alloca.h"
+
+/* { dg-final { scan-assembler-not {sd\tzero,} } } */
+
+/* Alloca of 0 should emit no probes, boundary condition. */
new file mode 100644
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-require-effective-target alloca } */
+
+#define SIZE 100
+#include "stack-check-alloca.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,8\(sp\)} 1 } } */
+
+/* Alloca is less than 1kB, 1 probe expected at word offset. */
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-require-effective-target alloca } */
+
+#define SIZE 1.5 * 1024
+#include "stack-check-alloca.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
+
+/* Alloca is more than 1kB, but less than guard-size, 1 probe expected at
+ 1kB offset. */
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-require-effective-target alloca } */
+
+#define SIZE 2 * 1024
+#include "stack-check-alloca.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
+
+/* Alloca is more than 1kB, but less than guard-size, 1 probe expected at
+ 1kB offset. */
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-require-effective-target alloca } */
+
+#define SIZE 2.5 * 1024
+#include "stack-check-alloca.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
+
+/* Alloca is more than 1kB, but less than guard-size, 1 probe expected at 1kB
+ offset. */
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-require-effective-target alloca } */
+
+#define SIZE 3 * 1024
+#include "stack-check-alloca.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
+
+/* Alloca is exactly one guard-size, 1 probe expected at 1kB offset.
+ Boundary condition. */
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection --param stack-clash-protection-guard-size=16" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-require-effective-target alloca } */
+
+#define SIZE 65 * 1024
+#include "stack-check-alloca.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
+/* { dg-final { scan-assembler-times {sd\tzero,8\(sp\)} 1 } } */
+
+/* Alloca is more than one guard-page, and residual is exactly 1Kb. 2 probes
+ expected. One at 1kB offset for the guard-size allocation and one at word
+ offset for the residual. */
new file mode 100644
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-require-effective-target alloca } */
+
+#define SIZE 127 * 3 * 1024
+#include "stack-check-alloca.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
+
+/* Large alloca of a constant amount which is a multiple of a guard-size,
+ no residiual. Loop expected with one 1Kb probe offset and no residual probe
+ because residual is at compile time known to be zero. */
new file mode 100644
@@ -0,0 +1,15 @@
+
+/* Avoid inclusion of alloca.h, unavailable on some systems. */
+#define alloca __builtin_alloca
+
+__attribute__((noinline, noipa))
+void g (char* ptr, int y)
+{
+ ptr[y] = '\0';
+}
+
+void f_caller (int y)
+{
+ char* pStr = alloca(SIZE);
+ g (pStr, y);
+}