* [PATCH 0/5] RISC-V: Enable stack-clash protection
@ 2024-07-24 18:00 Raphael Moreira Zinsly
2024-07-24 18:00 ` [PATCH 1/5] RISC-V: Small stack tie changes Raphael Moreira Zinsly
` (4 more replies)
0 siblings, 5 replies; 23+ messages in thread
From: Raphael Moreira Zinsly @ 2024-07-24 18:00 UTC (permalink / raw)
To: gcc-patches; +Cc: jlaw, Raphael Moreira Zinsly
Hi All,
This patch series implements stack-clash protection for RISC-V using 4K
probes as default. The non-vector implementation is based on AArch64’s
as the generated stack frame is similar.
The tests are also adapted from AArch64.
Thanks,
Raphael
Raphael Moreira Zinsly (5):
RISC-V: Small stack tie changes
RISC-V: Move riscv_v_adjust_scalable_frame
RISC-V: Stack-clash protection implemention
RISC-V: Add support to vector stack-clash protection
RISC-V: Enable stack clash in alloca
gcc/config/riscv/riscv.cc | 396 ++++++++++++++----
gcc/config/riscv/riscv.h | 27 ++
gcc/config/riscv/riscv.md | 2 +-
gcc/testsuite/gcc.dg/params/blocksort-part.c | 2 +-
gcc/testsuite/gcc.dg/pr82788.c | 2 +-
gcc/testsuite/gcc.dg/stack-check-6.c | 2 +-
gcc/testsuite/gcc.dg/stack-check-6a.c | 2 +-
.../gcc.target/riscv/stack-check-12.c | 23 +
.../gcc.target/riscv/stack-check-13.c | 26 ++
.../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 +
.../gcc.target/riscv/stack-check-cfa-1.c | 12 +
.../gcc.target/riscv/stack-check-cfa-2.c | 13 +
.../gcc.target/riscv/stack-check-cfa-3.c | 13 +
.../gcc.target/riscv/stack-check-prologue-1.c | 9 +
.../riscv/stack-check-prologue-10.c | 11 +
.../riscv/stack-check-prologue-11.c | 11 +
.../riscv/stack-check-prologue-12.c | 15 +
.../riscv/stack-check-prologue-13.c | 20 +
.../riscv/stack-check-prologue-14.c | 24 ++
.../riscv/stack-check-prologue-15.c | 23 +
.../riscv/stack-check-prologue-16.c | 30 ++
.../gcc.target/riscv/stack-check-prologue-2.c | 10 +
.../gcc.target/riscv/stack-check-prologue-3.c | 11 +
.../gcc.target/riscv/stack-check-prologue-4.c | 11 +
.../gcc.target/riscv/stack-check-prologue-5.c | 11 +
.../gcc.target/riscv/stack-check-prologue-6.c | 11 +
.../gcc.target/riscv/stack-check-prologue-7.c | 11 +
.../gcc.target/riscv/stack-check-prologue-8.c | 10 +
.../gcc.target/riscv/stack-check-prologue-9.c | 11 +
.../gcc.target/riscv/stack-check-prologue.h | 5 +
.../gcc.target/riscv/struct_vect_24.c | 47 +++
gcc/testsuite/lib/target-supports.exp | 6 +-
44 files changed, 912 insertions(+), 80 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-12.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-13.c
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
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-cfa-1.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-cfa-2.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-cfa-3.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-1.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-10.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-11.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-12.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-13.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-14.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-15.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-16.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-2.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-3.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-4.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-5.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-6.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-7.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-8.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-9.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue.h
create mode 100644 gcc/testsuite/gcc.target/riscv/struct_vect_24.c
--
2.42.0
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 1/5] RISC-V: Small stack tie changes
2024-07-24 18:00 [PATCH 0/5] RISC-V: Enable stack-clash protection Raphael Moreira Zinsly
@ 2024-07-24 18:00 ` Raphael Moreira Zinsly
2024-07-26 17:00 ` Jeff Law
2024-07-24 18:00 ` [PATCH 2/5] RISC-V: Move riscv_v_adjust_scalable_frame Raphael Moreira Zinsly
` (3 subsequent siblings)
4 siblings, 1 reply; 23+ messages in thread
From: Raphael Moreira Zinsly @ 2024-07-24 18:00 UTC (permalink / raw)
To: gcc-patches; +Cc: jlaw, Raphael Moreira Zinsly
Enable the register used by riscv_emit_stack_tie () to be passed as
an argument so we can tie the stack with other registers besides
hard_frame_pointer_rtx.
Also don't allow operand 1 of stack_tie<mode> to be optimized to sp
in preparation for the stack clash protection support.
gcc/ChangeLog:
* config/riscv/riscv.cc (riscv_emit_stack_tie): Pass the
register to be tied to the stack pointer as argument.
* config/riscv/riscv.md (stack_tie<mode>): Don't match equal
operands.
---
gcc/config/riscv/riscv.cc | 18 +++++++++---------
gcc/config/riscv/riscv.md | 2 +-
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 19b9b2daa95..f85d018c514 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -7891,12 +7891,12 @@ riscv_adjust_multi_push_cfi_prologue (int saved_size)
}
static void
-riscv_emit_stack_tie (void)
+riscv_emit_stack_tie (rtx reg)
{
if (Pmode == SImode)
- emit_insn (gen_stack_tiesi (stack_pointer_rtx, hard_frame_pointer_rtx));
+ emit_insn (gen_stack_tiesi (stack_pointer_rtx, reg));
else
- emit_insn (gen_stack_tiedi (stack_pointer_rtx, hard_frame_pointer_rtx));
+ emit_insn (gen_stack_tiedi (stack_pointer_rtx, reg));
}
/*zcmp multi push and pop code_for_push_pop function ptr array */
@@ -8077,7 +8077,7 @@ riscv_expand_prologue (void)
GEN_INT ((frame->hard_frame_pointer_offset - remaining_size).to_constant ()));
RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
- riscv_emit_stack_tie ();
+ riscv_emit_stack_tie (hard_frame_pointer_rtx);
}
/* Save the V registers. */
@@ -8108,7 +8108,7 @@ riscv_expand_prologue (void)
allocation is ordered WRT fp setup and subsequent writes
into the frame. */
if (frame_pointer_needed)
- riscv_emit_stack_tie ();
+ riscv_emit_stack_tie (hard_frame_pointer_rtx);
return;
}
@@ -8147,7 +8147,7 @@ riscv_expand_prologue (void)
allocation is ordered WRT fp setup and subsequent writes
into the frame. */
if (frame_pointer_needed)
- riscv_emit_stack_tie ();
+ riscv_emit_stack_tie (hard_frame_pointer_rtx);
}
}
@@ -8282,7 +8282,7 @@ riscv_expand_epilogue (int style)
if (cfun->calls_alloca)
{
/* Emit a barrier to prevent loads from a deallocated stack. */
- riscv_emit_stack_tie ();
+ riscv_emit_stack_tie (hard_frame_pointer_rtx);
need_barrier_p = false;
poly_int64 adjust_offset = -frame->hard_frame_pointer_offset;
@@ -8376,7 +8376,7 @@ riscv_expand_epilogue (int style)
if (known_gt (step1, 0))
{
/* Emit a barrier to prevent loads from a deallocated stack. */
- riscv_emit_stack_tie ();
+ riscv_emit_stack_tie (hard_frame_pointer_rtx);
need_barrier_p = false;
/* Restore the scalable frame which is assigned in prologue. */
@@ -8476,7 +8476,7 @@ riscv_expand_epilogue (int style)
frame->mask = mask; /* Undo the above fib. */
if (need_barrier_p)
- riscv_emit_stack_tie ();
+ riscv_emit_stack_tie (hard_frame_pointer_rtx);
/* Deallocate the final bit of the frame. */
if (step2.to_constant () > 0)
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 46c46039c33..5780c5abacf 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -3969,7 +3969,7 @@
(unspec:BLK [(match_operand:X 0 "register_operand" "r")
(match_operand:X 1 "register_operand" "r")]
UNSPEC_TIE))]
- ""
+ "!rtx_equal_p (operands[0], operands[1])"
""
[(set_attr "type" "ghost")
(set_attr "length" "0")]
--
2.42.0
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 2/5] RISC-V: Move riscv_v_adjust_scalable_frame
2024-07-24 18:00 [PATCH 0/5] RISC-V: Enable stack-clash protection Raphael Moreira Zinsly
2024-07-24 18:00 ` [PATCH 1/5] RISC-V: Small stack tie changes Raphael Moreira Zinsly
@ 2024-07-24 18:00 ` Raphael Moreira Zinsly
2024-07-26 20:26 ` Jeff Law
2024-07-24 18:00 ` [PATCH 3/5] RISC-V: Stack-clash protection implemention Raphael Moreira Zinsly
` (2 subsequent siblings)
4 siblings, 1 reply; 23+ messages in thread
From: Raphael Moreira Zinsly @ 2024-07-24 18:00 UTC (permalink / raw)
To: gcc-patches; +Cc: jlaw, Raphael Moreira Zinsly
Move riscv_v_adjust_scalable_frame () in preparation for the stack clash
protection support.
gcc/ChangeLog:
* config/riscv/riscv.cc (riscv_v_adjust_scalable_frame): Move
closer to riscv_expand_prologue.
---
gcc/config/riscv/riscv.cc | 62 +++++++++++++++++++--------------------
1 file changed, 31 insertions(+), 31 deletions(-)
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index f85d018c514..89fc8966654 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -3122,37 +3122,6 @@ riscv_legitimize_poly_move (machine_mode mode, rtx dest, rtx tmp, rtx src)
}
}
-/* Adjust scalable frame of vector for prologue && epilogue. */
-
-static void
-riscv_v_adjust_scalable_frame (rtx target, poly_int64 offset, bool epilogue)
-{
- rtx tmp = RISCV_PROLOGUE_TEMP (Pmode);
- rtx adjust_size = RISCV_PROLOGUE_TEMP2 (Pmode);
- rtx insn, dwarf, adjust_frame_rtx;
-
- riscv_legitimize_poly_move (Pmode, adjust_size, tmp,
- gen_int_mode (offset, Pmode));
-
- if (epilogue)
- insn = gen_add3_insn (target, target, adjust_size);
- else
- insn = gen_sub3_insn (target, target, adjust_size);
-
- insn = emit_insn (insn);
-
- RTX_FRAME_RELATED_P (insn) = 1;
-
- adjust_frame_rtx
- = gen_rtx_SET (target,
- plus_constant (Pmode, target, epilogue ? offset : -offset));
-
- dwarf = alloc_reg_note (REG_FRAME_RELATED_EXPR, copy_rtx (adjust_frame_rtx),
- NULL_RTX);
-
- REG_NOTES (insn) = dwarf;
-}
-
/* Take care below subreg const_poly_int move:
1. (set (subreg:DI (reg:TI 237) 8)
@@ -7928,6 +7897,37 @@ static const code_for_push_pop_t code_for_push_pop[ZCMP_MAX_GRP_SLOTS][ZCMP_OP_N
code_for_gpr_multi_popret_up_to_s11,
code_for_gpr_multi_popretz_up_to_s11}};
+/* Adjust scalable frame of vector for prologue && epilogue. */
+
+static void
+riscv_v_adjust_scalable_frame (rtx target, poly_int64 offset, bool epilogue)
+{
+ rtx tmp = RISCV_PROLOGUE_TEMP (Pmode);
+ rtx adjust_size = RISCV_PROLOGUE_TEMP2 (Pmode);
+ rtx insn, dwarf, adjust_frame_rtx;
+
+ riscv_legitimize_poly_move (Pmode, adjust_size, tmp,
+ gen_int_mode (offset, Pmode));
+
+ if (epilogue)
+ insn = gen_add3_insn (target, target, adjust_size);
+ else
+ insn = gen_sub3_insn (target, target, adjust_size);
+
+ insn = emit_insn (insn);
+
+ RTX_FRAME_RELATED_P (insn) = 1;
+
+ adjust_frame_rtx
+ = gen_rtx_SET (target,
+ plus_constant (Pmode, target, epilogue ? offset : -offset));
+
+ dwarf = alloc_reg_note (REG_FRAME_RELATED_EXPR, copy_rtx (adjust_frame_rtx),
+ NULL_RTX);
+
+ REG_NOTES (insn) = dwarf;
+}
+
static rtx
riscv_gen_multi_push_pop_insn (riscv_zcmp_op_t op, HOST_WIDE_INT adj_size,
unsigned int regs_num)
--
2.42.0
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 3/5] RISC-V: Stack-clash protection implemention
2024-07-24 18:00 [PATCH 0/5] RISC-V: Enable stack-clash protection Raphael Moreira Zinsly
2024-07-24 18:00 ` [PATCH 1/5] RISC-V: Small stack tie changes Raphael Moreira Zinsly
2024-07-24 18:00 ` [PATCH 2/5] RISC-V: Move riscv_v_adjust_scalable_frame Raphael Moreira Zinsly
@ 2024-07-24 18:00 ` Raphael Moreira Zinsly
2024-07-26 21:37 ` Jeff Law
2024-07-24 18:00 ` [PATCH 4/5] RISC-V: Add support to vector stack-clash protection Raphael Moreira Zinsly
2024-07-24 18:00 ` [PATCH 5/5] RISC-V: Enable stack clash in alloca Raphael Moreira Zinsly
4 siblings, 1 reply; 23+ messages in thread
From: Raphael Moreira Zinsly @ 2024-07-24 18:00 UTC (permalink / raw)
To: gcc-patches; +Cc: jlaw, Raphael Moreira Zinsly
This implements stack-clash protection for riscv, with
riscv_allocate_and_probe_stack_space being based of
aarch64_allocate_and_probe_stack_space from aarch64's implementation.
We enforce the probing interval and the guard size to always be equal, their
default value is 4Kb which is riscv page size.
We also probe up by 1024 bytes in the general case when a probe is required.
gcc/ChangeLog:
* config/riscv/riscv.cc
(riscv_option_override): Enforce that interval is the same size as
guard size.
(riscv_allocate_and_probe_stack_space): New function.
(riscv_expand_prologue): Call riscv_allocate_and_probe_stack_space
to the final allocation of the stack and add stack-clash dump
information.
* config/riscv/riscv.h: Define STACK_CLASH_CALLER_GUARD and
STACK_CLASH_MAX_UNROLL_PAGES.
gcc/testsuite/ChangeLog:
* gcc.dg/params/blocksort-part.c: Skip riscv for
stack-clash protection intervals.
* gcc.dg/pr82788.c: Skip riscv.
* gcc.dg/stack-check-6.c: Skip residual check for riscv.
* gcc.dg/stack-check-6a.c: Skip riscv.
* gcc.target/riscv/stack-check-12.c: New test.
* gcc.target/riscv/stack-check-13.c: New test.
* gcc.target/riscv/stack-check-cfa-1.c: New test.
* gcc.target/riscv/stack-check-cfa-2.c: New test.
* gcc.target/riscv/stack-check-prologue-1.c: New test.
* gcc.target/riscv/stack-check-prologue-10.c: New test.
* gcc.target/riscv/stack-check-prologue-11.c: New test.
* gcc.target/riscv/stack-check-prologue-12.c: New test.
* gcc.target/riscv/stack-check-prologue-13.c: New test.
* gcc.target/riscv/stack-check-prologue-14.c: New test.
* gcc.target/riscv/stack-check-prologue-15.c: New test.
* gcc.target/riscv/stack-check-prologue-2.c: New test.
* gcc.target/riscv/stack-check-prologue-3.c: New test.
* gcc.target/riscv/stack-check-prologue-4.c: New test.
* gcc.target/riscv/stack-check-prologue-5.c: New test.
* gcc.target/riscv/stack-check-prologue-6.c: New test.
* gcc.target/riscv/stack-check-prologue-7.c: New test.
* gcc.target/riscv/stack-check-prologue-8.c: New test.
* gcc.target/riscv/stack-check-prologue-9.c: New test.
* gcc.target/riscv/stack-check-prologue.h: New file.
* lib/target-supports.exp
(check_effective_target_supports_stack_clash_protection):
Add riscv.
(check_effective_target_caller_implicit_probes): Likewise.
---
gcc/config/riscv/riscv.cc | 244 +++++++++++++++---
gcc/config/riscv/riscv.h | 8 +
gcc/testsuite/gcc.dg/params/blocksort-part.c | 2 +-
gcc/testsuite/gcc.dg/pr82788.c | 2 +-
gcc/testsuite/gcc.dg/stack-check-6.c | 2 +-
gcc/testsuite/gcc.dg/stack-check-6a.c | 2 +-
.../gcc.target/riscv/stack-check-12.c | 23 ++
.../gcc.target/riscv/stack-check-13.c | 26 ++
.../gcc.target/riscv/stack-check-cfa-1.c | 12 +
.../gcc.target/riscv/stack-check-cfa-2.c | 13 +
.../gcc.target/riscv/stack-check-prologue-1.c | 9 +
.../riscv/stack-check-prologue-10.c | 11 +
.../riscv/stack-check-prologue-11.c | 11 +
.../riscv/stack-check-prologue-12.c | 15 ++
.../riscv/stack-check-prologue-13.c | 20 ++
.../riscv/stack-check-prologue-14.c | 24 ++
.../riscv/stack-check-prologue-15.c | 23 ++
.../gcc.target/riscv/stack-check-prologue-2.c | 10 +
.../gcc.target/riscv/stack-check-prologue-3.c | 11 +
.../gcc.target/riscv/stack-check-prologue-4.c | 11 +
.../gcc.target/riscv/stack-check-prologue-5.c | 11 +
.../gcc.target/riscv/stack-check-prologue-6.c | 11 +
.../gcc.target/riscv/stack-check-prologue-7.c | 11 +
.../gcc.target/riscv/stack-check-prologue-8.c | 10 +
.../gcc.target/riscv/stack-check-prologue-9.c | 11 +
.../gcc.target/riscv/stack-check-prologue.h | 5 +
gcc/testsuite/lib/target-supports.exp | 6 +-
27 files changed, 504 insertions(+), 40 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-12.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-13.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-cfa-1.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-cfa-2.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-1.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-10.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-11.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-12.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-13.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-14.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-15.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-2.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-3.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-4.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-5.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-6.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-7.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-8.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-9.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue.h
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 89fc8966654..292d190f319 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -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);
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 6f040011864..9670c7df8f7 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -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 */
diff --git a/gcc/testsuite/gcc.dg/params/blocksort-part.c b/gcc/testsuite/gcc.dg/params/blocksort-part.c
index cc15223c0de..72cd5da322c 100644
--- a/gcc/testsuite/gcc.dg/params/blocksort-part.c
+++ b/gcc/testsuite/gcc.dg/params/blocksort-part.c
@@ -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" } } */
/*-------------------------------------------------------------*/
diff --git a/gcc/testsuite/gcc.dg/pr82788.c b/gcc/testsuite/gcc.dg/pr82788.c
index 41c442f61a6..f5cb333f619 100644
--- a/gcc/testsuite/gcc.dg/pr82788.c
+++ b/gcc/testsuite/gcc.dg/pr82788.c
@@ -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;}
diff --git a/gcc/testsuite/gcc.dg/stack-check-6.c b/gcc/testsuite/gcc.dg/stack-check-6.c
index fe75612b737..50eb1924602 100644
--- a/gcc/testsuite/gcc.dg/stack-check-6.c
+++ b/gcc/testsuite/gcc.dg/stack-check-6.c
@@ -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 } } } } */
diff --git a/gcc/testsuite/gcc.dg/stack-check-6a.c b/gcc/testsuite/gcc.dg/stack-check-6a.c
index 68dd9bc48a0..8c6b5367afc 100644
--- a/gcc/testsuite/gcc.dg/stack-check-6a.c
+++ b/gcc/testsuite/gcc.dg/stack-check-6a.c
@@ -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"
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-12.c b/gcc/testsuite/gcc.target/riscv/stack-check-12.c
new file mode 100644
index 00000000000..ceb9acc3c40
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-12.c
@@ -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 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-13.c b/gcc/testsuite/gcc.target/riscv/stack-check-13.c
new file mode 100644
index 00000000000..abd8a32b712
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-13.c
@@ -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 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-cfa-1.c b/gcc/testsuite/gcc.target/riscv/stack-check-cfa-1.c
new file mode 100644
index 00000000000..60b01578692
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-cfa-1.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-cfa-2.c b/gcc/testsuite/gcc.target/riscv/stack-check-cfa-2.c
new file mode 100644
index 00000000000..9d36a302222
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-cfa-2.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-1.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-1.c
new file mode 100644
index 00000000000..9f2c527a5ed
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-1.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-10.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-10.c
new file mode 100644
index 00000000000..fd171c30f89
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-10.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 } */
+
+#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. */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-11.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-11.c
new file mode 100644
index 00000000000..ebe3b139eb0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-11.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-12.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-12.c
new file mode 100644
index 00000000000..2a001ea8b1f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-12.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-13.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-13.c
new file mode 100644
index 00000000000..d97f69a943f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-13.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-14.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-14.c
new file mode 100644
index 00000000000..bd263fbbd80
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-14.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-15.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-15.c
new file mode 100644
index 00000000000..f175e6f5b8f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-15.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-2.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-2.c
new file mode 100644
index 00000000000..9c78b1ebaf1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-2.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-3.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-3.c
new file mode 100644
index 00000000000..2c7e55acae6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-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 } */
+
+#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.
+*/
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-4.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-4.c
new file mode 100644
index 00000000000..506ea7b19c8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-4.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 } */
+
+#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. */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-5.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-5.c
new file mode 100644
index 00000000000..4c50a2a47a2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-5.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-6.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-6.c
new file mode 100644
index 00000000000..db39ecdc39f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-6.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-7.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-7.c
new file mode 100644
index 00000000000..b394849136d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-7.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 } */
+
+#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. */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-8.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-8.c
new file mode 100644
index 00000000000..6366cacc520
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-8.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-9.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-9.c
new file mode 100644
index 00000000000..5e65750b9e8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-9.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue.h b/gcc/testsuite/gcc.target/riscv/stack-check-prologue.h
new file mode 100644
index 00000000000..b7e06aedb81
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue.h
@@ -0,0 +1,5 @@
+int f_test (int x)
+{
+ char arr[SIZE];
+ return arr[x];
+}
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index daa0c75d2bc..3d7a4691624 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -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;
}
--
2.42.0
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 4/5] RISC-V: Add support to vector stack-clash protection
2024-07-24 18:00 [PATCH 0/5] RISC-V: Enable stack-clash protection Raphael Moreira Zinsly
` (2 preceding siblings ...)
2024-07-24 18:00 ` [PATCH 3/5] RISC-V: Stack-clash protection implemention Raphael Moreira Zinsly
@ 2024-07-24 18:00 ` Raphael Moreira Zinsly
2024-07-26 21:48 ` Jeff Law
2024-08-01 12:01 ` [PATCH v2] " Raphael Moreira Zinsly
2024-07-24 18:00 ` [PATCH 5/5] RISC-V: Enable stack clash in alloca Raphael Moreira Zinsly
4 siblings, 2 replies; 23+ messages in thread
From: Raphael Moreira Zinsly @ 2024-07-24 18:00 UTC (permalink / raw)
To: gcc-patches; +Cc: jlaw, Raphael Moreira Zinsly
Adds basic support to vector stack-clash protection using a loop to do
the probing and stack adjustments.
gcc/ChangeLog:
* config/riscv/riscv.cc
(riscv_allocate_and_probe_stack_loop): New function.
(riscv_v_adjust_scalable_frame): Add stack-clash protection
support.
(riscv_allocate_and_probe_stack_space): Move the probe loop
implementation to riscv_allocate_and_probe_stack_loop.
* config/riscv/riscv.h: Define RISCV_STACK_CLASH_VECTOR_CFA_REGNUM.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/stack-check-cfa-3.c: New test.
* gcc.target/riscv/stack-check-prologue-16.c: New test.
* gcc.target/riscv/struct_vect_24.c: New test.
---
gcc/config/riscv/riscv.cc | 99 +++++++++++++++----
gcc/config/riscv/riscv.h | 2 +
.../gcc.target/riscv/stack-check-cfa-3.c | 13 +++
.../riscv/stack-check-prologue-16.c | 30 ++++++
.../gcc.target/riscv/struct_vect_24.c | 47 +++++++++
5 files changed, 170 insertions(+), 21 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-cfa-3.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-16.c
create mode 100644 gcc/testsuite/gcc.target/riscv/struct_vect_24.c
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 292d190f319..69c0e07f4c5 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -7897,6 +7897,35 @@ static const code_for_push_pop_t code_for_push_pop[ZCMP_MAX_GRP_SLOTS][ZCMP_OP_N
code_for_gpr_multi_popret_up_to_s11,
code_for_gpr_multi_popretz_up_to_s11}};
+/* Set a probe loop for stack clash protection. */
+static void
+riscv_allocate_and_probe_stack_loop (rtx tmp, enum rtx_code code,
+ rtx op0, rtx op1, bool vector,
+ HOST_WIDE_INT offset)
+{
+ tmp = riscv_force_temporary (tmp, gen_int_mode (offset, Pmode));
+
+ /* Loop. */
+ rtx label = gen_label_rtx ();
+ emit_label (label);
+
+ /* Allocate and probe stack. */
+ emit_insn (gen_sub3_insn (stack_pointer_rtx, stack_pointer_rtx, tmp));
+ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
+ STACK_CLASH_CALLER_GUARD));
+ emit_insn (gen_blockage ());
+
+ /* Adjust the remaining vector length. */
+ if (vector)
+ emit_insn (gen_sub3_insn (op0, op0, tmp));
+
+ /* Branch if there's still more bytes to probe. */
+ riscv_expand_conditional_branch (label, code, op0, op1);
+ JUMP_LABEL (get_last_insn ()) = label;
+
+ emit_insn (gen_blockage ());
+}
+
/* Adjust scalable frame of vector for prologue && epilogue. */
static void
@@ -7909,6 +7938,49 @@ riscv_v_adjust_scalable_frame (rtx target, poly_int64 offset, bool epilogue)
riscv_legitimize_poly_move (Pmode, adjust_size, tmp,
gen_int_mode (offset, Pmode));
+ /* If doing stack clash protection then we use a loop to allocate and probe
+ the stack. */
+ if (flag_stack_clash_protection && !epilogue)
+ {
+ HOST_WIDE_INT min_probe_threshold
+ = (1 << param_stack_clash_protection_guard_size) - STACK_CLASH_CALLER_GUARD;
+
+ if (!frame_pointer_needed)
+ {
+ /* This is done to provide unwinding information for the stack
+ adjustments we're about to do, however to prevent the optimizers
+ from removing the S0 move and leaving the CFA note (which would be
+ very wrong) we tie the old and new stack pointer together.
+ The tie will expand to nothing but the optimizers will not touch
+ the instruction. */
+ insn = get_last_insn ();
+ rtx stack_ptr_copy = gen_rtx_REG (Pmode, RISCV_STACK_CLASH_VECTOR_CFA_REGNUM);
+ emit_move_insn (stack_ptr_copy, stack_pointer_rtx);
+ riscv_emit_stack_tie (stack_ptr_copy);
+
+ /* We want the CFA independent of the stack pointer for the
+ duration of the loop. */
+ add_reg_note (insn, REG_CFA_DEF_CFA, stack_ptr_copy);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ riscv_allocate_and_probe_stack_loop (tmp, GE, adjust_size, tmp, true,
+ min_probe_threshold);
+
+ /* Allocate the residual. */
+ insn = emit_insn (gen_sub3_insn (target, target, adjust_size));
+
+ /* Now reset the CFA register if needed. */
+ if (!frame_pointer_needed)
+ {
+ add_reg_note (insn, REG_CFA_DEF_CFA,
+ plus_constant (Pmode, stack_pointer_rtx, -offset));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ return;
+ }
+
if (epilogue)
insn = gen_add3_insn (target, target, adjust_size);
else
@@ -8056,8 +8128,9 @@ riscv_allocate_and_probe_stack_space (rtx temp1, HOST_WIDE_INT 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));
+ rtx temp2 = gen_rtx_REG (Pmode, RISCV_PROLOGUE_TEMP2_REGNUM);
+ temp2 = riscv_force_temporary (temp2, gen_int_mode (rounded_size, Pmode));
+ insn = emit_insn (gen_sub3_insn (temp2, stack_pointer_rtx, temp2));
if (!frame_pointer_needed)
{
@@ -8068,25 +8141,9 @@ riscv_allocate_and_probe_stack_space (rtx temp1, HOST_WIDE_INT 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 ());
+ /* This allocates and probes the stack. */
+ riscv_allocate_and_probe_stack_loop (temp1, NE, stack_pointer_rtx, temp2,
+ false, guard_size);
/* Now reset the CFA register if needed. */
if (!frame_pointer_needed)
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 9670c7df8f7..0432beb81e0 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -429,6 +429,8 @@ ASM_MISA_SPEC
#define RISCV_PROLOGUE_TEMP2_REGNUM (GP_TEMP_FIRST + 1)
#define RISCV_PROLOGUE_TEMP2(MODE) gen_rtx_REG (MODE, RISCV_PROLOGUE_TEMP2_REGNUM)
+#define RISCV_STACK_CLASH_VECTOR_CFA_REGNUM (GP_TEMP_FIRST + 4)
+
#define RISCV_CALL_ADDRESS_TEMP_REGNUM (GP_TEMP_FIRST + 1)
#define RISCV_CALL_ADDRESS_TEMP(MODE) \
gen_rtx_REG (MODE, RISCV_CALL_ADDRESS_TEMP_REGNUM)
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-cfa-3.c b/gcc/testsuite/gcc.target/riscv/stack-check-cfa-3.c
new file mode 100644
index 00000000000..cc0d54ed7c4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-cfa-3.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -fstack-clash-protection -funwind-tables -fno-stack-protector" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+#include "stack-check-prologue-16.c"
+
+/* Checks that the CFA notes are correct for every sp adjustment, but we also
+ need to make sure we can unwind correctly before the frame is set up. So
+ check that we're emitting s0 with a copy of sp an setting the CFA there. */
+
+/* { dg-final { scan-assembler-times {mv\ts1,sp} 1 } } */
+/* { dg-final { scan-assembler-times {\.cfi_def_cfa [0-9]+, 0} 1 } } */
+/* { dg-final { scan-assembler-times {\.cfi_escape 0xf,0xa,0x72,0,0x92,0xa2,0x38,0,0x9,0xec,0x1e,0x22} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-16.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-16.c
new file mode 100644
index 00000000000..c74dce04b23
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-16.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -fstack-clash-protection" } */
+
+/* Invoke X (P##n) for n in [0, 7]. */
+#define REPEAT8(X, P) \
+ X (P##0) X (P##1) X (P##2) X (P##3) X (P##4) X (P##5) X (P##6) X (P##7)
+
+/* Invoke X (n) for all octal n in [0, 39]. */
+#define REPEAT40(X) \
+ REPEAT8 (X, 0) REPEAT8 (X, 1) REPEAT8 (X, 2) REPEAT8 (X, 3) REPEAT8 (X, 4)
+
+/* Expect vector work to be done, with spilling of vector registers. */
+void
+f2 (int x[40][100], int *y)
+{
+ /* Try to force some spilling. */
+#define DECLARE(N) int y##N = y[N];
+ REPEAT40 (DECLARE);
+#pragma omp simd
+ for (int i = 0; i < 100; ++i)
+ {
+#define INC(N) x[N][i] += y##N;
+ REPEAT40 (INC);
+ }
+}
+
+/* Vector spill, requires probing as vector size is unknown at compile time. */
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/struct_vect_24.c b/gcc/testsuite/gcc.target/riscv/struct_vect_24.c
new file mode 100644
index 00000000000..7c0852f1a55
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/struct_vect_24.c
@@ -0,0 +1,47 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -fstack-clash-protection -fno-stack-protector" } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-Os" "-Oz" "-funroll-loops"} } */
+
+#include <stdint.h>
+
+#define N 50
+#define S 2 * 4 * 1024
+
+/* Invoke X (P##n) for n in [0, 9]. */
+#define REPEAT8(X, P) \
+ X (P##0) X (P##1) X (P##2) X (P##3) X (P##4) X (P##5) X (P##6) X (P##7) \
+ X (P##8) X (P##9)
+
+/* Invoke X (n) for all n in [0, 49]. */
+#define REPEAT50(X) \
+ REPEAT8 (X, ) REPEAT8 (X, 1) REPEAT8 (X, 2) REPEAT8 (X, 3) REPEAT8 (X, 4)
+
+ /* Try to force some spilling. */
+#define DECLARE(N) int src##N = src[N * 4];
+#define INC(N) dest[i] += src##N;
+
+#define TEST_LOOP(NAME, TYPE) \
+ void __attribute__ ((noinline)) \
+ NAME (TYPE *restrict dest, TYPE *restrict src) \
+ { \
+ REPEAT50 (DECLARE); \
+ volatile char foo[S]; \
+ foo[S-1]=1; \
+ for (int i = 0; i < N; i++) \
+ { \
+ REPEAT50 (INC); \
+ } \
+ }
+
+#define TEST(NAME) \
+ TEST_LOOP (NAME##_i32, int32_t) \
+ TEST_LOOP (NAME##_i64, int64_t)
+
+TEST (test)
+
+/* Check the vectorized loop for stack clash probing. */
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 6 } } */
+/* { dg-final { scan-assembler-times {bge\tt1,t0,.[^\\r\\n]*} 2 } } */
+/* { dg-final { scan-assembler-times {sub\s+t1,t1,t0} 2 } } */
--
2.42.0
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 5/5] RISC-V: Enable stack clash in alloca
2024-07-24 18:00 [PATCH 0/5] RISC-V: Enable stack-clash protection Raphael Moreira Zinsly
` (3 preceding siblings ...)
2024-07-24 18:00 ` [PATCH 4/5] RISC-V: Add support to vector stack-clash protection Raphael Moreira Zinsly
@ 2024-07-24 18:00 ` Raphael Moreira Zinsly
2024-07-26 21:53 ` Jeff Law
4 siblings, 1 reply; 23+ messages in thread
From: Raphael Moreira Zinsly @ 2024-07-24 18:00 UTC (permalink / raw)
To: gcc-patches; +Cc: jlaw, Raphael Moreira Zinsly
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
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/5] RISC-V: Small stack tie changes
2024-07-24 18:00 ` [PATCH 1/5] RISC-V: Small stack tie changes Raphael Moreira Zinsly
@ 2024-07-26 17:00 ` Jeff Law
2024-07-26 18:43 ` Raphael Zinsly
0 siblings, 1 reply; 23+ messages in thread
From: Jeff Law @ 2024-07-26 17:00 UTC (permalink / raw)
To: Raphael Moreira Zinsly, gcc-patches; +Cc: jlaw
On 7/24/24 12:00 PM, Raphael Moreira Zinsly wrote:
> Enable the register used by riscv_emit_stack_tie () to be passed as
> an argument so we can tie the stack with other registers besides
> hard_frame_pointer_rtx.
> Also don't allow operand 1 of stack_tie<mode> to be optimized to sp
> in preparation for the stack clash protection support.
>
> gcc/ChangeLog:
> * config/riscv/riscv.cc (riscv_emit_stack_tie): Pass the
> register to be tied to the stack pointer as argument.
> * config/riscv/riscv.md (stack_tie<mode>): Don't match equal
> operands.
So NFC at this point, just infrastructure you need, presumably for the
probing loops. One quick question:
> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index 46c46039c33..5780c5abacf 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -3969,7 +3969,7 @@
> (unspec:BLK [(match_operand:X 0 "register_operand" "r")
> (match_operand:X 1 "register_operand" "r")]
> UNSPEC_TIE))]
> - ""
> + "!rtx_equal_p (operands[0], operands[1])"
> ""
> [(set_attr "type" "ghost")
> (set_attr "length" "0")]
I'm guessing this condition to to prevent subsequent passes from combing
the stack tie with something like a reg->reg copy resulting in a stack
tie with the same source/dest register?
Or are we trying to make sure the users of this insn never generate that
scenario to begin with?
jeff
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/5] RISC-V: Small stack tie changes
2024-07-26 17:00 ` Jeff Law
@ 2024-07-26 18:43 ` Raphael Zinsly
2024-07-26 20:22 ` Jeff Law
0 siblings, 1 reply; 23+ messages in thread
From: Raphael Zinsly @ 2024-07-26 18:43 UTC (permalink / raw)
To: Jeff Law; +Cc: gcc-patches, jlaw
On Fri, Jul 26, 2024 at 2:00 PM Jeff Law <jeffreyalaw@gmail.com> wrote:
> On 7/24/24 12:00 PM, Raphael Moreira Zinsly wrote:
> ...
> > diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> > index 46c46039c33..5780c5abacf 100644
> > --- a/gcc/config/riscv/riscv.md
> > +++ b/gcc/config/riscv/riscv.md
> > @@ -3969,7 +3969,7 @@
> > (unspec:BLK [(match_operand:X 0 "register_operand" "r")
> > (match_operand:X 1 "register_operand" "r")]
> > UNSPEC_TIE))]
> > - ""
> > + "!rtx_equal_p (operands[0], operands[1])"
> > ""
> > [(set_attr "type" "ghost")
> > (set_attr "length" "0")]
> I'm guessing this condition to to prevent subsequent passes from combing
> the stack tie with something like a reg->reg copy resulting in a stack
> tie with the same source/dest register?
Correct, specifically it can result in a stack tie with sp as both the
src and dest registers and removing the S0 move needed in the vector
probe loop.
> Or are we trying to make sure the users of this insn never generate that
> scenario to begin with?
>
> jeff
>
--
Raphael Moreira Zinsly
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/5] RISC-V: Small stack tie changes
2024-07-26 18:43 ` Raphael Zinsly
@ 2024-07-26 20:22 ` Jeff Law
0 siblings, 0 replies; 23+ messages in thread
From: Jeff Law @ 2024-07-26 20:22 UTC (permalink / raw)
To: Raphael Zinsly; +Cc: gcc-patches, jlaw
On 7/26/24 12:43 PM, Raphael Zinsly wrote:
> On Fri, Jul 26, 2024 at 2:00 PM Jeff Law <jeffreyalaw@gmail.com> wrote:
>> On 7/24/24 12:00 PM, Raphael Moreira Zinsly wrote:
>> ...
>>> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
>>> index 46c46039c33..5780c5abacf 100644
>>> --- a/gcc/config/riscv/riscv.md
>>> +++ b/gcc/config/riscv/riscv.md
>>> @@ -3969,7 +3969,7 @@
>>> (unspec:BLK [(match_operand:X 0 "register_operand" "r")
>>> (match_operand:X 1 "register_operand" "r")]
>>> UNSPEC_TIE))]
>>> - ""
>>> + "!rtx_equal_p (operands[0], operands[1])"
>>> ""
>>> [(set_attr "type" "ghost")
>>> (set_attr "length" "0")]
>> I'm guessing this condition to to prevent subsequent passes from combining
>> the stack tie with something like a reg->reg copy resulting in a stack
>> tie with the same source/dest register?
>
> Correct, specifically it can result in a stack tie with sp as both the
> src and dest registers and removing the S0 move needed in the vector
> probe loop.
Thanks. I think this first patch is OK as-is. Given its NFC, you might
as well go ahead and install it whenever it's convenient for you.
Jeff
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 2/5] RISC-V: Move riscv_v_adjust_scalable_frame
2024-07-24 18:00 ` [PATCH 2/5] RISC-V: Move riscv_v_adjust_scalable_frame Raphael Moreira Zinsly
@ 2024-07-26 20:26 ` Jeff Law
0 siblings, 0 replies; 23+ messages in thread
From: Jeff Law @ 2024-07-26 20:26 UTC (permalink / raw)
To: Raphael Moreira Zinsly, gcc-patches; +Cc: jlaw
On 7/24/24 12:00 PM, Raphael Moreira Zinsly wrote:
> Move riscv_v_adjust_scalable_frame () in preparation for the stack clash
> protection support.
>
> gcc/ChangeLog:
> * config/riscv/riscv.cc (riscv_v_adjust_scalable_frame): Move
> closer to riscv_expand_prologue.
Guessing the point is move later in riscv.cc to avoid a future patch
referencing a function before its been defined. Given it's clear NFC,
go ahead and install when it's convenient for you.
jeff
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 3/5] RISC-V: Stack-clash protection implemention
2024-07-24 18:00 ` [PATCH 3/5] RISC-V: Stack-clash protection implemention Raphael Moreira Zinsly
@ 2024-07-26 21:37 ` Jeff Law
0 siblings, 0 replies; 23+ messages in thread
From: Jeff Law @ 2024-07-26 21:37 UTC (permalink / raw)
To: Raphael Moreira Zinsly, gcc-patches; +Cc: jlaw
On 7/24/24 12:00 PM, Raphael Moreira Zinsly wrote:
> This implements stack-clash protection for riscv, with
> riscv_allocate_and_probe_stack_space being based of
> aarch64_allocate_and_probe_stack_space from aarch64's implementation.
> We enforce the probing interval and the guard size to always be equal, their
> default value is 4Kb which is riscv page size.
>
> We also probe up by 1024 bytes in the general case when a probe is required.
>
> gcc/ChangeLog:
> * config/riscv/riscv.cc
> (riscv_option_override): Enforce that interval is the same size as
> guard size.
> (riscv_allocate_and_probe_stack_space): New function.
> (riscv_expand_prologue): Call riscv_allocate_and_probe_stack_space
> to the final allocation of the stack and add stack-clash dump
> information.
> * config/riscv/riscv.h: Define STACK_CLASH_CALLER_GUARD and
> STACK_CLASH_MAX_UNROLL_PAGES.
>
> gcc/testsuite/ChangeLog:
> * gcc.dg/params/blocksort-part.c: Skip riscv for
> stack-clash protection intervals.
> * gcc.dg/pr82788.c: Skip riscv.
> * gcc.dg/stack-check-6.c: Skip residual check for riscv.
> * gcc.dg/stack-check-6a.c: Skip riscv.
> * gcc.target/riscv/stack-check-12.c: New test.
> * gcc.target/riscv/stack-check-13.c: New test.
> * gcc.target/riscv/stack-check-cfa-1.c: New test.
> * gcc.target/riscv/stack-check-cfa-2.c: New test.
> * gcc.target/riscv/stack-check-prologue-1.c: New test.
> * gcc.target/riscv/stack-check-prologue-10.c: New test.
> * gcc.target/riscv/stack-check-prologue-11.c: New test.
> * gcc.target/riscv/stack-check-prologue-12.c: New test.
> * gcc.target/riscv/stack-check-prologue-13.c: New test.
> * gcc.target/riscv/stack-check-prologue-14.c: New test.
> * gcc.target/riscv/stack-check-prologue-15.c: New test.
> * gcc.target/riscv/stack-check-prologue-2.c: New test.
> * gcc.target/riscv/stack-check-prologue-3.c: New test.
> * gcc.target/riscv/stack-check-prologue-4.c: New test.
> * gcc.target/riscv/stack-check-prologue-5.c: New test.
> * gcc.target/riscv/stack-check-prologue-6.c: New test.
> * gcc.target/riscv/stack-check-prologue-7.c: New test.
> * gcc.target/riscv/stack-check-prologue-8.c: New test.
> * gcc.target/riscv/stack-check-prologue-9.c: New test.
> * gcc.target/riscv/stack-check-prologue.h: New file.
> * lib/target-supports.exp
> (check_effective_target_supports_stack_clash_protection):
> Add riscv.
> (check_effective_target_caller_implicit_probes): Likewise.
Guessing you've got a mixture of tabs and spaces in the ChangeLog entry.
I suspect the pre-commit hooks will complain about them.
This all looks really good. It follows the aarch64 implementation
reasonably closely with the notable exception of the RTL probe loop
rather than using probe_stack_range, but with the ability to have
multiple blocks in the prologue (that we didn't have in 2017/2018),
yours is the current preferred method.
I did reasonably closely check the bits you moved from
riscv_expand_prologue given the difficulties we had with them recently.
That all looked good as well.
I initially expected more changes to be necessary in
target_supports.exp, but reviewing aarch64's handling in there, I think
you got it right. For aarch64 & riscv, we support stack clash
protection and have limited implicit probes due to saving $ra. The
other properties don't apply to aarch64/riscv.
So again, overall it looks really good.
And to get on the record testing-wise. Raphael and I had just started
doing large scale testing of Fedora packages about a month ago. We
identified ~6k binary packages that looked potentially vulnerable given
the scanner work from Red Hat & Samsung. That narrowed down to around
4k source packages that we'd need to test with before/after builds.
We were just starting the rebuild & rescan process and were seeing good
results and our milkv pioneer system completely scrambled its disk (for
the 2nd time :( That naturally brought testing to a halt. Just
recovering data off the data drive is proving somewhat painful. We're
still committed to doing that testing as it proved quite valuable on x86
years ago when I did that implementation. I fully expect it'll find
minor glitches either in the scanner or the compiler bits.
Raphael has done bootstraps and regression testing for rv32 and rv64
with stack clash enabled (which was definitely useful in exposing
additional issues).
Your call whether or not to include it now or wait for review on 4/5 and
5/5.
Jeff
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 4/5] RISC-V: Add support to vector stack-clash protection
2024-07-24 18:00 ` [PATCH 4/5] RISC-V: Add support to vector stack-clash protection Raphael Moreira Zinsly
@ 2024-07-26 21:48 ` Jeff Law
2024-07-29 12:18 ` Raphael Zinsly
2024-08-01 12:01 ` [PATCH v2] " Raphael Moreira Zinsly
1 sibling, 1 reply; 23+ messages in thread
From: Jeff Law @ 2024-07-26 21:48 UTC (permalink / raw)
To: Raphael Moreira Zinsly, gcc-patches; +Cc: jlaw
On 7/24/24 12:00 PM, Raphael Moreira Zinsly wrote:
> Adds basic support to vector stack-clash protection using a loop to do
> the probing and stack adjustments.
>
> gcc/ChangeLog:
> * config/riscv/riscv.cc
> (riscv_allocate_and_probe_stack_loop): New function.
> (riscv_v_adjust_scalable_frame): Add stack-clash protection
> support.
> (riscv_allocate_and_probe_stack_space): Move the probe loop
> implementation to riscv_allocate_and_probe_stack_loop.
> * config/riscv/riscv.h: Define RISCV_STACK_CLASH_VECTOR_CFA_REGNUM.
>
> gcc/testsuite/ChangeLog:
> * gcc.target/riscv/stack-check-cfa-3.c: New test.
> * gcc.target/riscv/stack-check-prologue-16.c: New test.
> * gcc.target/riscv/struct_vect_24.c: New test.
So my only worry here is using another scratch register in the prologue
code instead of using one of the preexisting prologue scratch registers.
Is there a reasonable way to use PROLOGUE_TEMP or PROLOGUE_TEMP2 here?
Otherwise this looks good as well. So let's get closure on that
question and we can move forward after that.
jeff
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 5/5] RISC-V: Enable stack clash in alloca
2024-07-24 18:00 ` [PATCH 5/5] RISC-V: Enable stack clash in alloca Raphael Moreira Zinsly
@ 2024-07-26 21:53 ` Jeff Law
0 siblings, 0 replies; 23+ messages in thread
From: Jeff Law @ 2024-07-26 21:53 UTC (permalink / raw)
To: Raphael Moreira Zinsly, gcc-patches; +Cc: jlaw
On 7/24/24 12:00 PM, Raphael Moreira Zinsly wrote:
> 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.
Thanks for adding this. I don't offhand remember if I originally
noticed the lack of ALLOCA_PROBE_RANGE during review or as a result of
the initial package testing that started before the milkv blew up where
the unhandled cases very much looked alloca related. Either way, needed
fixing and thanks for taking care of it.
This looks good. So the only outstanding question is that one for
prologue temporaries in patch 4/5.
Jeff
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 4/5] RISC-V: Add support to vector stack-clash protection
2024-07-26 21:48 ` Jeff Law
@ 2024-07-29 12:18 ` Raphael Zinsly
2024-07-29 14:20 ` Jeff Law
0 siblings, 1 reply; 23+ messages in thread
From: Raphael Zinsly @ 2024-07-29 12:18 UTC (permalink / raw)
To: Jeff Law; +Cc: gcc-patches, jlaw
On Fri, Jul 26, 2024 at 6:48 PM Jeff Law <jeffreyalaw@gmail.com> wrote:
>
>
>
> On 7/24/24 12:00 PM, Raphael Moreira Zinsly wrote:
> > Adds basic support to vector stack-clash protection using a loop to do
> > the probing and stack adjustments.
> >
> > gcc/ChangeLog:
> > * config/riscv/riscv.cc
> > (riscv_allocate_and_probe_stack_loop): New function.
> > (riscv_v_adjust_scalable_frame): Add stack-clash protection
> > support.
> > (riscv_allocate_and_probe_stack_space): Move the probe loop
> > implementation to riscv_allocate_and_probe_stack_loop.
> > * config/riscv/riscv.h: Define RISCV_STACK_CLASH_VECTOR_CFA_REGNUM.
> >
> > gcc/testsuite/ChangeLog:
> > * gcc.target/riscv/stack-check-cfa-3.c: New test.
> > * gcc.target/riscv/stack-check-prologue-16.c: New test.
> > * gcc.target/riscv/struct_vect_24.c: New test.
> So my only worry here is using another scratch register in the prologue
> code instead of using one of the preexisting prologue scratch registers.
> Is there a reasonable way to use PROLOGUE_TEMP or PROLOGUE_TEMP2 here?
These are the preexisting prologue scratch registers: PROLOGUE_TEMP is
t0 and PROLOGUE_TEMP2 is t1.
> Otherwise this looks good as well. So let's get closure on that
> question and we can move forward after that.
>
> jeff
--
Raphael Moreira Zinsly
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 4/5] RISC-V: Add support to vector stack-clash protection
2024-07-29 12:18 ` Raphael Zinsly
@ 2024-07-29 14:20 ` Jeff Law
2024-07-29 14:52 ` Raphael Zinsly
0 siblings, 1 reply; 23+ messages in thread
From: Jeff Law @ 2024-07-29 14:20 UTC (permalink / raw)
To: Raphael Zinsly; +Cc: gcc-patches, jlaw
On 7/29/24 6:18 AM, Raphael Zinsly wrote:
> On Fri, Jul 26, 2024 at 6:48 PM Jeff Law <jeffreyalaw@gmail.com> wrote:
>>
>>
>>
>> On 7/24/24 12:00 PM, Raphael Moreira Zinsly wrote:
>>> Adds basic support to vector stack-clash protection using a loop to do
>>> the probing and stack adjustments.
>>>
>>> gcc/ChangeLog:
>>> * config/riscv/riscv.cc
>>> (riscv_allocate_and_probe_stack_loop): New function.
>>> (riscv_v_adjust_scalable_frame): Add stack-clash protection
>>> support.
>>> (riscv_allocate_and_probe_stack_space): Move the probe loop
>>> implementation to riscv_allocate_and_probe_stack_loop.
>>> * config/riscv/riscv.h: Define RISCV_STACK_CLASH_VECTOR_CFA_REGNUM.
>>>
>>> gcc/testsuite/ChangeLog:
>>> * gcc.target/riscv/stack-check-cfa-3.c: New test.
>>> * gcc.target/riscv/stack-check-prologue-16.c: New test.
>>> * gcc.target/riscv/struct_vect_24.c: New test.
>> So my only worry here is using another scratch register in the prologue
>> code instead of using one of the preexisting prologue scratch registers.
>> Is there a reasonable way to use PROLOGUE_TEMP or PROLOGUE_TEMP2 here?
>
> These are the preexisting prologue scratch registers: PROLOGUE_TEMP is
> t0 and PROLOGUE_TEMP2 is t1.
>
>> Otherwise this looks good as well. So let's get closure on that
>> question and we can move forward after that.
Right. And so my question is can we use PROLOGUE_TEMP or PROLOGUE_TEMP2
rather than defining another temporary for the prologue?
It may not seem all that important, but the more distinct hardware
register we use this way, the more likely we are to run into problems
with -fcall-saved-<reg> options. Right now I suspect both the risc-v
and aarch64 ports are broken WRT the -fcall-saved-<reg> option. We
shouldn't make it worse if we can avoid it.
jeff
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 4/5] RISC-V: Add support to vector stack-clash protection
2024-07-29 14:20 ` Jeff Law
@ 2024-07-29 14:52 ` Raphael Zinsly
2024-07-30 19:29 ` Jeff Law
0 siblings, 1 reply; 23+ messages in thread
From: Raphael Zinsly @ 2024-07-29 14:52 UTC (permalink / raw)
To: Jeff Law; +Cc: gcc-patches, jlaw
On Mon, Jul 29, 2024 at 11:20 AM Jeff Law <jeffreyalaw@gmail.com> wrote:
>
>
>
> On 7/29/24 6:18 AM, Raphael Zinsly wrote:
> > On Fri, Jul 26, 2024 at 6:48 PM Jeff Law <jeffreyalaw@gmail.com> wrote:
> >>
> >>
> >>
> >> On 7/24/24 12:00 PM, Raphael Moreira Zinsly wrote:
> >>> Adds basic support to vector stack-clash protection using a loop to do
> >>> the probing and stack adjustments.
> >>>
> >>> gcc/ChangeLog:
> >>> * config/riscv/riscv.cc
> >>> (riscv_allocate_and_probe_stack_loop): New function.
> >>> (riscv_v_adjust_scalable_frame): Add stack-clash protection
> >>> support.
> >>> (riscv_allocate_and_probe_stack_space): Move the probe loop
> >>> implementation to riscv_allocate_and_probe_stack_loop.
> >>> * config/riscv/riscv.h: Define RISCV_STACK_CLASH_VECTOR_CFA_REGNUM.
> >>>
> >>> gcc/testsuite/ChangeLog:
> >>> * gcc.target/riscv/stack-check-cfa-3.c: New test.
> >>> * gcc.target/riscv/stack-check-prologue-16.c: New test.
> >>> * gcc.target/riscv/struct_vect_24.c: New test.
> >> So my only worry here is using another scratch register in the prologue
> >> code instead of using one of the preexisting prologue scratch registers.
> >> Is there a reasonable way to use PROLOGUE_TEMP or PROLOGUE_TEMP2 here?
> >
> > These are the preexisting prologue scratch registers: PROLOGUE_TEMP is
> > t0 and PROLOGUE_TEMP2 is t1.
> >
> >> Otherwise this looks good as well. So let's get closure on that
> >> question and we can move forward after that.
> Right. And so my question is can we use PROLOGUE_TEMP or PROLOGUE_TEMP2
> rather than defining another temporary for the prologue?
We are only using these two and we do not need to use another temporary.
Do you mean stop using riscv_force_temporary?
If so, yes, we can change it to riscv_emit_move.
> It may not seem all that important, but the more distinct hardware
> register we use this way, the more likely we are to run into problems
> with -fcall-saved-<reg> options. Right now I suspect both the risc-v
> and aarch64 ports are broken WRT the -fcall-saved-<reg> option. We
> shouldn't make it worse if we can avoid it.
>
> jeff
Thanks,
--
Raphael Moreira Zinsly
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 4/5] RISC-V: Add support to vector stack-clash protection
2024-07-29 14:52 ` Raphael Zinsly
@ 2024-07-30 19:29 ` Jeff Law
2024-07-30 20:50 ` Raphael Zinsly
0 siblings, 1 reply; 23+ messages in thread
From: Jeff Law @ 2024-07-30 19:29 UTC (permalink / raw)
To: Raphael Zinsly; +Cc: gcc-patches, jlaw
On 7/29/24 8:52 AM, Raphael Zinsly wrote:
> On Mon, Jul 29, 2024 at 11:20 AM Jeff Law <jeffreyalaw@gmail.com> wrote:
>>
>>
>>
>> On 7/29/24 6:18 AM, Raphael Zinsly wrote:
>>> On Fri, Jul 26, 2024 at 6:48 PM Jeff Law <jeffreyalaw@gmail.com> wrote:
>>>>
>>>>
>>>>
>>>> On 7/24/24 12:00 PM, Raphael Moreira Zinsly wrote:
>>>>> Adds basic support to vector stack-clash protection using a loop to do
>>>>> the probing and stack adjustments.
>>>>>
>>>>> gcc/ChangeLog:
>>>>> * config/riscv/riscv.cc
>>>>> (riscv_allocate_and_probe_stack_loop): New function.
>>>>> (riscv_v_adjust_scalable_frame): Add stack-clash protection
>>>>> support.
>>>>> (riscv_allocate_and_probe_stack_space): Move the probe loop
>>>>> implementation to riscv_allocate_and_probe_stack_loop.
>>>>> * config/riscv/riscv.h: Define RISCV_STACK_CLASH_VECTOR_CFA_REGNUM.
>>>>>
>>>>> gcc/testsuite/ChangeLog:
>>>>> * gcc.target/riscv/stack-check-cfa-3.c: New test.
>>>>> * gcc.target/riscv/stack-check-prologue-16.c: New test.
>>>>> * gcc.target/riscv/struct_vect_24.c: New test.
>>>> So my only worry here is using another scratch register in the prologue
>>>> code instead of using one of the preexisting prologue scratch registers.
>>>> Is there a reasonable way to use PROLOGUE_TEMP or PROLOGUE_TEMP2 here?
>>>
>>> These are the preexisting prologue scratch registers: PROLOGUE_TEMP is
>>> t0 and PROLOGUE_TEMP2 is t1.
>>>
>>>> Otherwise this looks good as well. So let's get closure on that
>>>> question and we can move forward after that.
>> Right. And so my question is can we use PROLOGUE_TEMP or PROLOGUE_TEMP2
>> rather than defining another temporary for the prologue?
>
> We are only using these two and we do not need to use another temporary.
> Do you mean stop using riscv_force_temporary?
> If so, yes, we can change it to riscv_emit_move.
You define:
+#define RISCV_STACK_CLASH_VECTOR_CFA_REGNUM (GP_TEMP_FIRST + 4)
Where:
#define GP_REG_FIRST 0
#define GP_TEMP_FIRST (GP_REG_FIRST + 5)
So RISCV_STACK_CLASH_VECTOR_CFA_REGNUM defined as "9" which I think is
"s1". That can't be what we want :-)
What I don't understand is why we don't use RISCV_PROLOGUE_TEMP_REGNUM
or RISCV_PROLOGUE_TEMP2_REGNUM which are defined as t0 and t1 respectively.
We'd have to audit the prologue/epilogue code to ensure we can safely
use one of those two as a scratch in the context we care about.
jeff
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 4/5] RISC-V: Add support to vector stack-clash protection
2024-07-30 19:29 ` Jeff Law
@ 2024-07-30 20:50 ` Raphael Zinsly
2024-07-30 20:57 ` Jeff Law
0 siblings, 1 reply; 23+ messages in thread
From: Raphael Zinsly @ 2024-07-30 20:50 UTC (permalink / raw)
To: Jeff Law; +Cc: gcc-patches, jlaw
On Tue, Jul 30, 2024 at 4:29 PM Jeff Law <jeffreyalaw@gmail.com> wrote:
>...
> You define:
> +#define RISCV_STACK_CLASH_VECTOR_CFA_REGNUM (GP_TEMP_FIRST + 4)
>
> Where:
> #define GP_REG_FIRST 0
> #define GP_TEMP_FIRST (GP_REG_FIRST + 5)
>
> So RISCV_STACK_CLASH_VECTOR_CFA_REGNUM defined as "9" which I think is
> "s1". That can't be what we want :-)
Sorry I misunderstood your initial question.
Yes I am using s1 as a copy of the stack pointer and the new CFA.
It's only being used in a "mov s1,sp".
> What I don't understand is why we don't use RISCV_PROLOGUE_TEMP_REGNUM
> or RISCV_PROLOGUE_TEMP2_REGNUM which are defined as t0 and t1 respectively.
We already need both in the vector probe loop so unfortunately we
can't set them as the new CFA.
I'm using t0 as the probe size and t1 as the length/control of the loop.
> We'd have to audit the prologue/epilogue code to ensure we can safely
> use one of those two as a scratch in the context we care about.
>
> jeff
--
Raphael Moreira Zinsly
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 4/5] RISC-V: Add support to vector stack-clash protection
2024-07-30 20:50 ` Raphael Zinsly
@ 2024-07-30 20:57 ` Jeff Law
0 siblings, 0 replies; 23+ messages in thread
From: Jeff Law @ 2024-07-30 20:57 UTC (permalink / raw)
To: Raphael Zinsly; +Cc: gcc-patches, jlaw
On 7/30/24 2:50 PM, Raphael Zinsly wrote:
> On Tue, Jul 30, 2024 at 4:29 PM Jeff Law <jeffreyalaw@gmail.com> wrote:
>> ...
>> You define:
>> +#define RISCV_STACK_CLASH_VECTOR_CFA_REGNUM (GP_TEMP_FIRST + 4)
>>
>> Where:
>> #define GP_REG_FIRST 0
>> #define GP_TEMP_FIRST (GP_REG_FIRST + 5)
>>
>> So RISCV_STACK_CLASH_VECTOR_CFA_REGNUM defined as "9" which I think is
>> "s1". That can't be what we want :-)
>
> Sorry I misunderstood your initial question.
Figured we weren't on the same page with that :-)
> Yes I am using s1 as a copy of the stack pointer and the new CFA.
> It's only being used in a "mov s1,sp".
But s1 is a call saved register. So you can't overwrite it like that
without having first saved it. I'm guessing we can't use t2 because
it's the static chain. So what about t3? (GP_TEMP_FIRST+3)
It's not great, but it's better than s1 I think.
Jeff
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH v2] RISC-V: Add support to vector stack-clash protection
2024-07-24 18:00 ` [PATCH 4/5] RISC-V: Add support to vector stack-clash protection Raphael Moreira Zinsly
2024-07-26 21:48 ` Jeff Law
@ 2024-08-01 12:01 ` Raphael Moreira Zinsly
2024-08-01 18:40 ` Jeff Law
1 sibling, 1 reply; 23+ messages in thread
From: Raphael Moreira Zinsly @ 2024-08-01 12:01 UTC (permalink / raw)
To: gcc-patches, jeffreyalaw; +Cc: jlaw, Raphael Moreira Zinsly
Changes since v1:
- Changed RISCV_STACK_CLASH_VECTOR_CFA_REGNUM to t3.
-- >8 --
Adds basic support to vector stack-clash protection using a loop to do
the probing and stack adjustments.
gcc/ChangeLog:
* config/riscv/riscv.cc
(riscv_allocate_and_probe_stack_loop): New function.
(riscv_v_adjust_scalable_frame): Add stack-clash protection
support.
(riscv_allocate_and_probe_stack_space): Move the probe loop
implementation to riscv_allocate_and_probe_stack_loop.
* config/riscv/riscv.h: Define RISCV_STACK_CLASH_VECTOR_CFA_REGNUM.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/stack-check-cfa-3.c: New test.
* gcc.target/riscv/stack-check-prologue-16.c: New test.
* gcc.target/riscv/struct_vect_24.c: New test.
---
gcc/config/riscv/riscv.cc | 99 +++++++++++++++----
gcc/config/riscv/riscv.h | 5 +
.../gcc.target/riscv/stack-check-cfa-3.c | 13 +++
.../riscv/stack-check-prologue-16.c | 30 ++++++
.../gcc.target/riscv/struct_vect_24.c | 47 +++++++++
5 files changed, 173 insertions(+), 21 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-cfa-3.c
create mode 100644 gcc/testsuite/gcc.target/riscv/stack-check-prologue-16.c
create mode 100644 gcc/testsuite/gcc.target/riscv/struct_vect_24.c
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index b3534ee0b92..ccbb7ea1324 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -7898,6 +7898,35 @@ static const code_for_push_pop_t code_for_push_pop[ZCMP_MAX_GRP_SLOTS][ZCMP_OP_N
code_for_gpr_multi_popret_up_to_s11,
code_for_gpr_multi_popretz_up_to_s11}};
+/* Set a probe loop for stack clash protection. */
+static void
+riscv_allocate_and_probe_stack_loop (rtx tmp, enum rtx_code code,
+ rtx op0, rtx op1, bool vector,
+ HOST_WIDE_INT offset)
+{
+ tmp = riscv_force_temporary (tmp, gen_int_mode (offset, Pmode));
+
+ /* Loop. */
+ rtx label = gen_label_rtx ();
+ emit_label (label);
+
+ /* Allocate and probe stack. */
+ emit_insn (gen_sub3_insn (stack_pointer_rtx, stack_pointer_rtx, tmp));
+ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
+ STACK_CLASH_CALLER_GUARD));
+ emit_insn (gen_blockage ());
+
+ /* Adjust the remaining vector length. */
+ if (vector)
+ emit_insn (gen_sub3_insn (op0, op0, tmp));
+
+ /* Branch if there's still more bytes to probe. */
+ riscv_expand_conditional_branch (label, code, op0, op1);
+ JUMP_LABEL (get_last_insn ()) = label;
+
+ emit_insn (gen_blockage ());
+}
+
/* Adjust scalable frame of vector for prologue && epilogue. */
static void
@@ -7910,6 +7939,49 @@ riscv_v_adjust_scalable_frame (rtx target, poly_int64 offset, bool epilogue)
riscv_legitimize_poly_move (Pmode, adjust_size, tmp,
gen_int_mode (offset, Pmode));
+ /* If doing stack clash protection then we use a loop to allocate and probe
+ the stack. */
+ if (flag_stack_clash_protection && !epilogue)
+ {
+ HOST_WIDE_INT min_probe_threshold
+ = (1 << param_stack_clash_protection_guard_size) - STACK_CLASH_CALLER_GUARD;
+
+ if (!frame_pointer_needed)
+ {
+ /* This is done to provide unwinding information for the stack
+ adjustments we're about to do, however to prevent the optimizers
+ from removing the T3 move and leaving the CFA note (which would be
+ very wrong) we tie the old and new stack pointer together.
+ The tie will expand to nothing but the optimizers will not touch
+ the instruction. */
+ insn = get_last_insn ();
+ rtx stack_ptr_copy = gen_rtx_REG (Pmode, RISCV_STACK_CLASH_VECTOR_CFA_REGNUM);
+ emit_move_insn (stack_ptr_copy, stack_pointer_rtx);
+ riscv_emit_stack_tie (stack_ptr_copy);
+
+ /* We want the CFA independent of the stack pointer for the
+ duration of the loop. */
+ add_reg_note (insn, REG_CFA_DEF_CFA, stack_ptr_copy);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ riscv_allocate_and_probe_stack_loop (tmp, GE, adjust_size, tmp, true,
+ min_probe_threshold);
+
+ /* Allocate the residual. */
+ insn = emit_insn (gen_sub3_insn (target, target, adjust_size));
+
+ /* Now reset the CFA register if needed. */
+ if (!frame_pointer_needed)
+ {
+ add_reg_note (insn, REG_CFA_DEF_CFA,
+ plus_constant (Pmode, stack_pointer_rtx, -offset));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ return;
+ }
+
if (epilogue)
insn = gen_add3_insn (target, target, adjust_size);
else
@@ -8057,8 +8129,9 @@ riscv_allocate_and_probe_stack_space (rtx temp1, HOST_WIDE_INT 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));
+ rtx temp2 = gen_rtx_REG (Pmode, RISCV_PROLOGUE_TEMP2_REGNUM);
+ temp2 = riscv_force_temporary (temp2, gen_int_mode (rounded_size, Pmode));
+ insn = emit_insn (gen_sub3_insn (temp2, stack_pointer_rtx, temp2));
if (!frame_pointer_needed)
{
@@ -8069,25 +8142,9 @@ riscv_allocate_and_probe_stack_space (rtx temp1, HOST_WIDE_INT 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 ());
+ /* This allocates and probes the stack. */
+ riscv_allocate_and_probe_stack_loop (temp1, NE, stack_pointer_rtx, temp2,
+ false, guard_size);
/* Now reset the CFA register if needed. */
if (!frame_pointer_needed)
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 9670c7df8f7..35a53982ae9 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -429,6 +429,11 @@ ASM_MISA_SPEC
#define RISCV_PROLOGUE_TEMP2_REGNUM (GP_TEMP_FIRST + 1)
#define RISCV_PROLOGUE_TEMP2(MODE) gen_rtx_REG (MODE, RISCV_PROLOGUE_TEMP2_REGNUM)
+/* Both prologue temp registers are used in the vector probe loop for when
+ stack-clash protection is enabled, so we need to copy SP to a new register
+ and set it as CFA during the loop, we are using T3 for that. */
+#define RISCV_STACK_CLASH_VECTOR_CFA_REGNUM (GP_TEMP_FIRST + 23)
+
#define RISCV_CALL_ADDRESS_TEMP_REGNUM (GP_TEMP_FIRST + 1)
#define RISCV_CALL_ADDRESS_TEMP(MODE) \
gen_rtx_REG (MODE, RISCV_CALL_ADDRESS_TEMP_REGNUM)
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-cfa-3.c b/gcc/testsuite/gcc.target/riscv/stack-check-cfa-3.c
new file mode 100644
index 00000000000..e45f7bb7df5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-cfa-3.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -fstack-clash-protection -funwind-tables -fno-stack-protector" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+#include "stack-check-prologue-16.c"
+
+/* Checks that the CFA notes are correct for every sp adjustment, but we also
+ need to make sure we can unwind correctly before the frame is set up. So
+ check that we're emitting t3 with a copy of sp an setting the CFA there. */
+
+/* { dg-final { scan-assembler-times {mv\tt3,sp} 1 } } */
+/* { dg-final { scan-assembler-times {\.cfi_def_cfa [0-9]+, 0} 1 } } */
+/* { dg-final { scan-assembler-times {\.cfi_escape 0xf,0xa,0x72,0,0x92,0xa2,0x38,0,0x9,0xec,0x1e,0x22} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-prologue-16.c b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-16.c
new file mode 100644
index 00000000000..c74dce04b23
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/stack-check-prologue-16.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -fstack-clash-protection" } */
+
+/* Invoke X (P##n) for n in [0, 7]. */
+#define REPEAT8(X, P) \
+ X (P##0) X (P##1) X (P##2) X (P##3) X (P##4) X (P##5) X (P##6) X (P##7)
+
+/* Invoke X (n) for all octal n in [0, 39]. */
+#define REPEAT40(X) \
+ REPEAT8 (X, 0) REPEAT8 (X, 1) REPEAT8 (X, 2) REPEAT8 (X, 3) REPEAT8 (X, 4)
+
+/* Expect vector work to be done, with spilling of vector registers. */
+void
+f2 (int x[40][100], int *y)
+{
+ /* Try to force some spilling. */
+#define DECLARE(N) int y##N = y[N];
+ REPEAT40 (DECLARE);
+#pragma omp simd
+ for (int i = 0; i < 100; ++i)
+ {
+#define INC(N) x[N][i] += y##N;
+ REPEAT40 (INC);
+ }
+}
+
+/* Vector spill, requires probing as vector size is unknown at compile time. */
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/struct_vect_24.c b/gcc/testsuite/gcc.target/riscv/struct_vect_24.c
new file mode 100644
index 00000000000..7c0852f1a55
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/struct_vect_24.c
@@ -0,0 +1,47 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -fstack-clash-protection -fno-stack-protector" } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-Os" "-Oz" "-funroll-loops"} } */
+
+#include <stdint.h>
+
+#define N 50
+#define S 2 * 4 * 1024
+
+/* Invoke X (P##n) for n in [0, 9]. */
+#define REPEAT8(X, P) \
+ X (P##0) X (P##1) X (P##2) X (P##3) X (P##4) X (P##5) X (P##6) X (P##7) \
+ X (P##8) X (P##9)
+
+/* Invoke X (n) for all n in [0, 49]. */
+#define REPEAT50(X) \
+ REPEAT8 (X, ) REPEAT8 (X, 1) REPEAT8 (X, 2) REPEAT8 (X, 3) REPEAT8 (X, 4)
+
+ /* Try to force some spilling. */
+#define DECLARE(N) int src##N = src[N * 4];
+#define INC(N) dest[i] += src##N;
+
+#define TEST_LOOP(NAME, TYPE) \
+ void __attribute__ ((noinline)) \
+ NAME (TYPE *restrict dest, TYPE *restrict src) \
+ { \
+ REPEAT50 (DECLARE); \
+ volatile char foo[S]; \
+ foo[S-1]=1; \
+ for (int i = 0; i < N; i++) \
+ { \
+ REPEAT50 (INC); \
+ } \
+ }
+
+#define TEST(NAME) \
+ TEST_LOOP (NAME##_i32, int32_t) \
+ TEST_LOOP (NAME##_i64, int64_t)
+
+TEST (test)
+
+/* Check the vectorized loop for stack clash probing. */
+
+/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 6 } } */
+/* { dg-final { scan-assembler-times {bge\tt1,t0,.[^\\r\\n]*} 2 } } */
+/* { dg-final { scan-assembler-times {sub\s+t1,t1,t0} 2 } } */
--
2.42.0
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v2] RISC-V: Add support to vector stack-clash protection
2024-08-01 12:01 ` [PATCH v2] " Raphael Moreira Zinsly
@ 2024-08-01 18:40 ` Jeff Law
2024-08-01 20:16 ` Raphael Zinsly
0 siblings, 1 reply; 23+ messages in thread
From: Jeff Law @ 2024-08-01 18:40 UTC (permalink / raw)
To: Raphael Moreira Zinsly, gcc-patches; +Cc: jlaw
On 8/1/24 6:01 AM, Raphael Moreira Zinsly wrote:
>
> +/* Both prologue temp registers are used in the vector probe loop for when
> + stack-clash protection is enabled, so we need to copy SP to a new register
> + and set it as CFA during the loop, we are using T3 for that. */
> +#define RISCV_STACK_CLASH_VECTOR_CFA_REGNUM (GP_TEMP_FIRST + 23)
"23" looks like a typo. Shouldn't it be "3"?
Jeff
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v2] RISC-V: Add support to vector stack-clash protection
2024-08-01 18:40 ` Jeff Law
@ 2024-08-01 20:16 ` Raphael Zinsly
2024-08-05 14:19 ` Jeff Law
0 siblings, 1 reply; 23+ messages in thread
From: Raphael Zinsly @ 2024-08-01 20:16 UTC (permalink / raw)
To: Jeff Law; +Cc: gcc-patches, jlaw
On Thu, Aug 1, 2024 at 3:40 PM Jeff Law <jeffreyalaw@gmail.com> wrote:
> On 8/1/24 6:01 AM, Raphael Moreira Zinsly wrote:
> > +/* Both prologue temp registers are used in the vector probe loop for when
> > + stack-clash protection is enabled, so we need to copy SP to a new register
> > + and set it as CFA during the loop, we are using T3 for that. */
> > +#define RISCV_STACK_CLASH_VECTOR_CFA_REGNUM (GP_TEMP_FIRST + 23)
> "23" looks like a typo. Shouldn't it be "3"?
GP_TEMP_FIRST + 3 = 8, which is s0/fp.
t3 is register 28.
--
Raphael Moreira Zinsly
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v2] RISC-V: Add support to vector stack-clash protection
2024-08-01 20:16 ` Raphael Zinsly
@ 2024-08-05 14:19 ` Jeff Law
0 siblings, 0 replies; 23+ messages in thread
From: Jeff Law @ 2024-08-05 14:19 UTC (permalink / raw)
To: Raphael Zinsly; +Cc: gcc-patches, jlaw
On 8/1/24 2:16 PM, Raphael Zinsly wrote:
> On Thu, Aug 1, 2024 at 3:40 PM Jeff Law <jeffreyalaw@gmail.com> wrote:
>> On 8/1/24 6:01 AM, Raphael Moreira Zinsly wrote:
>>> +/* Both prologue temp registers are used in the vector probe loop for when
>>> + stack-clash protection is enabled, so we need to copy SP to a new register
>>> + and set it as CFA during the loop, we are using T3 for that. */
>>> +#define RISCV_STACK_CLASH_VECTOR_CFA_REGNUM (GP_TEMP_FIRST + 23)
>> "23" looks like a typo. Shouldn't it be "3"?
>
> GP_TEMP_FIRST + 3 = 8, which is s0/fp.
> t3 is register 28.
I'd forgotten the temps are a disjoint set, sorry about goofing that up.
The series is OK for the trunk. IT's been a long road....
jeff
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2024-08-05 14:19 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-07-24 18:00 [PATCH 0/5] RISC-V: Enable stack-clash protection Raphael Moreira Zinsly
2024-07-24 18:00 ` [PATCH 1/5] RISC-V: Small stack tie changes Raphael Moreira Zinsly
2024-07-26 17:00 ` Jeff Law
2024-07-26 18:43 ` Raphael Zinsly
2024-07-26 20:22 ` Jeff Law
2024-07-24 18:00 ` [PATCH 2/5] RISC-V: Move riscv_v_adjust_scalable_frame Raphael Moreira Zinsly
2024-07-26 20:26 ` Jeff Law
2024-07-24 18:00 ` [PATCH 3/5] RISC-V: Stack-clash protection implemention Raphael Moreira Zinsly
2024-07-26 21:37 ` Jeff Law
2024-07-24 18:00 ` [PATCH 4/5] RISC-V: Add support to vector stack-clash protection Raphael Moreira Zinsly
2024-07-26 21:48 ` Jeff Law
2024-07-29 12:18 ` Raphael Zinsly
2024-07-29 14:20 ` Jeff Law
2024-07-29 14:52 ` Raphael Zinsly
2024-07-30 19:29 ` Jeff Law
2024-07-30 20:50 ` Raphael Zinsly
2024-07-30 20:57 ` Jeff Law
2024-08-01 12:01 ` [PATCH v2] " Raphael Moreira Zinsly
2024-08-01 18:40 ` Jeff Law
2024-08-01 20:16 ` Raphael Zinsly
2024-08-05 14:19 ` Jeff Law
2024-07-24 18:00 ` [PATCH 5/5] RISC-V: Enable stack clash in alloca Raphael Moreira Zinsly
2024-07-26 21:53 ` Jeff Law
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).