diff --git a/gcc/config/loongarch/linux.h b/gcc/config/loongarch/linux.h index 110d0fab93d..00039ac1871 100644 --- a/gcc/config/loongarch/linux.h +++ b/gcc/config/loongarch/linux.h @@ -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 diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index 9e0d6c7c3ea..c6b03fcf2f9 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -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. diff --git a/gcc/config/loongarch/loongarch.h b/gcc/config/loongarch/loongarch.h index f4a9c329fef..a402d3ba35a 100644 --- a/gcc/config/loongarch/loongarch.h +++ b/gcc/config/loongarch/loongarch.h @@ -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. */ diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-1.c b/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-1.c new file mode 100644 index 00000000000..6ee589c4b3d --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-1.c @@ -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. */ diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-2.c b/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-2.c new file mode 100644 index 00000000000..8deaa587305 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-2.c @@ -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. */ diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-3.c b/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-3.c new file mode 100644 index 00000000000..e326ba9a092 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-3.c @@ -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. */ diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-4.c b/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-4.c new file mode 100644 index 00000000000..b9f7572dedc --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-4.c @@ -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. */ diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-5.c b/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-5.c new file mode 100644 index 00000000000..0ff6e493fec --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-5.c @@ -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. */ diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-6.c b/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-6.c new file mode 100644 index 00000000000..c5cf74fcb4f --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/stack-check-alloca-6.c @@ -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. */ diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-alloca.h b/gcc/testsuite/gcc.target/loongarch/stack-check-alloca.h new file mode 100644 index 00000000000..8c75f6c0f70 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/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); +} diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-cfa-1.c b/gcc/testsuite/gcc.target/loongarch/stack-check-cfa-1.c new file mode 100644 index 00000000000..f0c6877fc25 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/stack-check-cfa-1.c @@ -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. */ diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-cfa-2.c b/gcc/testsuite/gcc.target/loongarch/stack-check-cfa-2.c new file mode 100644 index 00000000000..c6e07bc561a --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/stack-check-cfa-2.c @@ -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. */ diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-1.c b/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-1.c new file mode 100644 index 00000000000..351bc1f61fd --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-1.c @@ -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. */ diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-2.c b/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-2.c new file mode 100644 index 00000000000..6bba659a36d --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-2.c @@ -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. */ diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-3.c b/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-3.c new file mode 100644 index 00000000000..164956c3747 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-3.c @@ -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. */ diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-4.c b/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-4.c new file mode 100644 index 00000000000..f53da6b0de9 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-4.c @@ -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. */ diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-5.c b/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-5.c new file mode 100644 index 00000000000..c092317ea94 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-5.c @@ -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. */ diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-6.c b/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-6.c new file mode 100644 index 00000000000..70a2f53f6d7 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-6.c @@ -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. */ diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-7.c b/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-7.c new file mode 100644 index 00000000000..e2df89acc77 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/stack-check-prologue-7.c @@ -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. */ diff --git a/gcc/testsuite/gcc.target/loongarch/stack-check-prologue.h b/gcc/testsuite/gcc.target/loongarch/stack-check-prologue.h new file mode 100644 index 00000000000..b7e06aedb81 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/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 364e0ed8cf5..2a058c67c53 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -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 }