aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog34
-rw-r--r--gcc/config/i386/linux.h3
-rw-r--r--gcc/config/i386/linux64.h3
-rw-r--r--gcc/doc/md.texi18
-rw-r--r--gcc/doc/tm.texi20
-rw-r--r--gcc/explow.c340
-rw-r--r--gcc/expr.h20
-rw-r--r--gcc/ira.c3
-rw-r--r--gcc/rtlanal.c5
-rw-r--r--gcc/system.h2
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gnat.dg/stack_check1.adb38
-rw-r--r--gcc/testsuite/gnat.dg/stack_check2.adb43
-rw-r--r--gcc/tree.c3
-rw-r--r--gcc/unwind-dw2.c8
15 files changed, 442 insertions, 103 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0da48a4..ce89099 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,37 @@
+2009-11-03 Eric Botcazou <ebotcazou@adacore.com>
+
+ PR target/10127
+ PR ada/20548
+ * expr.h (STACK_CHECK_PROBE_INTERVAL): Delete.
+ (STACK_CHECK_PROBE_INTERVAL_EXP): New macro.
+ (STACK_CHECK_MOVING_SP): Likewise.
+ * system.h (STACK_CHECK_PROBE_INTERVAL): Poison it.
+ * doc/tm.texi (Stack Checking): Delete STACK_CHECK_PROBE_INTERVAL.
+ Document STACK_CHECK_PROBE_INTERVAL_EXP and STACK_CHECK_MOVING_SP.
+ * doc/md.texi (Standard Pattern Names): Tweak entry of CHECK_STACK.
+ Document PROBE_STACK.
+ * explow.c (anti_adjust_stack_and_probe): New function.
+ (allocate_dynamic_stack_space): Do not directly allocate space if
+ STACK_CHECK_MOVING_SP, instead invoke above function.
+ (emit_stack_probe): Handle probe_stack insn.
+ (PROBE_INTERVAL): New macro.
+ (STACK_GROW_OPTAB): Likewise.
+ (STACK_GROW_OFF): Likewise.
+ (probe_stack_range): Use Pmode and memory_address consistently. Fix
+ loop condition in the small constant case. Rewrite in the general
+ case to be immune to wraparounds. Make sure the address of probes
+ is valid. Try to use [base + disp] addressing mode if possible.
+ * ira.c (setup_eliminable_regset): Set frame_pointer_needed if stack
+ checking is enabled and STACK_CHECK_MOVING_SP.
+ * rtlanal.c (may_trap_p_1) <MEM>: If stack checking is enabled,
+ return 1 for volatile references to the stack pointer.
+ * tree.c (build_common_builtin_nodes): Do not set ECF_NOTHROW on
+ __builtin_alloca if stack checking is enabled.
+ * unwind-dw2.c (uw_identify_context): Take into account whether the
+ context is that of a signal frame or not.
+ * config/i386/linux.h (STACK_CHECK_MOVING_SP): Define to 1.
+ * config/i386/linux64.h (STACK_CHECK_MOVING_SP): Likewise.
+
2009-11-03 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/41917
diff --git a/gcc/config/i386/linux.h b/gcc/config/i386/linux.h
index 5e2e013..5d8e5ad 100644
--- a/gcc/config/i386/linux.h
+++ b/gcc/config/i386/linux.h
@@ -207,6 +207,9 @@ along with GCC; see the file COPYING3. If not see
#define MD_UNWIND_SUPPORT "config/i386/linux-unwind.h"
+/* The stack pointer needs to be moved while checking the stack. */
+#define STACK_CHECK_MOVING_SP 1
+
/* This macro may be overridden in i386/k*bsd-gnu.h. */
#define REG_NAME(reg) reg
diff --git a/gcc/config/i386/linux64.h b/gcc/config/i386/linux64.h
index cfa3f49..d07547a 100644
--- a/gcc/config/i386/linux64.h
+++ b/gcc/config/i386/linux64.h
@@ -110,6 +110,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define MD_UNWIND_SUPPORT "config/i386/linux-unwind.h"
+/* The stack pointer needs to be moved while checking the stack. */
+#define STACK_CHECK_MOVING_SP 1
+
/* This macro may be overridden in i386/k*bsd-gnu.h. */
#define REG_NAME(reg) reg
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index dcfba92..2974dcf 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -5037,11 +5037,19 @@ operations in addition to updating the stack pointer.
@item @samp{check_stack}
If stack checking cannot be done on your system by probing the stack with
a load or store instruction (@pxref{Stack Checking}), define this pattern
-to perform the needed check and signaling an error if the stack
-has overflowed. The single operand is the location in the stack furthest
-from the current stack pointer that you need to validate. Normally,
-on machines where this pattern is needed, you would obtain the stack
-limit from a global or thread-specific variable or register.
+to perform the needed check and signal an error if the stack has overflowed.
+The single operand is the address in the stack furthest from the current
+stack pointer that you need to validate. Normally, on machines where this
+pattern is needed, you would obtain the stack limit from a global or
+thread-specific variable or register.
+
+@cindex @code{probe_stack} instruction pattern
+@item @samp{probe_stack}
+If stack checking can be done on your system by probing the stack but doing
+it with a load or store instruction is not optimal (@pxref{Stack Checking}),
+define this pattern to do the probing differently and signal an error if
+the stack has overflowed. The single operand is the memory location in the
+stack that needs to be probed.
@cindex @code{nonlocal_goto} instruction pattern
@item @samp{nonlocal_goto}
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 984bbd7..c69ef0c 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3556,11 +3556,12 @@ like to do static stack checking in some more efficient way than the generic
approach. The default value of this macro is zero.
@end defmac
-@defmac STACK_CHECK_PROBE_INTERVAL
-An integer representing the interval at which GCC must generate stack
-probe instructions. You will normally define this macro to be no larger
-than the size of the ``guard pages'' at the end of a stack area. The
-default value of 4096 is suitable for most systems.
+@defmac STACK_CHECK_PROBE_INTERVAL_EXP
+An integer specifying the interval at which GCC must generate stack probe
+instructions, defined as 2 raised to this integer. You will normally
+define this macro so that the interval be no larger than the size of
+the ``guard pages'' at the end of a stack area. The default value
+of 12 (4096-byte interval) is suitable for most systems.
@end defmac
@defmac STACK_CHECK_PROBE_LOAD
@@ -3569,6 +3570,15 @@ as a load instruction and zero if GCC should use a store instruction.
The default is zero, which is the most efficient choice on most systems.
@end defmac
+@defmac STACK_CHECK_MOVING_SP
+An integer which is nonzero if GCC should move the stack pointer page by page
+when doing probes. This can be necessary on systems where the stack pointer
+contains the bottom address of the memory area accessible to the executing
+thread at any point in time. In this situation an alternate signal stack
+is required in order to be able to recover from a stack overflow. The
+default value of this macro is zero.
+@end defmac
+
@defmac STACK_CHECK_PROTECT
The number of bytes of stack needed to recover from a stack overflow,
for languages where such a recovery is supported. The default value of
diff --git a/gcc/explow.c b/gcc/explow.c
index c38682d..0bbbc00 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see
static rtx break_out_memory_refs (rtx);
static void emit_stack_probe (rtx);
+static void anti_adjust_stack_and_probe (rtx);
/* Truncate and perhaps sign-extend C as appropriate for MODE. */
@@ -1233,9 +1234,11 @@ allocate_dynamic_stack_space (rtx size, rtx target, int known_align)
gcc_assert (!(stack_pointer_delta
% (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)));
- /* If needed, check that we have the required amount of stack.
- Take into account what has already been checked. */
- if (flag_stack_check == GENERIC_STACK_CHECK)
+ /* If needed, check that we have the required amount of stack. Take into
+ account what has already been checked. */
+ if (STACK_CHECK_MOVING_SP)
+ ;
+ else if (flag_stack_check == GENERIC_STACK_CHECK)
probe_stack_range (STACK_OLD_CHECK_PROTECT + STACK_CHECK_MAX_FRAME_SIZE,
size);
else if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
@@ -1304,7 +1307,10 @@ allocate_dynamic_stack_space (rtx size, rtx target, int known_align)
emit_label (space_available);
}
- anti_adjust_stack (size);
+ if (flag_stack_check && STACK_CHECK_MOVING_SP)
+ anti_adjust_stack_and_probe (size);
+ else
+ anti_adjust_stack (size);
#ifdef STACK_GROWS_DOWNWARD
emit_move_insn (target, virtual_stack_dynamic_rtx);
@@ -1355,6 +1361,12 @@ emit_stack_probe (rtx address)
MEM_VOLATILE_P (memref) = 1;
+ /* See if we have an insn to probe the stack. */
+#ifdef HAVE_probe_stack
+ if (HAVE_probe_stack)
+ emit_insn (gen_probe_stack (memref));
+ else
+#endif
if (STACK_CHECK_PROBE_LOAD)
emit_move_insn (gen_reg_rtx (word_mode), memref);
else
@@ -1362,15 +1374,20 @@ emit_stack_probe (rtx address)
}
/* Probe a range of stack addresses from FIRST to FIRST+SIZE, inclusive.
- FIRST is a constant and size is a Pmode RTX. These are offsets from the
- current stack pointer. STACK_GROWS_DOWNWARD says whether to add or
- subtract from the stack. If SIZE is constant, this is done
- with a fixed number of probes. Otherwise, we must make a loop. */
+ FIRST is a constant and size is a Pmode RTX. These are offsets from
+ the current stack pointer. STACK_GROWS_DOWNWARD says whether to add
+ or subtract them from the stack pointer. */
+
+#define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP)
#ifdef STACK_GROWS_DOWNWARD
#define STACK_GROW_OP MINUS
+#define STACK_GROW_OPTAB sub_optab
+#define STACK_GROW_OFF(off) -(off)
#else
#define STACK_GROW_OP PLUS
+#define STACK_GROW_OPTAB add_optab
+#define STACK_GROW_OFF(off) (off)
#endif
void
@@ -1380,113 +1397,272 @@ probe_stack_range (HOST_WIDE_INT first, rtx size)
if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)
size = convert_to_mode (Pmode, size, 1);
- /* Next see if the front end has set up a function for us to call to
- check the stack. */
- if (stack_check_libfunc != 0)
+ /* Next see if we have a function to check the stack. */
+ if (stack_check_libfunc)
{
- rtx addr = memory_address (QImode,
+ rtx addr = memory_address (Pmode,
gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
stack_pointer_rtx,
plus_constant (size, first)));
-
- addr = convert_memory_address (ptr_mode, addr);
- emit_library_call (stack_check_libfunc, LCT_NORMAL, VOIDmode, 1, addr,
- ptr_mode);
+ emit_library_call (stack_check_libfunc, LCT_NORMAL, VOIDmode, 1, addr);
}
- /* Next see if we have an insn to check the stack. Use it if so. */
+ /* Next see if we have an insn to check the stack. */
#ifdef HAVE_check_stack
else if (HAVE_check_stack)
{
- insn_operand_predicate_fn pred;
- rtx last_addr
- = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
- stack_pointer_rtx,
- plus_constant (size, first)),
- NULL_RTX);
-
- pred = insn_data[(int) CODE_FOR_check_stack].operand[0].predicate;
- if (pred && ! ((*pred) (last_addr, Pmode)))
- last_addr = copy_to_mode_reg (Pmode, last_addr);
+ rtx addr = memory_address (Pmode,
+ gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
+ stack_pointer_rtx,
+ plus_constant (size, first)));
+ insn_operand_predicate_fn pred
+ = insn_data[(int) CODE_FOR_check_stack].operand[0].predicate;
+ if (pred && !((*pred) (addr, Pmode)))
+ addr = copy_to_mode_reg (Pmode, addr);
- emit_insn (gen_check_stack (last_addr));
+ emit_insn (gen_check_stack (addr));
}
#endif
- /* If we have to generate explicit probes, see if we have a constant
- small number of them to generate. If so, that's the easy case. */
- else if (CONST_INT_P (size)
- && INTVAL (size) < 10 * STACK_CHECK_PROBE_INTERVAL)
+ /* Otherwise we have to generate explicit probes. If we have a constant
+ small number of them to generate, that's the easy case. */
+ else if (CONST_INT_P (size) && INTVAL (size) < 7 * PROBE_INTERVAL)
{
- HOST_WIDE_INT offset;
-
- /* Start probing at FIRST + N * STACK_CHECK_PROBE_INTERVAL
- for values of N from 1 until it exceeds LAST. If only one
- probe is needed, this will not generate any code. Then probe
- at LAST. */
- for (offset = first + STACK_CHECK_PROBE_INTERVAL;
- offset < INTVAL (size);
- offset = offset + STACK_CHECK_PROBE_INTERVAL)
- emit_stack_probe (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
- stack_pointer_rtx,
- GEN_INT (offset)));
-
- emit_stack_probe (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
- stack_pointer_rtx,
- plus_constant (size, first)));
+ HOST_WIDE_INT isize = INTVAL (size), i;
+ rtx addr;
+
+ /* 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 < isize; i += PROBE_INTERVAL)
+ {
+ addr = memory_address (Pmode,
+ plus_constant (stack_pointer_rtx,
+ STACK_GROW_OFF (first + i)));
+ emit_stack_probe (addr);
+ }
+
+ addr = memory_address (Pmode,
+ plus_constant (stack_pointer_rtx,
+ STACK_GROW_OFF (first + isize)));
+ emit_stack_probe (addr);
}
- /* In the variable case, do the same as above, but in a loop. We emit loop
- notes so that loop optimization can be done. */
+ /* In the variable case, 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
{
- rtx test_addr
- = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
- stack_pointer_rtx,
- GEN_INT (first + STACK_CHECK_PROBE_INTERVAL)),
- NULL_RTX);
- rtx last_addr
- = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
- stack_pointer_rtx,
- plus_constant (size, first)),
- NULL_RTX);
- rtx incr = GEN_INT (STACK_CHECK_PROBE_INTERVAL);
+ rtx rounded_size, rounded_size_op, test_addr, last_addr, temp;
rtx loop_lab = gen_label_rtx ();
- rtx test_lab = gen_label_rtx ();
rtx end_lab = gen_label_rtx ();
- rtx temp;
- if (!REG_P (test_addr)
- || REGNO (test_addr) < FIRST_PSEUDO_REGISTER)
- test_addr = force_reg (Pmode, test_addr);
- emit_jump (test_lab);
+ /* Step 1: round SIZE to the previous multiple of the interval. */
+
+ /* ROUNDED_SIZE = SIZE & -PROBE_INTERVAL */
+ rounded_size
+ = simplify_gen_binary (AND, Pmode, size, GEN_INT (-PROBE_INTERVAL));
+ rounded_size_op = force_operand (rounded_size, NULL_RTX);
+
+
+ /* Step 2: compute initial and final value of the loop counter. */
+
+ /* TEST_ADDR = SP + FIRST. */
+ test_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
+ stack_pointer_rtx,
+ GEN_INT (first)), NULL_RTX);
+
+ /* LAST_ADDR = SP + FIRST + ROUNDED_SIZE. */
+ last_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
+ test_addr,
+ rounded_size_op), NULL_RTX);
+
+
+ /* Step 3: the loop
+
+ while (TEST_ADDR != LAST_ADDR)
+ {
+ TEST_ADDR = TEST_ADDR + PROBE_INTERVAL
+ probe at TEST_ADDR
+ }
+
+ probes at FIRST + N * PROBE_INTERVAL for values of N from 1
+ until it is equal to ROUNDED_SIZE. */
emit_label (loop_lab);
- emit_stack_probe (test_addr);
-#ifdef STACK_GROWS_DOWNWARD
-#define CMP_OPCODE GTU
- temp = expand_binop (Pmode, sub_optab, test_addr, incr, test_addr,
- 1, OPTAB_WIDEN);
-#else
-#define CMP_OPCODE LTU
- temp = expand_binop (Pmode, add_optab, test_addr, incr, test_addr,
+ /* Jump to END_LAB if TEST_ADDR == LAST_ADDR. */
+ emit_cmp_and_jump_insns (test_addr, last_addr, EQ, NULL_RTX, Pmode, 1,
+ end_lab);
+
+ /* TEST_ADDR = TEST_ADDR + PROBE_INTERVAL. */
+ temp = expand_binop (Pmode, STACK_GROW_OPTAB, test_addr,
+ GEN_INT (PROBE_INTERVAL), test_addr,
1, OPTAB_WIDEN);
-#endif
gcc_assert (temp == test_addr);
- emit_label (test_lab);
- emit_cmp_and_jump_insns (test_addr, last_addr, CMP_OPCODE,
- NULL_RTX, Pmode, 1, loop_lab);
- emit_jump (end_lab);
+ /* Probe at TEST_ADDR. */
+ emit_stack_probe (test_addr);
+
+ emit_jump (loop_lab);
+
emit_label (end_lab);
- emit_stack_probe (last_addr);
+
+ /* Step 4: probe at FIRST + SIZE if we cannot assert at compile-time
+ that SIZE is equal to ROUNDED_SIZE. */
+
+ /* TEMP = SIZE - ROUNDED_SIZE. */
+ temp = simplify_gen_binary (MINUS, Pmode, size, rounded_size);
+ if (temp != const0_rtx)
+ {
+ rtx addr;
+
+ if (GET_CODE (temp) == CONST_INT)
+ {
+ /* Use [base + disp} addressing mode if supported. */
+ HOST_WIDE_INT offset = INTVAL (temp);
+ addr = memory_address (Pmode,
+ plus_constant (last_addr,
+ STACK_GROW_OFF (offset)));
+ }
+ else
+ {
+ /* Manual CSE if the difference is not known at compile-time. */
+ temp = gen_rtx_MINUS (Pmode, size, rounded_size_op);
+ addr = memory_address (Pmode,
+ gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
+ last_addr, temp));
+ }
+
+ emit_stack_probe (addr);
+ }
}
}
-
+
+/* Adjust the stack by SIZE bytes while probing it. Note that we skip the
+ probe for the first interval + a small dope of 4 words and instead probe
+ that many bytes past the specified size to maintain a protection area. */
+
+static void
+anti_adjust_stack_and_probe (rtx size)
+{
+ const int dope = 4 * UNITS_PER_WORD;
+
+ /* First ensure SIZE is Pmode. */
+ if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)
+ size = convert_to_mode (Pmode, size, 1);
+
+ /* If we have a constant small number of probes to generate, that's the
+ easy case. */
+ if (GET_CODE (size) == CONST_INT && INTVAL (size) < 7 * PROBE_INTERVAL)
+ {
+ HOST_WIDE_INT isize = INTVAL (size), i;
+ bool first_probe = true;
+
+ /* Adjust SP and probe to PROBE_INTERVAL + 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 adjust and probe
+ to PROBE_INTERVAL + SIZE. */
+ for (i = PROBE_INTERVAL; i < isize; i += PROBE_INTERVAL)
+ {
+ if (first_probe)
+ {
+ anti_adjust_stack (GEN_INT (2 * PROBE_INTERVAL + dope));
+ first_probe = false;
+ }
+ else
+ anti_adjust_stack (GEN_INT (PROBE_INTERVAL));
+ emit_stack_probe (stack_pointer_rtx);
+ }
+
+ if (first_probe)
+ anti_adjust_stack (plus_constant (size, PROBE_INTERVAL + dope));
+ else
+ anti_adjust_stack (plus_constant (size, PROBE_INTERVAL - i));
+ emit_stack_probe (stack_pointer_rtx);
+ }
+
+ /* In the variable case, 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
+ {
+ rtx rounded_size, rounded_size_op, last_addr, temp;
+ rtx loop_lab = gen_label_rtx ();
+ rtx end_lab = gen_label_rtx ();
+
+
+ /* Step 1: round SIZE to the previous multiple of the interval. */
+
+ /* ROUNDED_SIZE = SIZE & -PROBE_INTERVAL */
+ rounded_size
+ = simplify_gen_binary (AND, Pmode, size, GEN_INT (-PROBE_INTERVAL));
+ rounded_size_op = force_operand (rounded_size, NULL_RTX);
+
+
+ /* Step 2: compute initial and final value of the loop counter. */
+
+ /* SP = SP_0 + PROBE_INTERVAL. */
+ anti_adjust_stack (GEN_INT (PROBE_INTERVAL + dope));
+
+ /* LAST_ADDR = SP_0 + PROBE_INTERVAL + ROUNDED_SIZE. */
+ last_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
+ stack_pointer_rtx,
+ rounded_size_op), NULL_RTX);
+
+
+ /* Step 3: the loop
+
+ while (SP != LAST_ADDR)
+ {
+ SP = SP + PROBE_INTERVAL
+ probe at SP
+ }
+
+ adjusts SP and probes to PROBE_INTERVAL + N * PROBE_INTERVAL for
+ values of N from 1 until it is equal to ROUNDED_SIZE. */
+
+ emit_label (loop_lab);
+
+ /* Jump to END_LAB if SP == LAST_ADDR. */
+ emit_cmp_and_jump_insns (stack_pointer_rtx, last_addr, EQ, NULL_RTX,
+ Pmode, 1, end_lab);
+
+ /* SP = SP + PROBE_INTERVAL and probe at SP. */
+ anti_adjust_stack (GEN_INT (PROBE_INTERVAL));
+ emit_stack_probe (stack_pointer_rtx);
+
+ emit_jump (loop_lab);
+
+ emit_label (end_lab);
+
+
+ /* Step 4: adjust SP and probe to PROBE_INTERVAL + SIZE if we cannot
+ assert at compile-time that SIZE is equal to ROUNDED_SIZE. */
+
+ /* TEMP = SIZE - ROUNDED_SIZE. */
+ temp = simplify_gen_binary (MINUS, Pmode, size, rounded_size);
+ if (temp != const0_rtx)
+ {
+ /* Manual CSE if the difference is not known at compile-time. */
+ if (GET_CODE (temp) != CONST_INT)
+ temp = gen_rtx_MINUS (Pmode, size, rounded_size_op);
+ anti_adjust_stack (temp);
+ emit_stack_probe (stack_pointer_rtx);
+ }
+ }
+
+ /* Adjust back to account for the additional first interval. */
+ adjust_stack (GEN_INT (PROBE_INTERVAL + dope));
+}
+
/* Return an rtx representing the register or memory location
in which a scalar value of data type VALTYPE
was returned by a function call to function FUNC.
diff --git a/gcc/expr.h b/gcc/expr.h
index 0eceb6e..e847796 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -218,9 +218,9 @@ do { \
#define STACK_CHECK_STATIC_BUILTIN 0
#endif
-/* The default interval is one page. */
-#ifndef STACK_CHECK_PROBE_INTERVAL
-#define STACK_CHECK_PROBE_INTERVAL 4096
+/* The default interval is one page (4096 bytes). */
+#ifndef STACK_CHECK_PROBE_INTERVAL_EXP
+#define STACK_CHECK_PROBE_INTERVAL_EXP 12
#endif
/* The default is to do a store into the stack. */
@@ -228,6 +228,11 @@ do { \
#define STACK_CHECK_PROBE_LOAD 0
#endif
+/* The default is not to move the stack pointer. */
+#ifndef STACK_CHECK_MOVING_SP
+#define STACK_CHECK_MOVING_SP 0
+#endif
+
/* This is a kludge to try to capture the discrepancy between the old
mechanism (generic stack checking) and the new mechanism (static
builtin stack checking). STACK_CHECK_PROTECT needs to be bumped
@@ -252,7 +257,7 @@ do { \
one probe per function. */
#ifndef STACK_CHECK_MAX_FRAME_SIZE
#define STACK_CHECK_MAX_FRAME_SIZE \
- (STACK_CHECK_PROBE_INTERVAL - UNITS_PER_WORD)
+ ((1 << STACK_CHECK_PROBE_INTERVAL_EXP) - UNITS_PER_WORD)
#endif
/* This is arbitrary, but should be large enough everywhere. */
@@ -779,10 +784,9 @@ extern void update_nonlocal_goto_save_area (void);
extern rtx allocate_dynamic_stack_space (rtx, rtx, int);
/* Probe a range of stack addresses from FIRST to FIRST+SIZE, inclusive.
- FIRST is a constant and size is a Pmode RTX. These are offsets from the
- current stack pointer. STACK_GROWS_DOWNWARD says whether to add or
- subtract from the stack. If SIZE is constant, this is done
- with a fixed number of probes. Otherwise, we must make a loop. */
+ FIRST is a constant and size is a Pmode RTX. These are offsets from
+ the current stack pointer. STACK_GROWS_DOWNWARD says whether to add
+ or subtract them from the stack pointer. */
extern void probe_stack_range (HOST_WIDE_INT, rtx);
/* Return an rtx that refers to the value returned by a library call
diff --git a/gcc/ira.c b/gcc/ira.c
index 962d099..a3e899f 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -1442,6 +1442,9 @@ ira_setup_eliminable_regset (void)
int need_fp
= (! flag_omit_frame_pointer
|| (cfun->calls_alloca && EXIT_IGNORE_STACK)
+ /* We need the frame pointer to catch stack overflow exceptions
+ if the stack pointer is moving. */
+ || (flag_stack_check && STACK_CHECK_MOVING_SP)
|| crtl->accesses_prior_frames
|| crtl->stack_realign_needed
|| targetm.frame_pointer_required ());
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 120d37a..ab88f23 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -2252,6 +2252,11 @@ may_trap_p_1 (const_rtx x, unsigned flags)
/* Memory ref can trap unless it's a static var or a stack slot. */
case MEM:
+ /* Recognize specific pattern of stack checking probes. */
+ if (flag_stack_check
+ && MEM_VOLATILE_P (x)
+ && XEXP (x, 0) == stack_pointer_rtx)
+ return 1;
if (/* MEM_NOTRAP_P only relates to the actual position of the memory
reference; moving it out of context such as when moving code
when optimizing, might cause its address to become invalid. */
diff --git a/gcc/system.h b/gcc/system.h
index 0c846cf..03910d0 100644
--- a/gcc/system.h
+++ b/gcc/system.h
@@ -761,7 +761,7 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN;
TARGET_ASM_EXCEPTION_SECTION TARGET_ASM_EH_FRAME_SECTION \
SMALL_ARG_MAX ASM_OUTPUT_SHARED_BSS ASM_OUTPUT_SHARED_COMMON \
ASM_OUTPUT_SHARED_LOCAL UNALIGNED_WORD_ASM_OP \
- ASM_MAKE_LABEL_LINKONCE
+ ASM_MAKE_LABEL_LINKONCE STACK_CHECK_PROBE_INTERVAL
/* Hooks that are no longer used. */
#pragma GCC poison LANG_HOOKS_FUNCTION_MARK LANG_HOOKS_FUNCTION_FREE \
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 220a4c3..4a499e2 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2009-11-03 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gnat.dg/stack_check.adb1: New test.
+ * gnat.dg/stack_check.adb2: Likewise.
+
2009-11-03 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/41917
diff --git a/gcc/testsuite/gnat.dg/stack_check1.adb b/gcc/testsuite/gnat.dg/stack_check1.adb
new file mode 100644
index 0000000..51ee1a6
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/stack_check1.adb
@@ -0,0 +1,38 @@
+-- { dg-do run }
+-- { dg-options "-fstack-check" }
+
+-- This test requires architecture- and OS-specific support code for unwinding
+-- through signal frames (typically located in *-unwind.h) to pass. Feel free
+-- to disable it if this code hasn't been implemented yet.
+
+procedure Stack_Check1 is
+
+ type A is Array (1..2048) of Integer;
+
+ procedure Consume_Stack (N : Integer) is
+ My_A : A; -- 8 KB static
+ begin
+ My_A (1) := 0;
+ if N <= 0 then
+ return;
+ end if;
+ Consume_Stack (N-1);
+ end;
+
+ Task T;
+
+ Task body T is
+ begin
+ begin
+ Consume_Stack (Integer'Last);
+ raise Program_Error;
+ exception
+ when Storage_Error => null;
+ end;
+
+ Consume_Stack (128);
+ end;
+
+begin
+ null;
+end;
diff --git a/gcc/testsuite/gnat.dg/stack_check2.adb b/gcc/testsuite/gnat.dg/stack_check2.adb
new file mode 100644
index 0000000..4a3008b
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/stack_check2.adb
@@ -0,0 +1,43 @@
+-- { dg-do run }
+-- { dg-options "-fstack-check" }
+
+-- This test requires architecture- and OS-specific support code for unwinding
+-- through signal frames (typically located in *-unwind.h) to pass. Feel free
+-- to disable it if this code hasn't been implemented yet.
+
+procedure Stack_Check2 is
+
+ function UB return Integer is
+ begin
+ return 2048;
+ end;
+
+ type A is Array (Positive range <>) of Integer;
+
+ procedure Consume_Stack (N : Integer) is
+ My_A : A (1..UB); -- 8 KB dynamic
+ begin
+ My_A (1) := 0;
+ if N <= 0 then
+ return;
+ end if;
+ Consume_Stack (N-1);
+ end;
+
+ Task T;
+
+ Task body T is
+ begin
+ begin
+ Consume_Stack (Integer'Last);
+ raise Program_Error;
+ exception
+ when Storage_Error => null;
+ end;
+
+ Consume_Stack (128);
+ end;
+
+begin
+ null;
+end;
diff --git a/gcc/tree.c b/gcc/tree.c
index 6079725..f3970dd 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -9009,7 +9009,8 @@ build_common_builtin_nodes (void)
tmp = tree_cons (NULL_TREE, size_type_node, void_list_node);
ftype = build_function_type (ptr_type_node, tmp);
local_define_builtin ("__builtin_alloca", ftype, BUILT_IN_ALLOCA,
- "alloca", ECF_NOTHROW | ECF_MALLOC);
+ "alloca",
+ ECF_MALLOC | (flag_stack_check ? 0 : ECF_NOTHROW));
}
tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
diff --git a/gcc/unwind-dw2.c b/gcc/unwind-dw2.c
index 82958b0..2208f17 100644
--- a/gcc/unwind-dw2.c
+++ b/gcc/unwind-dw2.c
@@ -1559,7 +1559,13 @@ uw_install_context_1 (struct _Unwind_Context *current,
static inline _Unwind_Ptr
uw_identify_context (struct _Unwind_Context *context)
{
- return _Unwind_GetCFA (context);
+ /* The CFA is not sufficient to disambiguate the context of a function
+ interrupted by a signal before establishing its frame and the context
+ of the signal itself. */
+ if (STACK_GROWS_DOWNWARD)
+ return _Unwind_GetCFA (context) - _Unwind_IsSignalFrame (context);
+ else
+ return _Unwind_GetCFA (context) + _Unwind_IsSignalFrame (context);
}