LoongArch: Optimize the implementation of stack check.

The old stack check was performed before the stack was dropped,
which would cause the detection tool to report a memory leak.

The current stack check scheme is as follows:

'-fstack-clash-protection':
1. When the frame->total_size is smaller than the guard page size,
   the stack is dropped according to the original scheme, and there
   is no need to perform stack detection in the prologue.
2. When frame->total_size is greater than or equal to guard page size,
   the first step to drop the stack is to drop the space required by
   the caller-save registers. This space needs to save the caller-save
   registers, so an implicit stack check is performed.
   So just need to check the rest of the stack space.

'-fstack-check':
There is no one-time stack drop and then page-by-page detection as
described in the document. It is also the same as
'-fstack-clash-protection', which is detected immediately after page drop.

It is judged that when frame->total_size is not 0, only the size required
to save the s register is dropped for the first stack down.

The test cases are referenced from aarch64.

gcc/ChangeLog:

	* config/loongarch/linux.h (STACK_CHECK_MOVING_SP):
	Define this macro to 1.
	* config/loongarch/loongarch.cc (STACK_CLASH_PROTECTION_GUARD_SIZE):
	Size of guard page.
	(loongarch_first_stack_step): Return the size of the first drop stack
	according to whether stack checking is performed.
	(loongarch_emit_probe_stack_range): Adjust the method of stack checking in prologue.
	(loongarch_output_probe_stack_range): Delete useless code.
	(loongarch_expand_prologue): Adjust the method of stack checking in prologue.
	(loongarch_option_override_internal): Enforce that interval is the same
	size as size so the mid-end does the right thing.
	* config/loongarch/loongarch.h (STACK_CLASH_MAX_UNROLL_PAGES):
	New macro decide whether to loop stack detection.

gcc/testsuite/ChangeLog:

	* lib/target-supports.exp:
	* gcc.target/loongarch/stack-check-alloca-1.c: New test.
	* gcc.target/loongarch/stack-check-alloca-2.c: New test.
	* gcc.target/loongarch/stack-check-alloca-3.c: New test.
	* gcc.target/loongarch/stack-check-alloca-4.c: New test.
	* gcc.target/loongarch/stack-check-alloca-5.c: New test.
	* gcc.target/loongarch/stack-check-alloca-6.c: New test.
	* gcc.target/loongarch/stack-check-alloca.h: New test.
	* gcc.target/loongarch/stack-check-cfa-1.c: New test.
	* gcc.target/loongarch/stack-check-cfa-2.c: New test.
	* gcc.target/loongarch/stack-check-prologue-1.c: New test.
	* gcc.target/loongarch/stack-check-prologue-2.c: New test.
	* gcc.target/loongarch/stack-check-prologue-3.c: New test.
	* gcc.target/loongarch/stack-check-prologue-4.c: New test.
	* gcc.target/loongarch/stack-check-prologue-5.c: New test.
	* gcc.target/loongarch/stack-check-prologue-6.c: New test.
	* gcc.target/loongarch/stack-check-prologue-7.c: New test.
	* gcc.target/loongarch/stack-check-prologue.h: New test.
This commit is contained in:
Lulu Cheng 2022-11-29 16:06:12 +08:00
parent 84046b192e
commit f57ff18957
21 changed files with 366 additions and 106 deletions

View file

@ -48,3 +48,6 @@ along with GCC; see the file COPYING3. If not see
#define STACK_CHECK_PROTECT (TARGET_64BIT ? 16 * 1024 : 12 * 1024)
#define TARGET_ASM_FILE_END file_end_indicate_exec_stack
/* The stack pointer needs to be moved while checking the stack. */
#define STACK_CHECK_MOVING_SP 1

View file

@ -257,6 +257,10 @@ const char *const
loongarch_fp_conditions[16]= {LARCH_FP_CONDITIONS (STRINGIFY)};
#undef STRINGIFY
/* Size of guard page. */
#define STACK_CLASH_PROTECTION_GUARD_SIZE \
(1 << param_stack_clash_protection_guard_size)
/* Implement TARGET_FUNCTION_ARG_BOUNDARY. Every parameter gets at
least PARM_BOUNDARY bits of alignment, but will be given anything up
to PREFERRED_STACK_BOUNDARY bits if the type requires it. */
@ -1070,11 +1074,20 @@ loongarch_restore_reg (rtx reg, rtx mem)
static HOST_WIDE_INT
loongarch_first_stack_step (struct loongarch_frame_info *frame)
{
HOST_WIDE_INT min_first_step
= LARCH_STACK_ALIGN (frame->total_size - frame->fp_sp_offset);
/* When stack checking is required, if the sum of frame->total_size
and stack_check_protect is greater than stack clash protection guard
size, then return min_first_step. */
if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
|| (flag_stack_clash_protection
&& frame->total_size > STACK_CLASH_PROTECTION_GUARD_SIZE))
return min_first_step;
if (IMM12_OPERAND (frame->total_size))
return frame->total_size;
HOST_WIDE_INT min_first_step
= LARCH_STACK_ALIGN (frame->total_size - frame->fp_sp_offset);
HOST_WIDE_INT max_first_step = IMM_REACH / 2 - PREFERRED_STACK_BOUNDARY / 8;
HOST_WIDE_INT min_second_step = frame->total_size - max_first_step;
gcc_assert (min_first_step <= max_first_step);
@ -1107,103 +1120,109 @@ loongarch_emit_stack_tie (void)
static void
loongarch_emit_probe_stack_range (HOST_WIDE_INT first, HOST_WIDE_INT size)
{
/* See if we have a constant small number of probes to generate. If so,
that's the easy case. */
if ((TARGET_64BIT && (first + size <= 32768))
|| (!TARGET_64BIT && (first + size <= 2048)))
{
HOST_WIDE_INT i;
HOST_WIDE_INT rounded_size;
HOST_WIDE_INT interval;
/* Probe at FIRST + N * PROBE_INTERVAL for values of N from 1 until
it exceeds SIZE. If only one probe is needed, this will not
generate any code. Then probe at FIRST + SIZE. */
for (i = PROBE_INTERVAL; i < size; i += PROBE_INTERVAL)
emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
-(first + i)));
emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
-(first + size)));
}
/* Otherwise, do the same as above, but in a loop. Note that we must be
extra careful with variables wrapping around because we might be at
the very top (or the very bottom) of the address space and we have
to be able to handle this case properly; in particular, we use an
equality test for the loop condition. */
if (flag_stack_clash_protection)
interval = STACK_CLASH_PROTECTION_GUARD_SIZE;
else
interval = PROBE_INTERVAL;
rtx r12 = LARCH_PROLOGUE_TEMP2 (Pmode);
rtx r14 = LARCH_PROLOGUE_TEMP3 (Pmode);
size = size + first;
/* Sanity check for the addressing mode we're going to use. */
gcc_assert (first <= 16384);
/* Step 1: round SIZE to the previous multiple of the interval. */
rounded_size = ROUND_DOWN (size, interval);
/* Step 2: compute initial and final value of the loop counter. */
emit_move_insn (r14, GEN_INT (interval));
/* If rounded_size is zero, it means that the space requested by
the local variable is less than the interval, and there is no
need to display and detect the allocated space. */
if (rounded_size != 0)
{
HOST_WIDE_INT rounded_size;
rtx r13 = LARCH_PROLOGUE_TEMP (Pmode);
rtx r12 = LARCH_PROLOGUE_TEMP2 (Pmode);
rtx r14 = LARCH_PROLOGUE_TEMP3 (Pmode);
/* Step 3: the loop
/* Sanity check for the addressing mode we're going to use. */
gcc_assert (first <= 16384);
do
{
TEST_ADDR = TEST_ADDR + PROBE_INTERVAL
probe at TEST_ADDR
}
while (TEST_ADDR != LAST_ADDR)
probes at FIRST + N * PROBE_INTERVAL for values of N from 1
until it is equal to ROUNDED_SIZE. */
/* Step 1: round SIZE to the previous multiple of the interval. */
rounded_size = ROUND_DOWN (size, PROBE_INTERVAL);
/* TEST_ADDR = SP + FIRST */
if (first != 0)
if (rounded_size <= STACK_CLASH_MAX_UNROLL_PAGES * interval)
{
emit_move_insn (r14, GEN_INT (first));
emit_insn (gen_rtx_SET (r13, gen_rtx_MINUS (Pmode,
stack_pointer_rtx,
r14)));
for (HOST_WIDE_INT i = 0; i < rounded_size; i += interval)
{
emit_insn (gen_rtx_SET (stack_pointer_rtx,
gen_rtx_MINUS (Pmode,
stack_pointer_rtx,
r14)));
emit_move_insn (gen_rtx_MEM (Pmode,
gen_rtx_PLUS (Pmode,
stack_pointer_rtx,
const0_rtx)),
const0_rtx);
emit_insn (gen_blockage ());
}
dump_stack_clash_frame_info (PROBE_INLINE, size != rounded_size);
}
else
emit_move_insn (r13, stack_pointer_rtx);
/* Step 2: compute initial and final value of the loop counter. */
emit_move_insn (r14, GEN_INT (PROBE_INTERVAL));
/* LAST_ADDR = SP + FIRST + ROUNDED_SIZE. */
if (rounded_size == 0)
emit_move_insn (r12, r13);
else
{
emit_move_insn (r12, GEN_INT (rounded_size));
emit_insn (gen_rtx_SET (r12, gen_rtx_MINUS (Pmode, r13, r12)));
/* Step 3: the loop
emit_insn (gen_rtx_SET (r12,
gen_rtx_MINUS (Pmode,
stack_pointer_rtx,
r12)));
do
{
TEST_ADDR = TEST_ADDR + PROBE_INTERVAL
probe at TEST_ADDR
}
while (TEST_ADDR != LAST_ADDR)
probes at FIRST + N * PROBE_INTERVAL for values of N from 1
until it is equal to ROUNDED_SIZE. */
emit_insn (gen_probe_stack_range (Pmode, r13, r13, r12, r14));
}
/* Step 4: probe at FIRST + SIZE if we cannot assert at compile-time
that SIZE is equal to ROUNDED_SIZE. */
if (size != rounded_size)
{
if (TARGET_64BIT)
emit_stack_probe (plus_constant (Pmode, r12, rounded_size - size));
else
{
HOST_WIDE_INT i;
for (i = 2048; i < (size - rounded_size); i += 2048)
{
emit_stack_probe (plus_constant (Pmode, r12, -i));
emit_insn (gen_rtx_SET (r12,
plus_constant (Pmode, r12, -2048)));
}
rtx r1 = plus_constant (Pmode, r12,
-(size - rounded_size - i + 2048));
emit_stack_probe (r1);
}
emit_insn (gen_probe_stack_range (Pmode, stack_pointer_rtx,
stack_pointer_rtx, r12, r14));
emit_insn (gen_blockage ());
dump_stack_clash_frame_info (PROBE_LOOP, size != rounded_size);
}
}
else
dump_stack_clash_frame_info (NO_PROBE_SMALL_FRAME, true);
/* Step 4: probe at FIRST + SIZE if we cannot assert at compile-time
that SIZE is equal to ROUNDED_SIZE. */
if (size != rounded_size)
{
if (size - rounded_size >= 2048)
{
emit_move_insn (r14, GEN_INT (size - rounded_size));
emit_insn (gen_rtx_SET (stack_pointer_rtx,
gen_rtx_MINUS (Pmode,
stack_pointer_rtx,
r14)));
}
else
emit_insn (gen_rtx_SET (stack_pointer_rtx,
gen_rtx_PLUS (Pmode,
stack_pointer_rtx,
GEN_INT (rounded_size - size))));
}
if (first)
{
emit_move_insn (r12, GEN_INT (first));
emit_insn (gen_rtx_SET (stack_pointer_rtx,
gen_rtx_PLUS (Pmode,
stack_pointer_rtx, r12)));
}
/* Make sure nothing is scheduled before we are done. */
emit_insn (gen_blockage ());
}
@ -1224,7 +1243,6 @@ loongarch_output_probe_stack_range (rtx reg1, rtx reg2, rtx reg3)
/* TEST_ADDR = TEST_ADDR + PROBE_INTERVAL. */
xops[0] = reg1;
xops[1] = GEN_INT (-PROBE_INTERVAL);
xops[2] = reg3;
if (TARGET_64BIT)
output_asm_insn ("sub.d\t%0,%0,%2", xops);
@ -1250,28 +1268,11 @@ loongarch_expand_prologue (void)
{
struct loongarch_frame_info *frame = &cfun->machine->frame;
HOST_WIDE_INT size = frame->total_size;
HOST_WIDE_INT tmp;
rtx insn;
if (flag_stack_usage_info)
current_function_static_stack_size = size;
if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
|| flag_stack_clash_protection)
{
if (crtl->is_leaf && !cfun->calls_alloca)
{
if (size > PROBE_INTERVAL && size > get_stack_check_protect ())
{
tmp = size - get_stack_check_protect ();
loongarch_emit_probe_stack_range (get_stack_check_protect (),
tmp);
}
}
else if (size > 0)
loongarch_emit_probe_stack_range (get_stack_check_protect (), size);
}
/* Save the registers. */
if ((frame->mask | frame->fmask) != 0)
{
@ -1284,7 +1285,6 @@ loongarch_expand_prologue (void)
loongarch_for_each_saved_reg (size, loongarch_save_reg);
}
/* Set up the frame pointer, if we're using one. */
if (frame_pointer_needed)
{
@ -1295,7 +1295,45 @@ loongarch_expand_prologue (void)
loongarch_emit_stack_tie ();
}
/* Allocate the rest of the frame. */
if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
|| flag_stack_clash_protection)
{
HOST_WIDE_INT first = get_stack_check_protect ();
if (frame->total_size == 0)
{
/* do nothing. */
dump_stack_clash_frame_info (NO_PROBE_NO_FRAME, false);
return;
}
if (crtl->is_leaf && !cfun->calls_alloca)
{
HOST_WIDE_INT interval;
if (flag_stack_clash_protection)
interval = STACK_CLASH_PROTECTION_GUARD_SIZE;
else
interval = PROBE_INTERVAL;
if (size > interval && size > first)
loongarch_emit_probe_stack_range (first, size - first);
else
loongarch_emit_probe_stack_range (first, size);
}
else
loongarch_emit_probe_stack_range (first, size);
if (size > 0)
{
/* Describe the effect of the previous instructions. */
insn = plus_constant (Pmode, stack_pointer_rtx, -size);
insn = gen_rtx_SET (stack_pointer_rtx, insn);
loongarch_set_frame_expr (insn);
}
return;
}
if (size > 0)
{
if (IMM12_OPERAND (-size))
@ -1306,7 +1344,8 @@ loongarch_expand_prologue (void)
}
else
{
loongarch_emit_move (LARCH_PROLOGUE_TEMP (Pmode), GEN_INT (-size));
loongarch_emit_move (LARCH_PROLOGUE_TEMP (Pmode),
GEN_INT (-size));
emit_insn (gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx,
LARCH_PROLOGUE_TEMP (Pmode)));
@ -6163,6 +6202,15 @@ loongarch_option_override_internal (struct gcc_options *opts)
gcc_unreachable ();
}
/* Validate the guard size. */
int guard_size = param_stack_clash_protection_guard_size;
/* Enforce that interval is the same size as size so the mid-end does the
right thing. */
SET_OPTION_IF_UNSET (opts, &global_options_set,
param_stack_clash_protection_probe_interval,
guard_size);
loongarch_init_print_operand_punct ();
/* Set up array to map GCC register number to debug register number.

View file

@ -668,6 +668,10 @@ enum reg_class
#define STACK_BOUNDARY (TARGET_ABI_LP64 ? 128 : 64)
/* This value controls how many pages we manually unroll the loop for when
generating stack clash probes. */
#define STACK_CLASH_MAX_UNROLL_PAGES 4
/* Symbolic macros for the registers used to return integer and floating
point values. */

View file

@ -0,0 +1,15 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
/* { dg-require-effective-target alloca } */
/* { dg-skip-if "" { *-*-* } { "-fstack-check" } { "" } } */
#define SIZE y
#include "stack-check-alloca.h"
/* { dg-final { scan-assembler-times {stp*t*r*\.d\t\$r0,\$r\d{1,2},-8} 1 } } */
/* { dg-final { scan-assembler-times {stx\.d\t\$r0,\$r3,\$r12} 1 } } */
/* Dynamic alloca, expect loop, and 1 probes with top at sp.
1st probe is inside the loop for the full guard-size allocations, second
probe is for the case where residual is zero. */

View file

@ -0,0 +1,12 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
/* { dg-require-effective-target alloca } */
/* { dg-skip-if "" { *-*-* } { "-fstack-check" } { "" } } */
#define SIZE 0
#include "stack-check-alloca.h"
/* { dg-final { scan-assembler-not {stp*t*r*\.d\t\$r0,\$r3,4088} } } */
/* Alloca of 0 should emit no probes, boundary condition. */

View file

@ -0,0 +1,12 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
/* { dg-require-effective-target alloca } */
/* { dg-skip-if "" { *-*-* } { "-fstack-check" } { "" } } */
#define SIZE 100
#include "stack-check-alloca.h"
/* { dg-final { scan-assembler-times {st\.d\t\$r0,\$r3,104} 1 } } */
/* Alloca is less than guard-size, 1 probe at the top of the new allocation. */

View file

@ -0,0 +1,12 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
/* { dg-require-effective-target alloca } */
/* { dg-skip-if "" { *-*-* } { "-fstack-check" } { "" } } */
#define SIZE 64 * 1024
#include "stack-check-alloca.h"
/* { dg-final { scan-assembler-times {stp*t*r*\.d\t\$r0,\$r\d{1,2},-8} 1 } } */
/* Alloca is exactly one guard-size, 1 probe expected at top. */

View file

@ -0,0 +1,13 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
/* { dg-require-effective-target alloca } */
/* { dg-skip-if "" { *-*-* } { "-fstack-check" } { "" } } */
#define SIZE 65 * 1024
#include "stack-check-alloca.h"
/* { dg-final { scan-assembler-times {stp*t*r*\.d\t\$r0,\$r\d{1,2},-8} 1 } } */
/* { dg-final { scan-assembler-times {stp*t*r*\.d\t\$r0,\$r3,1016} 1 } } */
/* Alloca is more than one guard-page. 2 probes expected. */

View file

@ -0,0 +1,13 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
/* { dg-require-effective-target alloca } */
/* { dg-skip-if "" { *-*-* } { "-fstack-check" } { "" } } */
#define SIZE 127 * 64 * 1024
#include "stack-check-alloca.h"
/* { dg-final { scan-assembler-times {stp*t*r*\.d\t\$r0,\$r\d{1,2},-8} 1 } } */
/* Large alloca of a constant amount which is a multiple of a guard-size.
Loop expected with top probe. */

View file

@ -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);
}

View file

@ -0,0 +1,12 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16 -funwind-tables" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
/* { dg-skip-if "" { *-*-* } { "-fstack-check" } { "" } } */
#define SIZE 128*1024
#include "stack-check-prologue.h"
/* { dg-final { scan-assembler-times {\.cfi_def_cfa_offset 131088} 1 } } */
/* { dg-final { scan-assembler-times {\.cfi_def_cfa_offset 0} 1 } } */
/* Checks that the CFA notes are correct for every sp adjustment. */

View file

@ -0,0 +1,12 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16 -funwind-tables" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
/* { dg-skip-if "" { *-*-* } { "-fstack-check" } { "" } } */
#define SIZE 1280*1024 + 512
#include "stack-check-prologue.h"
/* { dg-final { scan-assembler-times {\.cfi_def_cfa_offset 1311248} 1 } } */
/* { dg-final { scan-assembler-times {\.cfi_def_cfa_offset 0} 1 } } */
/* Checks that the CFA notes are correct for every sp adjustment. */

View file

@ -0,0 +1,11 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
/* { dg-skip-if "" { *-*-* } { "-fstack-check" } { "" } } */
#define SIZE 128
#include "stack-check-prologue.h"
/* { dg-final { scan-assembler-times {stp*t*r*\.d\t\$r0,\$r3,0} 0 } } */
/* SIZE is smaller than guard-size so no probe expected. */

View file

@ -0,0 +1,11 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
/* { dg-skip-if "" { *-*-* } { "-fstack-check" } { "" } } */
#define SIZE 63 * 1024
#include "stack-check-prologue.h"
/* { dg-final { scan-assembler-times {stp*t*r*.d\t\$r0,\$r3,0} 0 } } */
/* SIZE is smaller than guard-size so no probe expected. */

View file

@ -0,0 +1,11 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
/* { dg-skip-if "" { *-*-* } { "-fstack-check" } { "" } } */
#define SIZE 64 * 1024
#include "stack-check-prologue.h"
/* { dg-final { scan-assembler-times {stp*t*r*\.d\t\$r0,\$r3,0} 1 } } */
/* SIZE is equal to guard-size, 1 probe expected, boundary condition. */

View file

@ -0,0 +1,11 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
/* { dg-skip-if "" { *-*-* } { "-fstack-check" } { "" } } */
#define SIZE 65 * 1024
#include "stack-check-prologue.h"
/* { dg-final { scan-assembler-times {stp*t*r*\.d\t\$r0,\$r3,0} 1 } } */
/* SIZE is more than guard-size 1 probe expected. */

View file

@ -0,0 +1,12 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
/* { dg-skip-if "" { *-*-* } { "-fstack-check" } { "" } } */
#define SIZE 127 * 1024
#include "stack-check-prologue.h"
/* { dg-final { scan-assembler-times {stp*t*r*\.d\t\$r0,\$r3,0} 1 } } */
/* SIZE is more than 1x guard-size and remainder small than guard-size,
1 probe expected, unrolled, no loop. */

View file

@ -0,0 +1,11 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
/* { dg-skip-if "" { *-*-* } { "-fstack-check" } { "" } } */
#define SIZE 128 * 1024
#include "stack-check-prologue.h"
/* { dg-final { scan-assembler-times {stp*t*r*\.d\t\$r0,\$r3,0} 2 } } */
/* SIZE is more than 2x guard-size and no remainder, unrolled, no loop. */

View file

@ -0,0 +1,12 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16" } */
/* { dg-require-effective-target supports_stack_clash_protection } */
/* { dg-skip-if "" { *-*-* } { "-fstack-check" } { "" } } */
#define SIZE 6 * 64 * 1024
#include "stack-check-prologue.h"
/* { dg-final { scan-assembler-times {stp*t*r*.d\t\$r0,\$r3,0} 1 } } */
/* SIZE is more than 4x guard-size and no remainder, 1 probe expected in a loop
and no residual probe. */

View file

@ -0,0 +1,5 @@
int f_test (int x)
{
char arr[SIZE];
return arr[x];
}

View file

@ -11557,7 +11557,8 @@ proc check_effective_target_supports_stack_clash_protection { } {
if { [istarget x86_64-*-*] || [istarget i?86-*-*]
|| [istarget powerpc*-*-*] || [istarget rs6000*-*-*]
|| [istarget aarch64*-**] || [istarget s390*-*-*] } {
|| [istarget aarch64*-**] || [istarget s390*-*-*]
|| [istarget loongarch64*-**] } {
return 1
}
return 0
@ -11608,6 +11609,10 @@ proc check_effective_target_caller_implicit_probes { } {
return 1;
}
if { [istarget loongarch64*-*-*] } {
return 1;
}
return 0
}