Add the TARGET_STACK_CLASH_PROTECTION_ALLOCA_PROBE_RANGE to riscv in
order to enable stack clash protection when using alloca.
The code and tests are the same used by aarch64.

gcc/ChangeLog:
        * config/riscv/riscv.cc (riscv_compute_frame_info): Update
          outgoing args size.
          (riscv_stack_clash_protection_alloca_probe_range): New.
          (TARGET_STACK_CLASH_PROTECTION_ALLOCA_PROBE_RANGE): New.
        * config/riscv/riscv.h
          (STACK_CLASH_MIN_BYTES_OUTGOING_ARGS): New.
          (STACK_DYNAMIC_OFFSET): New.

gcc/testsuite/ChangeLog:
        * gcc.target/riscv/stack-check-14.c: New test.
        * gcc.target/riscv/stack-check-15.c: New test.
        * gcc.target/riscv/stack-check-alloca-1.c: New test.
        * gcc.target/riscv/stack-check-alloca-2.c: New test.
        * gcc.target/riscv/stack-check-alloca-3.c: New test.
        * gcc.target/riscv/stack-check-alloca-4.c: New test.
        * gcc.target/riscv/stack-check-alloca-5.c: New test.
        * gcc.target/riscv/stack-check-alloca-6.c: New test.
        * gcc.target/riscv/stack-check-alloca-7.c: New test.
        * gcc.target/riscv/stack-check-alloca-8.c: New test.
        * gcc.target/riscv/stack-check-alloca-9.c: New test.
        * gcc.target/riscv/stack-check-alloca-10.c: New test.
        * gcc.target/riscv/stack-check-alloca.h: New.
---
 gcc/config/riscv/riscv.cc                     | 17 +++++++++++++
 gcc/config/riscv/riscv.h                      | 17 +++++++++++++
 .../gcc.target/riscv/stack-check-14.c         | 24 +++++++++++++++++++
 .../gcc.target/riscv/stack-check-15.c         | 21 ++++++++++++++++
 .../gcc.target/riscv/stack-check-alloca-1.c   | 15 ++++++++++++
 .../gcc.target/riscv/stack-check-alloca-10.c  | 13 ++++++++++
 .../gcc.target/riscv/stack-check-alloca-2.c   | 11 +++++++++
 .../gcc.target/riscv/stack-check-alloca-3.c   | 11 +++++++++
 .../gcc.target/riscv/stack-check-alloca-4.c   | 12 ++++++++++
 .../gcc.target/riscv/stack-check-alloca-5.c   | 12 ++++++++++
 .../gcc.target/riscv/stack-check-alloca-6.c   | 12 ++++++++++
 .../gcc.target/riscv/stack-check-alloca-7.c   | 12 ++++++++++
 .../gcc.target/riscv/stack-check-alloca-8.c   | 14 +++++++++++
 .../gcc.target/riscv/stack-check-alloca-9.c   | 13 ++++++++++
 .../gcc.target/riscv/stack-check-alloca.h     | 15 ++++++++++++
 15 files changed, 219 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-14.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-15.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-alloca-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-alloca-10.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-alloca-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-alloca-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-alloca-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-alloca-5.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-alloca-6.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-alloca-7.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-alloca-8.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-alloca-9.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-alloca.h

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 69c0e07f4c5..a110e011766 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -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
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 0432beb81e0..7f20190e960 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -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 */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-14.c 
b/gcc/testsuite/gcc.target/riscv/stack-check-14.c
new file mode 100644
index 00000000000..8ca0488c468
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-14.c
@@ -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 } } */
+
+
+
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-15.c 
b/gcc/testsuite/gcc.target/riscv/stack-check-15.c
new file mode 100644
index 00000000000..a44b257ba75
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-15.c
@@ -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 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-1.c 
b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-1.c
new file mode 100644
index 00000000000..642840fb50c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-1.c
@@ -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.  */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-10.c 
b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-10.c
new file mode 100644
index 00000000000..11844aad748
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-10.c
@@ -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.  */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-2.c 
b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-2.c
new file mode 100644
index 00000000000..5c7a158adec
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-2.c
@@ -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.  */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-3.c 
b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-3.c
new file mode 100644
index 00000000000..a5db2679aef
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-3.c
@@ -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.  */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-4.c 
b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-4.c
new file mode 100644
index 00000000000..1841412ff36
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-4.c
@@ -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.  */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-5.c 
b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-5.c
new file mode 100644
index 00000000000..f8f9d944564
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-5.c
@@ -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.  */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-6.c 
b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-6.c
new file mode 100644
index 00000000000..d937e929d75
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-6.c
@@ -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.  */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-7.c 
b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-7.c
new file mode 100644
index 00000000000..cbb32f3157e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-7.c
@@ -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.  */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-8.c 
b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-8.c
new file mode 100644
index 00000000000..3cc3450355b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-8.c
@@ -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.  */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-9.c 
b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-9.c
new file mode 100644
index 00000000000..36466930e4e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-9.c
@@ -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.  */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca.h 
b/gcc/testsuite/gcc.target/riscv/stack-check-alloca.h
new file mode 100644
index 00000000000..8c75f6c0f70
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca.h
@@ -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);
+}
-- 
2.42.0

Reply via email to