@@ -7950,6 +7950,191 @@ get_multi_push_fpr_mask (unsigned max_fprs_push)
return mask_fprs_push;
}
+/* Allocate SIZE bytes of stack space using TEMP1 as a scratch register.
+ If SIZE is not large enough to require a probe this function will only
+ adjust the stack.
+
+ We emit barriers after each stack adjustment to prevent optimizations from
+ breaking the invariant that we never drop the stack more than a page. This
+ invariant is needed to make it easier to correctly handle asynchronous
+ events, e.g. if we were to allow the stack to be dropped by more than a page
+ and then have multiple probes up and we take a signal somewhere in between
+ then the signal handler doesn't know the state of the stack and can make no
+ assumptions about which pages have been probed. */
+
+static void
+riscv_allocate_and_probe_stack_space (rtx temp1, HOST_WIDE_INT size)
+{
+ HOST_WIDE_INT guard_size
+ = 1 << param_stack_clash_protection_guard_size;
+ HOST_WIDE_INT guard_used_by_caller = STACK_CLASH_CALLER_GUARD;
+ HOST_WIDE_INT byte_sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
+ HOST_WIDE_INT min_probe_threshold = guard_size - guard_used_by_caller;
+ rtx insn;
+
+ /* We should always have a positive probe threshold. */
+ gcc_assert (min_probe_threshold > 0);
+
+ /* If SIZE is not large enough to require probing, just adjust the stack and
+ exit. */
+ if (known_lt (size, min_probe_threshold)
+ || !flag_stack_clash_protection)
+ {
+ if (flag_stack_clash_protection)
+ {
+ if (known_eq (cfun->machine->frame.total_size, 0))
+ dump_stack_clash_frame_info (NO_PROBE_NO_FRAME, false);
+ else
+ dump_stack_clash_frame_info (NO_PROBE_SMALL_FRAME, true);
+ }
+
+ if (SMALL_OPERAND (-size))
+ {
+ insn = gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-size));
+ RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
+ }
+ else if (SUM_OF_TWO_S12_ALGN (-size))
+ {
+ HOST_WIDE_INT one, two;
+ riscv_split_sum_of_two_s12 (-size, &one, &two);
+ insn = gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (one));
+ RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
+ insn = gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (two));
+ RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
+ }
+ else
+ {
+ temp1 = riscv_force_temporary (temp1, GEN_INT (-size));
+ emit_insn (gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx, temp1));
+ insn = plus_constant (Pmode, stack_pointer_rtx, -size);
+ insn = gen_rtx_SET (stack_pointer_rtx, insn);
+ riscv_set_frame_expr (insn);
+ }
+
+ /* We must have allocated the remainder of the stack frame.
+ Emit a stack tie if we have a frame pointer so that the
+ allocation is ordered WRT fp setup and subsequent writes
+ into the frame. */
+ if (frame_pointer_needed)
+ riscv_emit_stack_tie (hard_frame_pointer_rtx);
+
+ return;
+ }
+
+ gcc_assert (multiple_p (size, byte_sp_alignment));
+
+ if (dump_file)
+ fprintf (dump_file,
+ "Stack clash prologue: " HOST_WIDE_INT_PRINT_DEC
+ " bytes, probing will be required.\n", size);
+
+ /* Round size to the nearest multiple of guard_size, and calculate the
+ residual as the difference between the original size and the rounded
+ size. */
+ HOST_WIDE_INT rounded_size = ROUND_DOWN (size, guard_size);
+ HOST_WIDE_INT residual = size - rounded_size;
+
+ /* We can handle a small number of allocations/probes inline. Otherwise
+ punt to a loop. */
+ if (rounded_size <= STACK_CLASH_MAX_UNROLL_PAGES * guard_size)
+ {
+ temp1 = riscv_force_temporary (temp1, gen_int_mode (guard_size, Pmode));
+ for (HOST_WIDE_INT i = 0; i < rounded_size; i += guard_size)
+ {
+ emit_insn (gen_sub3_insn (stack_pointer_rtx, stack_pointer_rtx, temp1));
+ insn = plus_constant (Pmode, stack_pointer_rtx, -guard_size);
+ insn = gen_rtx_SET (stack_pointer_rtx, insn);
+ riscv_set_frame_expr (insn);
+ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
+ guard_used_by_caller));
+ emit_insn (gen_blockage ());
+ }
+ dump_stack_clash_frame_info (PROBE_INLINE, size != rounded_size);
+ }
+ else
+ {
+ /* Compute the ending address. */
+ temp1 = riscv_force_temporary (temp1, gen_int_mode (rounded_size, Pmode));
+ insn = emit_insn (gen_sub3_insn (temp1, stack_pointer_rtx, temp1));
+
+ if (!frame_pointer_needed)
+ {
+ /* We want the CFA independent of the stack pointer for the
+ duration of the loop. */
+ add_reg_note (insn, REG_CFA_DEF_CFA,
+ plus_constant (Pmode, temp1, rounded_size));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ /* Allocate and probe the stack. */
+
+ rtx temp2 = gen_rtx_REG (Pmode, RISCV_PROLOGUE_TEMP2_REGNUM);
+ temp2 = riscv_force_temporary (temp2, gen_int_mode (guard_size, Pmode));
+
+ /* Loop. */
+ rtx label = gen_label_rtx ();
+ emit_label (label);
+
+ emit_insn (gen_sub3_insn (stack_pointer_rtx, stack_pointer_rtx, temp2));
+ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
+ guard_used_by_caller));
+ emit_insn (gen_blockage ());
+
+ /* Check if the stack pointer is at the ending address. */
+ riscv_expand_conditional_branch (label, NE, stack_pointer_rtx, temp1);
+ JUMP_LABEL (get_last_insn ()) = label;
+
+ emit_insn (gen_blockage ());
+
+ /* Now reset the CFA register if needed. */
+ if (!frame_pointer_needed)
+ {
+ insn = get_last_insn ();
+ add_reg_note (insn, REG_CFA_DEF_CFA,
+ plus_constant (Pmode, stack_pointer_rtx, rounded_size));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ dump_stack_clash_frame_info (PROBE_LOOP, size != rounded_size);
+ }
+
+ /* Handle any residuals. Residuals of at least MIN_PROBE_THRESHOLD have to
+ be probed. This maintains the requirement that each page is probed at
+ least once. For initial probing we probe only if the allocation is
+ more than GUARD_SIZE - buffer, and below the saved registers we probe
+ if the amount is larger than buffer. GUARD_SIZE - buffer + buffer ==
+ GUARD_SIZE. This works that for any allocation that is large enough to
+ trigger a probe here, we'll have at least one, and if they're not large
+ enough for this code to emit anything for them, The page would have been
+ probed by the saving of FP/LR either by this function or any callees. If
+ we don't have any callees then we won't have more stack adjustments and so
+ are still safe. */
+ if (residual)
+ {
+ gcc_assert (guard_used_by_caller + byte_sp_alignment <= size);
+
+ temp1 = riscv_force_temporary (temp1, gen_int_mode (residual, Pmode));
+ emit_insn (gen_sub3_insn (stack_pointer_rtx, stack_pointer_rtx, temp1));
+ insn = plus_constant (Pmode, stack_pointer_rtx, -residual);
+ insn = gen_rtx_SET (stack_pointer_rtx, insn);
+ riscv_set_frame_expr (insn);
+ if (residual >= min_probe_threshold)
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "Stack clash prologue residuals: "
+ HOST_WIDE_INT_PRINT_DEC " bytes, probing will be required."
+ "\n", residual);
+
+ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
+ guard_used_by_caller));
+ emit_insn (gen_blockage ());
+ }
+ }
+}
+
/* Expand the "prologue" pattern. */
void
@@ -8112,42 +8297,14 @@ riscv_expand_prologue (void)
return;
}
- if (SMALL_OPERAND (-constant_frame))
- {
- insn = gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (-constant_frame));
- RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
- }
- else if (SUM_OF_TWO_S12_ALGN (-constant_frame))
- {
- HOST_WIDE_INT one, two;
- riscv_split_sum_of_two_s12 (-constant_frame, &one, &two);
- insn = gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (one));
- RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
- insn = gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (two));
- RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
- }
+ riscv_allocate_and_probe_stack_space (RISCV_PROLOGUE_TEMP (Pmode), constant_frame);
+ }
+ else if (flag_stack_clash_protection)
+ {
+ if (known_eq (frame->total_size, 0))
+ dump_stack_clash_frame_info (NO_PROBE_NO_FRAME, false);
else
- {
- riscv_emit_move (RISCV_PROLOGUE_TEMP (Pmode), GEN_INT (-constant_frame));
- emit_insn (gen_add3_insn (stack_pointer_rtx,
- stack_pointer_rtx,
- RISCV_PROLOGUE_TEMP (Pmode)));
-
- /* Describe the effect of the previous instructions. */
- insn = plus_constant (Pmode, stack_pointer_rtx, -constant_frame);
- insn = gen_rtx_SET (stack_pointer_rtx, insn);
- riscv_set_frame_expr (insn);
- }
-
- /* We must have allocated the remainder of the stack frame.
- Emit a stack tie if we have a frame pointer so that the
- allocation is ordered WRT fp setup and subsequent writes
- into the frame. */
- if (frame_pointer_needed)
- riscv_emit_stack_tie (hard_frame_pointer_rtx);
+ dump_stack_clash_frame_info (NO_PROBE_SMALL_FRAME, true);
}
}
@@ -9894,6 +10051,23 @@ riscv_option_override (void)
riscv_stack_protector_guard_offset = offs;
}
+ int guard_size = param_stack_clash_protection_guard_size;
+
+ /* Enforce that interval is the same size as guard size so the mid-end does
+ the right thing. */
+ SET_OPTION_IF_UNSET (&global_options, &global_options_set,
+ param_stack_clash_protection_probe_interval,
+ guard_size);
+
+ /* The maybe_set calls won't update the value if the user has explicitly set
+ one. Which means we need to validate that probing interval and guard size
+ are equal. */
+ int probe_interval
+ = param_stack_clash_protection_probe_interval;
+ if (guard_size != probe_interval)
+ error ("stack clash guard size %<%d%> must be equal to probing interval "
+ "%<%d%>", guard_size, probe_interval);
+
SET_OPTION_IF_UNSET (&global_options, &global_options_set,
param_sched_pressure_algorithm,
SCHED_PRESSURE_MODEL);
@@ -1260,4 +1260,12 @@ extern void riscv_remove_unneeded_save_restore_calls (void);
/* Check TLS Descriptors mechanism is selected. */
#define TARGET_TLSDESC (riscv_tls_dialect == TLS_DESCRIPTORS)
+/* This value is the amount of bytes a caller is allowed to drop the stack
+ before probing has to be done for stack clash protection. */
+#define STACK_CLASH_CALLER_GUARD 1024
+
+/* This value controls how many pages we manually unroll the loop for when
+ generating stack clash probes. */
+#define STACK_CLASH_MAX_UNROLL_PAGES 4
+
#endif /* ! GCC_RISCV_H */
@@ -1,4 +1,4 @@
-/* { dg-skip-if "AArch64 does not support these bounds." { aarch64*-*-* } { "--param stack-clash-protection-*" } } */
+/* { dg-skip-if "RISC-V and AArch64 do not support these bounds." { riscv*-*-* aarch64*-*-* } { "--param stack-clash-protection-*" } } */
/* { dg-skip-if "For 32-bit hosts such param is too much and even for 64-bit might require hundreds of GB of RAM" { *-*-* } { "--param min-nondebug-insn-uid=1073741824" } } */
/*-------------------------------------------------------------*/
@@ -1,5 +1,5 @@
/* { dg-do run } */
/* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-probe-interval=10 --param stack-clash-protection-guard-size=12" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
-/* { dg-skip-if "AArch64 does not support this interval." { aarch64*-*-* } } */
+/* { dg-skip-if "RISC-V and AArch64 do not support this interval." { riscv*-*-* aarch64*-*-* } } */
int main() { int a[1442]; return 0;}
@@ -48,7 +48,7 @@ f7 (void)
/* { dg-final { scan-rtl-dump-times "Stack clash inline probes" 2 "pro_and_epilogue" } } */
/* { dg-final { scan-rtl-dump-times "Stack clash probe loop" 2 "pro_and_epilogue" } } */
-/* { dg-final { scan-rtl-dump-times "Stack clash residual allocation in prologue" 4 "pro_and_epilogue" } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash residual allocation in prologue" 4 "pro_and_epilogue" { target { ! riscv*-*-* } } } } */
/* { dg-final { scan-rtl-dump-times "Stack clash not noreturn" 4 "pro_and_epilogue" } } */
/* { dg-final { scan-rtl-dump-times "Stack clash no frame pointer needed" 4 "pro_and_epilogue" { target { ! frame_pointer_for_non_leaf } } } } */
@@ -5,7 +5,7 @@
/* { dg-options "-O2 -fstack-clash-protection -fdump-rtl-pro_and_epilogue -fno-optimize-sibling-calls --param stack-clash-protection-probe-interval=12 --param stack-clash-protection-guard-size=16" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
/* { dg-skip-if "" { *-*-* } { "-fstack-protector*" } { "" } } */
-/* { dg-skip-if "" { aarch64*-*-* } } */
+/* { dg-skip-if "" { riscv*-*-* aarch64*-*-* } } */
#include "stack-check-6.c"
new file mode 100644
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection -fno-asynchronous-unwind-tables -fno-unwind-tables -fno-stack-protector --param stack-clash-protection-guard-size=16" } */
+/* { dg-skip-if "" { *-*-* } { "-g"} } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+typedef unsigned __attribute__((mode(DI))) uint64_t;
+
+extern void arf (uint64_t *, uint64_t *);
+void
+frob ()
+{
+ uint64_t num[10000];
+ uint64_t den[10000];
+ arf (den, num);
+}
+
+/* This verifies that the scheduler did not break the dependencies
+ by adjusting the offsets within the probe and that the scheduler
+ did not reorder around the stack probes. */
+/* { dg-final { scan-assembler-times "li\\tt0,65536" 1 } } */
+/* { dg-final { scan-assembler-times "sub\\tsp,sp,t0\\n\\tsd\\tzero,1024\\(sp\\)" 2 } } */
+/* There is some residual allocation, but we don't care about that. Only that it's not probed. */
+/* { dg-final { scan-assembler-times "sd\\tzero," 2 } } */
new file mode 100644
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection -fno-asynchronous-unwind-tables -fno-unwind-tables" } */
+/* { dg-skip-if "" { *-*-* } { "-g"} } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+#define ARG32(X) X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X
+#define ARG384(X) ARG32(X),ARG32(X),ARG32(X),ARG32(X),ARG32(X),ARG32(X), ARG32(X),ARG32(X),ARG32(X),ARG32(X),ARG32(X),ARG32(X)
+void out1(ARG384(__int128));
+int t1(int);
+
+int t3(int x)
+{
+ if (x < 1000)
+ return t1 (x) + 1;
+
+ out1 (ARG384(1));
+ return 0;
+}
+
+
+
+/* This test creates a large (> 1k) outgoing argument area that needs
+ to be probed. We don't test the exact size of the space or the
+ exact offset to make the test a little less sensitive to trivial
+ output changes. */
+/* { dg-final { scan-assembler-times "sub\\tsp,sp,t0\\n\\tsd\\tzero,1024\\(sp\\)" 1 } } */
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection -funwind-tables -fno-stack-protector" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+#define SIZE 128*1024
+#include "stack-check-prologue.h"
+
+/* { dg-final { scan-assembler-times {\.cfi_def_cfa [0-9]+, 131072} 1 } } */
+/* { dg-final { scan-assembler-times {\.cfi_def_cfa_register 2} 1 } } */
+/* { dg-final { scan-assembler-times {\.cfi_def_cfa_offset 0} 1 } } */
+
+/* Checks that the CFA notes are correct for every sp adjustment. */
new file mode 100644
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection -funwind-tables -fno-stack-protector" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+#define SIZE 80*1024 + 512
+#include "stack-check-prologue.h"
+
+/* { dg-final { scan-assembler-times {\.cfi_def_cfa [0-9]+, 81920} 1 } } */
+/* { dg-final { scan-assembler-times {\.cfi_def_cfa_register 2} 1 } } */
+/* { dg-final { scan-assembler-times {\.cfi_def_cfa_offset 82432} 1 } } */
+/* { dg-final { scan-assembler-times {\.cfi_def_cfa_offset 0} 1 } } */
+
+/* Checks that the CFA notes are correct for every sp adjustment. */
new file mode 100644
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+#define SIZE 128
+#include "stack-check-prologue.h"
+
+/* { dg-final { scan-assembler-not "sd\tzero," } } */
+/* SIZE is smaller than guard-size - 1Kb so no probe expected. */
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 } */
+
+#define SIZE (6 * 4 * 1024) + (1 * 3 * 1024) + 512
+#include "stack-check-prologue.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 2 } } */
+
+/* SIZE is more than 4x guard-size and remainder larger than guard-size - 1Kb,
+ 1 probe expected in a loop and 1 residual probe. */
new file mode 100644
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection -fno-stack-protector" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+#define SIZE (6 * 4 * 1024) + (1 * 2 * 1024)
+#include "stack-check-prologue.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
+
+/* SIZE is more than 4x guard-size and remainder larger than guard-size - 1Kb,
+ 1 probe expected in a loop and 1 residual probe. */
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection --param stack-clash-protection-guard-size=16 -fomit-frame-pointer -momit-leaf-frame-pointer -fno-stack-protector" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+void
+f (void)
+{
+ volatile int x[16384 + 1000];
+ x[0] = 0;
+}
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
+
+/* SIZE is more than 1 guard-size, but only one 64KB page is used, expect only 1
+ probe. Leaf function and omitting leaf pointers. */
new file mode 100644
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection --param stack-clash-protection-guard-size=16 -fomit-frame-pointer -momit-leaf-frame-pointer -fno-stack-protector" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+void h (void) __attribute__ ((noreturn));
+
+void
+f (void)
+{
+ volatile int x[16384 + 1000];
+ x[30]=0;
+ h ();
+}
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
+/* { dg-final { scan-assembler-times {sw\tzero,120\(sp\)} 1 } } */
+
+/* SIZE is more than 1 guard-size, but only one 64KB page is used, expect only 1
+ probe. Leaf function and omitting leaf pointers, tail call to noreturn which
+ may only omit an epilogue and not a prologue. Checking for LR saving. */
new file mode 100644
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection --param stack-clash-protection-guard-size=16 -fomit-frame-pointer -momit-leaf-frame-pointer -fno-stack-protector" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+void h (void) __attribute__ ((noreturn));
+
+void
+f (void)
+{
+ volatile int x[16384 + 1000];
+ if (x[0])
+ h ();
+ x[345] = 1;
+ h ();
+}
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
+/* { dg-final { scan-assembler-times {sd\tra,8\(sp\)} 1 } } */
+
+/* SIZE is more than 1 guard-size, two 64k pages used, expect only 1 explicit
+ probe at 1024 and one implicit probe due to LR being saved. Leaf function
+ and omitting leaf pointers, tail call to noreturn which may only omit an
+ epilogue and not a prologue and control flow in between. Checking for
+ LR saving. */
new file mode 100644
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection --param stack-clash-protection-guard-size=16 -fomit-frame-pointer -momit-leaf-frame-pointer -fno-stack-protector" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+void g (volatile int *x) ;
+void h (void) __attribute__ ((noreturn));
+
+void
+f (void)
+{
+ volatile int x[16384 + 1000];
+ g (x);
+ h ();
+}
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
+/* { dg-final { scan-assembler-times {sd\tra,8\(sp\)} 1 } } */
+
+/* SIZE is more than 1 guard-size, two 64k pages used, expect only 1 explicit
+ probe at 1024 and one implicit probe due to LR being saved. Leaf function
+ and omitting leaf pointers, normal function call followed by a tail call to
+ noreturn which may only omit an epilogue and not a prologue and control flow
+ in between. Checking for LR saving. */
new file mode 100644
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+#define SIZE 2 * 1024
+#include "stack-check-prologue.h"
+
+/* { dg-final { scan-assembler-not "sd\tzero," } } */
+
+/* SIZE is smaller than guard-size - 1Kb so no probe expected. */
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 } */
+
+#define SIZE 3 * 1024
+#include "stack-check-prologue.h"
+
+/* { dg-final { scan-assembler-times "sd\tzero," 1 } } */
+
+/* SIZE is exactly guard-size - 1Kb, boundary condition so 1 probe expected.
+*/
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 } */
+
+#define SIZE 3 * 1024 + 512
+#include "stack-check-prologue.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
+
+/* SIZE is more than guard-size - 1Kb and remainder is less than 1kB,
+ 1 probe expected. */
new file mode 100644
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection -fno-stack-protector" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+#define SIZE 4 * 1024
+#include "stack-check-prologue.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
+
+/* SIZE is more than guard-size - 1Kb and remainder is zero,
+ 1 probe expected, boundary condition. */
new file mode 100644
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection -fno-stack-protector" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+#define SIZE 5 * 1024
+#include "stack-check-prologue.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
+
+/* SIZE is more than guard-size - 1Kb and remainder is equal to 1kB,
+ 1 probe expected. */
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 } */
+
+#define SIZE 7 * 1024
+#include "stack-check-prologue.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 2 } } */
+
+/* SIZE is more than 1x guard-size and remainder equal than guard-size - 1Kb,
+ 2 probe expected, unrolled, no loop. */
new file mode 100644
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+#define SIZE 8 * 1024
+#include "stack-check-prologue.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 2 } } */
+
+/* SIZE is more than 2x guard-size and no remainder, unrolled, no loop. */
new file mode 100644
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection -fno-stack-protector" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+#define SIZE 6 * 4 * 1024
+#include "stack-check-prologue.h"
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
+
+/* SIZE is more than 4x guard-size and no remainder, 1 probe expected in a loop
+ and no residual probe. */
new file mode 100644
@@ -0,0 +1,5 @@
+int f_test (int x)
+{
+ char arr[SIZE];
+ return arr[x];
+}
@@ -12718,7 +12718,7 @@ proc check_effective_target_supports_stack_clash_protection { } {
if { [istarget x86_64-*-*] || [istarget i?86-*-*]
|| [istarget powerpc*-*-*] || [istarget rs6000*-*-*]
|| [istarget aarch64*-**] || [istarget s390*-*-*]
- || [istarget loongarch64*-**] } {
+ || [istarget loongarch64*-**] || [istarget riscv64*-**] } {
return 1
}
return 0
@@ -12778,6 +12778,10 @@ proc check_effective_target_caller_implicit_probes { } {
return 1;
}
+ if { [istarget riscv64*-*-*] } {
+ return 1;
+ }
+
if { [istarget loongarch64*-*-*] } {
return 1;
}