@@ -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
@@ -63,6 +63,7 @@ along with GCC; see the file COPYING3. If not see
#include "context.h"
#include "builtins.h"
#include "rtl-iter.h"
+#include "opts.h"
/* This file should be included last. */
#include "target-def.h"
@@ -257,6 +258,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. */
@@ -1069,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);
@@ -1106,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)));
+ if (flag_stack_clash_protection)
+ interval = STACK_CLASH_PROTECTION_GUARD_SIZE;
+ else
+ interval = PROBE_INTERVAL;
- emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
- -(first + size)));
- }
+ rtx r12 = LARCH_PROLOGUE_TEMP2 (Pmode);
+ rtx r14 = LARCH_PROLOGUE_TEMP3 (Pmode);
- /* 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. */
- else
- {
- HOST_WIDE_INT rounded_size;
- rtx r13 = LARCH_PROLOGUE_TEMP (Pmode);
- 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);
+ /* 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. */
- /* Step 1: round SIZE to the previous multiple of the interval. */
+ rounded_size = ROUND_DOWN (size, interval);
- rounded_size = ROUND_DOWN (size, PROBE_INTERVAL);
+ /* Step 2: compute initial and final value of the loop counter. */
- /* TEST_ADDR = SP + FIRST */
- if (first != 0)
- {
- emit_move_insn (r14, GEN_INT (first));
- emit_insn (gen_rtx_SET (r13, gen_rtx_MINUS (Pmode,
- stack_pointer_rtx,
- r14)));
- }
- else
- emit_move_insn (r13, stack_pointer_rtx);
+ 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)
+ {
+ /* Step 3: the loop
+
+ do
+ {
+ TEST_ADDR = TEST_ADDR + PROBE_INTERVAL
+ probe at TEST_ADDR
+ }
+ while (TEST_ADDR != LAST_ADDR)
- /* Step 2: compute initial and final value of the loop counter. */
+ probes at FIRST + N * PROBE_INTERVAL for values of N from 1
+ until it is equal to ROUNDED_SIZE. */
- emit_move_insn (r14, GEN_INT (PROBE_INTERVAL));
- /* LAST_ADDR = SP + FIRST + ROUNDED_SIZE. */
- if (rounded_size == 0)
- emit_move_insn (r12, r13);
+ if (rounded_size <= STACK_CLASH_MAX_UNROLL_PAGES * interval)
+ {
+ 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 (r12, GEN_INT (rounded_size));
- emit_insn (gen_rtx_SET (r12, gen_rtx_MINUS (Pmode, r13, r12)));
- /* Step 3: the loop
-
- 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));
+ emit_insn (gen_rtx_SET (r12,
+ gen_rtx_MINUS (Pmode,
+ stack_pointer_rtx,
+ r12)));
+
+ 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)
+ /* 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)
{
- 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_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 ());
}
@@ -1223,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);
@@ -1249,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)
{
@@ -1283,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)
{
@@ -1294,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))
@@ -1305,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)));
@@ -6127,6 +6167,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.
@@ -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. */
new file mode 100644
@@ -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. */
new file mode 100644
@@ -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. */
new file mode 100644
@@ -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. */
new file mode 100644
@@ -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. */
new file mode 100644
@@ -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. */
new file mode 100644
@@ -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. */
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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. */
new file mode 100644
@@ -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. */
new file mode 100644
@@ -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. */
new file mode 100644
@@ -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. */
new file mode 100644
@@ -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. */
new file mode 100644
@@ -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. */
new file mode 100644
@@ -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. */
new file mode 100644
@@ -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. */
new file mode 100644
@@ -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. */
new file mode 100644
@@ -0,0 +1,5 @@
+int f_test (int x)
+{
+ char arr[SIZE];
+ return arr[x];
+}
@@ -11377,7 +11377,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
@@ -11428,6 +11429,10 @@ proc check_effective_target_caller_implicit_probes { } {
return 1;
}
+ if { [istarget loongarch64*-*-*] } {
+ return 1;
+ }
+
return 0
}