summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog29
-rw-r--r--gcc/config/ia64/hpux.h7
-rw-r--r--gcc/config/ia64/ia64-protos.h1
-rw-r--r--gcc/config/ia64/ia64.c284
-rw-r--r--gcc/config/ia64/ia64.md22
-rw-r--r--gcc/config/ia64/linux.h3
-rw-r--r--gcc/doc/md.texi7
-rw-r--r--gcc/explow.c21
8 files changed, 333 insertions, 41 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8df98d7ea2f..856c6756ea9 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,32 @@
+2012-05-10 Eric Botcazou <ebotcazou@adacore.com>
+ Tristan Gingold <gingold@adacore.com>
+
+ * doc/md.texi (Standard Names): Document probe_stack_address.
+ * explow.c (emit_stack_probe): Handle probe_stack_address.
+ * config/ia64/ia64.md (UNSPECV_PROBE_STACK_ADDRESS): New constant.
+ (UNSPECV_PROBE_STACK_RANGE): Likewise.
+ (probe_stack_address): New insn.
+ (probe_stack_range): Likewise.
+ * config/ia64/ia64.c: Include common/common-target.h.
+ (ia64_compute_frame_size): Mark r2 and r3 as used if static stack
+ checking is enabled.
+ (ia64_emit_probe_stack_range): New function.
+ (output_probe_stack_range): Likewise.
+ (ia64_expand_prologue): Invoke ia64_emit_probe_stack_range if static
+ builtin stack checking is enabled.
+ (rtx_needs_barrier) <UNSPEC_VOLATILE>: Handle UNSPECV_PROBE_STACK_RANGE
+ and UNSPECV_PROBE_STACK_ADDRESS.
+ (unknown_for_bundling_p): New predicate.
+ (group_barrier_needed): Use important_for_bundling_p.
+ (ia64_dfa_new_cycle): Use unknown_for_bundling_p.
+ (issue_nops_and_insn): Likewise.
+ (bundling): Likewise.
+ (final_emit_insn_group_barriers): Likewise.
+ * config/ia64/ia64-protos.h (output_probe_stack_range): Declare.
+ * config/ia64/hpux.h (STACK_CHECK_STATIC_BUILTIN): Define.
+ (STACK_CHECK_PROTECT): Likewise.
+ * config/ia64/linux.h (STACK_CHECK_STATIC_BUILTIN): Likewise.
+
2012-05-10 Jan Hubicka <jh@suse.cz>
* ipa-inline.c (update_all_callee_keys): Remove.
diff --git a/gcc/config/ia64/hpux.h b/gcc/config/ia64/hpux.h
index edbf339fbf1..ad106b4dee2 100644
--- a/gcc/config/ia64/hpux.h
+++ b/gcc/config/ia64/hpux.h
@@ -228,3 +228,10 @@ do { \
#define TARGET_ASM_FUNCTION_SECTION ia64_hpux_function_section
#define TARGET_POSIX_IO
+
+/* Define this to be nonzero if static stack checking is supported. */
+#define STACK_CHECK_STATIC_BUILTIN 1
+
+/* Minimum amount of stack required to recover from an anticipated stack
+ overflow detection. */
+#define STACK_CHECK_PROTECT (24 * 1024)
diff --git a/gcc/config/ia64/ia64-protos.h b/gcc/config/ia64/ia64-protos.h
index f7bd4c60240..458b1201c94 100644
--- a/gcc/config/ia64/ia64-protos.h
+++ b/gcc/config/ia64/ia64-protos.h
@@ -61,6 +61,7 @@ extern int ia64_hard_regno_rename_ok (int, int);
extern enum reg_class ia64_secondary_reload_class (enum reg_class,
enum machine_mode, rtx);
extern const char *get_bundle_name (int);
+extern const char *output_probe_stack_range (rtx, rtx);
extern void ia64_expand_vec_perm_even_odd (rtx, rtx, rtx, int);
extern bool ia64_expand_vec_perm_const (rtx op[4]);
diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
index 89a65ff82a2..ccffa37fd87 100644
--- a/gcc/config/ia64/ia64.c
+++ b/gcc/config/ia64/ia64.c
@@ -47,6 +47,7 @@ along with GCC; see the file COPYING3. If not see
#include "timevar.h"
#include "target.h"
#include "target-def.h"
+#include "common/common-target.h"
#include "tm_p.h"
#include "hashtab.h"
#include "langhooks.h"
@@ -272,6 +273,7 @@ static int get_template (state_t, int);
static rtx get_next_important_insn (rtx, rtx);
static bool important_for_bundling_p (rtx);
+static bool unknown_for_bundling_p (rtx);
static void bundling (FILE *, int, rtx, rtx);
static void ia64_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
@@ -2672,6 +2674,10 @@ ia64_compute_frame_size (HOST_WIDE_INT size)
if (cfun->machine->ia64_eh_epilogue_bsp)
mark_reg_gr_used_mask (cfun->machine->ia64_eh_epilogue_bsp, NULL);
+ /* Static stack checking uses r2 and r3. */
+ if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
+ current_frame_info.gr_used_mask |= 0xc;
+
/* Find the size of the register stack frame. We have only 80 local
registers, because we reserve 8 for the inputs and 8 for the
outputs. */
@@ -3230,6 +3236,213 @@ gen_fr_restore_x (rtx dest, rtx src, rtx offset ATTRIBUTE_UNUSED)
return gen_fr_restore (dest, src);
}
+#define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP)
+
+/* See Table 6.2 of the IA-64 Software Developer Manual, Volume 2. */
+#define BACKING_STORE_SIZE(N) ((N) > 0 ? ((N) + (N)/63 + 1) * 8 : 0)
+
+/* Emit code to probe a range of stack addresses from FIRST to FIRST+SIZE,
+ inclusive. These are offsets from the current stack pointer. SOL is the
+ size of local registers. ??? This clobbers r2 and r3. */
+
+static void
+ia64_emit_probe_stack_range (HOST_WIDE_INT first, HOST_WIDE_INT size, int sol)
+{
+ /* On the IA-64 there is a second stack in memory, namely the Backing Store
+ of the Register Stack Engine. We also need to probe it after checking
+ that the 2 stacks don't overlap. */
+ const int bs_size = BACKING_STORE_SIZE (sol);
+ rtx r2 = gen_rtx_REG (Pmode, GR_REG (2));
+ rtx r3 = gen_rtx_REG (Pmode, GR_REG (3));
+
+ /* Detect collision of the 2 stacks if necessary. */
+ if (bs_size > 0 || size > 0)
+ {
+ rtx p6 = gen_rtx_REG (BImode, PR_REG (6));
+
+ emit_insn (gen_bsp_value (r3));
+ emit_move_insn (r2, GEN_INT (-(first + size)));
+
+ /* Compare current value of BSP and SP registers. */
+ emit_insn (gen_rtx_SET (VOIDmode, p6,
+ gen_rtx_fmt_ee (LTU, BImode,
+ r3, stack_pointer_rtx)));
+
+ /* Compute the address of the probe for the Backing Store (which grows
+ towards higher addresses). We probe only at the first offset of
+ the next page because some OS (eg Linux/ia64) only extend the
+ backing store when this specific address is hit (but generate a SEGV
+ on other address). Page size is the worst case (4KB). The reserve
+ size is at least 4096 - (96 + 2) * 8 = 3312 bytes, which is enough.
+ Also compute the address of the last probe for the memory stack
+ (which grows towards lower addresses). */
+ emit_insn (gen_rtx_SET (VOIDmode, r3, plus_constant (r3, 4095)));
+ emit_insn (gen_rtx_SET (VOIDmode, r2,
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx, r2)));
+
+ /* Compare them and raise SEGV if the former has topped the latter. */
+ emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+ gen_rtx_fmt_ee (NE, VOIDmode, p6,
+ const0_rtx),
+ gen_rtx_SET (VOIDmode, p6,
+ gen_rtx_fmt_ee (GEU, BImode,
+ r3, r2))));
+ emit_insn (gen_rtx_SET (VOIDmode,
+ gen_rtx_ZERO_EXTRACT (DImode, r3, GEN_INT (12),
+ const0_rtx),
+ const0_rtx));
+ emit_insn (gen_rtx_COND_EXEC (VOIDmode,
+ gen_rtx_fmt_ee (NE, VOIDmode, p6,
+ const0_rtx),
+ gen_rtx_TRAP_IF (VOIDmode, const1_rtx,
+ GEN_INT (11))));
+ }
+
+ /* Probe the Backing Store if necessary. */
+ if (bs_size > 0)
+ emit_stack_probe (r3);
+
+ /* Probe the memory stack if necessary. */
+ if (size == 0)
+ ;
+
+ /* See if we have a constant small number of probes to generate. If so,
+ that's the easy case. */
+ else if (size <= PROBE_INTERVAL)
+ emit_stack_probe (r2);
+
+ /* The run-time loop is made up of 8 insns in the generic case while this
+ compile-time loop is made up of 5+2*(n-2) insns for n # of intervals. */
+ else if (size <= 4 * PROBE_INTERVAL)
+ {
+ HOST_WIDE_INT i;
+
+ emit_move_insn (r2, GEN_INT (-(first + PROBE_INTERVAL)));
+ emit_insn (gen_rtx_SET (VOIDmode, r2,
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx, r2)));
+ emit_stack_probe (r2);
+
+ /* Probe at FIRST + N * PROBE_INTERVAL for values of N from 2 until
+ it exceeds SIZE. If only two probes are needed, this will not
+ generate any code. Then probe at FIRST + SIZE. */
+ for (i = 2 * PROBE_INTERVAL; i < size; i += PROBE_INTERVAL)
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, r2,
+ plus_constant (r2, -PROBE_INTERVAL)));
+ emit_stack_probe (r2);
+ }
+
+ emit_insn (gen_rtx_SET (VOIDmode, r2,
+ plus_constant (r2,
+ (i - PROBE_INTERVAL) - size)));
+ emit_stack_probe (r2);
+ }
+
+ /* 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;
+
+ emit_move_insn (r2, GEN_INT (-first));
+
+
+ /* Step 1: round SIZE to the previous multiple of the interval. */
+
+ rounded_size = size & -PROBE_INTERVAL;
+
+
+ /* Step 2: compute initial and final value of the loop counter. */
+
+ /* TEST_ADDR = SP + FIRST. */
+ emit_insn (gen_rtx_SET (VOIDmode, r2,
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx, r2)));
+
+ /* LAST_ADDR = SP + FIRST + ROUNDED_SIZE. */
+ if (rounded_size > (1 << 21))
+ {
+ emit_move_insn (r3, GEN_INT (-rounded_size));
+ emit_insn (gen_rtx_SET (VOIDmode, r3, gen_rtx_PLUS (Pmode, r2, r3)));
+ }
+ else
+ emit_insn (gen_rtx_SET (VOIDmode, r3,
+ gen_rtx_PLUS (Pmode, r2,
+ GEN_INT (-rounded_size))));
+
+
+ /* 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_insn (gen_probe_stack_range (r2, r2, r3));
+
+
+ /* Step 4: probe at FIRST + SIZE if we cannot assert at compile-time
+ that SIZE is equal to ROUNDED_SIZE. */
+
+ /* TEMP = SIZE - ROUNDED_SIZE. */
+ if (size != rounded_size)
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, r2,
+ plus_constant (r2, rounded_size - size)));
+ emit_stack_probe (r2);
+ }
+ }
+
+ /* Make sure nothing is scheduled before we are done. */
+ emit_insn (gen_blockage ());
+}
+
+/* Probe a range of stack addresses from REG1 to REG2 inclusive. These are
+ absolute addresses. */
+
+const char *
+output_probe_stack_range (rtx reg1, rtx reg2)
+{
+ static int labelno = 0;
+ char loop_lab[32], end_lab[32];
+ rtx xops[3];
+
+ ASM_GENERATE_INTERNAL_LABEL (loop_lab, "LPSRL", labelno);
+ ASM_GENERATE_INTERNAL_LABEL (end_lab, "LPSRE", labelno++);
+
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, loop_lab);
+
+ /* Jump to END_LAB if TEST_ADDR == LAST_ADDR. */
+ xops[0] = reg1;
+ xops[1] = reg2;
+ xops[2] = gen_rtx_REG (BImode, PR_REG (6));
+ output_asm_insn ("cmp.eq %2, %I2 = %0, %1", xops);
+ fprintf (asm_out_file, "\t(%s) br.cond.dpnt ", reg_names [REGNO (xops[2])]);
+ assemble_name_raw (asm_out_file, end_lab);
+ fputc ('\n', asm_out_file);
+
+ /* TEST_ADDR = TEST_ADDR + PROBE_INTERVAL. */
+ xops[1] = GEN_INT (-PROBE_INTERVAL);
+ output_asm_insn ("addl %0 = %1, %0", xops);
+ fputs ("\t;;\n", asm_out_file);
+
+ /* Probe at TEST_ADDR and branch. */
+ output_asm_insn ("probe.w.fault %0, 0", xops);
+ fprintf (asm_out_file, "\tbr ");
+ assemble_name_raw (asm_out_file, loop_lab);
+ fputc ('\n', asm_out_file);
+
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, end_lab);
+
+ return "";
+}
+
/* Called after register allocation to add any instructions needed for the
prologue. Using a prologue insn is favored compared to putting all of the
instructions in output_function_prologue(), since it allows the scheduler
@@ -3265,6 +3478,12 @@ ia64_expand_prologue (void)
if (flag_stack_usage_info)
current_function_static_stack_size = current_frame_info.total_size;
+ if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
+ ia64_emit_probe_stack_range (STACK_CHECK_PROTECT,
+ current_frame_info.total_size,
+ current_frame_info.n_input_regs
+ + current_frame_info.n_local_regs);
+
if (dump_file)
{
fprintf (dump_file, "ia64 frame related registers "
@@ -6529,6 +6748,7 @@ rtx_needs_barrier (rtx x, struct reg_flags flags, int pred)
return 1;
case UNSPECV_SET_BSP:
+ case UNSPECV_PROBE_STACK_RANGE:
need_barrier = 1;
break;
@@ -6539,6 +6759,10 @@ rtx_needs_barrier (rtx x, struct reg_flags flags, int pred)
case UNSPECV_PSAC_NORMAL:
return 0;
+ case UNSPECV_PROBE_STACK_ADDRESS:
+ need_barrier = rtx_needs_barrier (XVECEXP (x, 0, 0), flags, pred);
+ break;
+
default:
gcc_unreachable ();
}
@@ -6700,10 +6924,7 @@ group_barrier_needed (rtx insn)
gcc_unreachable ();
}
- if (first_instruction && INSN_P (insn)
- && ia64_safe_itanium_class (insn) != ITANIUM_CLASS_IGNORE
- && GET_CODE (PATTERN (insn)) != USE
- && GET_CODE (PATTERN (insn)) != CLOBBER)
+ if (first_instruction && important_for_bundling_p (insn))
{
need_barrier = 0;
first_instruction = 0;
@@ -7397,8 +7618,7 @@ ia64_dfa_new_cycle (FILE *dump, int verbose, rtx insn, int last_clock,
&& scheduled_good_insn (last_scheduled_insn))))
|| (last_scheduled_insn
&& (GET_CODE (last_scheduled_insn) == CALL_INSN
- || GET_CODE (PATTERN (last_scheduled_insn)) == ASM_INPUT
- || asm_noperands (PATTERN (last_scheduled_insn)) >= 0)))
+ || unknown_for_bundling_p (last_scheduled_insn))))
{
init_insn_group_barriers ();
@@ -7423,8 +7643,7 @@ ia64_dfa_new_cycle (FILE *dump, int verbose, rtx insn, int last_clock,
if (last_scheduled_insn)
{
- if (GET_CODE (PATTERN (last_scheduled_insn)) == ASM_INPUT
- || asm_noperands (PATTERN (last_scheduled_insn)) >= 0)
+ if (unknown_for_bundling_p (last_scheduled_insn))
state_reset (curr_state);
else
{
@@ -8540,8 +8759,7 @@ issue_nops_and_insn (struct bundle_state *originator, int before_nops_num,
if (!try_issue_insn (curr_state, insn))
return;
curr_state->accumulated_insns_num++;
- gcc_assert (GET_CODE (PATTERN (insn)) != ASM_INPUT
- && asm_noperands (PATTERN (insn)) < 0);
+ gcc_assert (!unknown_for_bundling_p (insn));
if (ia64_safe_type (insn) == TYPE_L)
curr_state->accumulated_insns_num++;
@@ -8567,8 +8785,7 @@ issue_nops_and_insn (struct bundle_state *originator, int before_nops_num,
if (!try_issue_insn (curr_state, insn))
return;
curr_state->accumulated_insns_num++;
- if (GET_CODE (PATTERN (insn)) == ASM_INPUT
- || asm_noperands (PATTERN (insn)) >= 0)
+ if (unknown_for_bundling_p (insn))
{
/* Finish bundle containing asm insn. */
curr_state->after_nops_num
@@ -8702,6 +8919,7 @@ get_template (state_t state, int pos)
}
/* True when INSN is important for bundling. */
+
static bool
important_for_bundling_p (rtx insn)
{
@@ -8723,6 +8941,17 @@ get_next_important_insn (rtx insn, rtx tail)
return NULL_RTX;
}
+/* True when INSN is unknown, but important, for bundling. */
+
+static bool
+unknown_for_bundling_p (rtx insn)
+{
+ return (INSN_P (insn)
+ && ia64_safe_itanium_class (insn) == ITANIUM_CLASS_UNKNOWN
+ && GET_CODE (PATTERN (insn)) != USE
+ && GET_CODE (PATTERN (insn)) != CLOBBER);
+}
+
/* Add a bundle selector TEMPLATE0 before INSN. */
static void
@@ -8850,19 +9079,14 @@ bundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail)
insn != tail;
insn = NEXT_INSN (insn))
if (INSN_P (insn)
- && (ia64_safe_itanium_class (insn) == ITANIUM_CLASS_IGNORE
- || GET_CODE (PATTERN (insn)) == USE
- || GET_CODE (PATTERN (insn)) == CLOBBER)
+ && !important_for_bundling_p (insn)
&& GET_MODE (insn) == TImode)
{
PUT_MODE (insn, VOIDmode);
for (next_insn = NEXT_INSN (insn);
next_insn != tail;
next_insn = NEXT_INSN (next_insn))
- if (INSN_P (next_insn)
- && ia64_safe_itanium_class (next_insn) != ITANIUM_CLASS_IGNORE
- && GET_CODE (PATTERN (next_insn)) != USE
- && GET_CODE (PATTERN (next_insn)) != CLOBBER
+ if (important_for_bundling_p (next_insn)
&& INSN_CODE (next_insn) != CODE_FOR_insn_group_barrier)
{
PUT_MODE (next_insn, TImode);
@@ -8874,10 +9098,7 @@ bundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail)
insn != NULL_RTX;
insn = next_insn)
{
- gcc_assert (INSN_P (insn)
- && ia64_safe_itanium_class (insn) != ITANIUM_CLASS_IGNORE
- && GET_CODE (PATTERN (insn)) != USE
- && GET_CODE (PATTERN (insn)) != CLOBBER);
+ gcc_assert (important_for_bundling_p (insn));
type = ia64_safe_type (insn);
next_insn = get_next_important_insn (NEXT_INSN (insn), tail);
insn_num++;
@@ -8894,7 +9115,7 @@ bundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail)
only_bundle_end_p
= (next_insn != NULL_RTX
&& INSN_CODE (insn) == CODE_FOR_insn_group_barrier
- && ia64_safe_type (next_insn) == TYPE_UNKNOWN);
+ && unknown_for_bundling_p (next_insn));
/* We may fill up the current bundle if it is the cycle end
without a group barrier. */
bundle_end_p
@@ -8978,8 +9199,7 @@ bundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail)
curr_state = curr_state->originator)
{
insn = curr_state->insn;
- asm_p = (GET_CODE (PATTERN (insn)) == ASM_INPUT
- || asm_noperands (PATTERN (insn)) >= 0);
+ asm_p = unknown_for_bundling_p (insn);
insn_num++;
if (verbose >= 2 && dump)
{
@@ -9055,8 +9275,7 @@ bundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail)
/* Move the position backward in the window. Group barrier has
no slot. Asm insn takes all bundle. */
if (INSN_CODE (insn) != CODE_FOR_insn_group_barrier
- && GET_CODE (PATTERN (insn)) != ASM_INPUT
- && asm_noperands (PATTERN (insn)) < 0)
+ && !unknown_for_bundling_p (insn))
pos--;
/* Long insn takes 2 slots. */
if (ia64_safe_type (insn) == TYPE_L)
@@ -9064,8 +9283,7 @@ bundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail)
gcc_assert (pos >= 0);
if (pos % 3 == 0
&& INSN_CODE (insn) != CODE_FOR_insn_group_barrier
- && GET_CODE (PATTERN (insn)) != ASM_INPUT
- && asm_noperands (PATTERN (insn)) < 0)
+ && !unknown_for_bundling_p (insn))
{
/* The current insn is at the bundle start: emit the
template. */
@@ -9139,8 +9357,7 @@ bundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail)
if (recog_memoized (insn) == CODE_FOR_insn_group_barrier
&& !start_bundle && !end_bundle
&& next_insn
- && GET_CODE (PATTERN (next_insn)) != ASM_INPUT
- && asm_noperands (PATTERN (next_insn)) < 0)
+ && !unknown_for_bundling_p (next_insn))
num--;
start_bundle = false;
@@ -9270,8 +9487,7 @@ final_emit_insn_group_barriers (FILE *dump ATTRIBUTE_UNUSED)
&& important_for_bundling_p (insn))
seen_good_insn = 1;
need_barrier_p = (GET_CODE (insn) == CALL_INSN
- || GET_CODE (PATTERN (insn)) == ASM_INPUT
- || asm_noperands (PATTERN (insn)) >= 0);
+ || unknown_for_bundling_p (insn));
}
}
}
diff --git a/gcc/config/ia64/ia64.md b/gcc/config/ia64/ia64.md
index 349da7ba996..aa5e78636ea 100644
--- a/gcc/config/ia64/ia64.md
+++ b/gcc/config/ia64/ia64.md
@@ -105,6 +105,8 @@
UNSPECV_PSAC_NORMAL
UNSPECV_SETJMP_RECEIVER
UNSPECV_GOTO_RECEIVER
+ UNSPECV_PROBE_STACK_ADDRESS
+ UNSPECV_PROBE_STACK_RANGE
])
(include "predicates.md")
@@ -5182,6 +5184,26 @@
"mov %0 = ip"
[(set_attr "itanium_class" "frbr")])
+;;
+;; Stack checking
+
+(define_insn "probe_stack_address"
+ [(unspec_volatile [(match_operand:DI 0 "register_operand" "r")]
+ UNSPECV_PROBE_STACK_ADDRESS)]
+ ""
+ "probe.w.fault %0, 0"
+[(set_attr "itanium_class" "chk_s_i")])
+
+(define_insn "probe_stack_range"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec_volatile:DI [(match_operand:DI 1 "register_operand" "0")
+ (match_operand:DI 2 "register_operand" "r")]
+ UNSPECV_PROBE_STACK_RANGE))]
+ ""
+ "* return output_probe_stack_range (operands[0], operands[2]);"
+ [(set_attr "itanium_class" "unknown")
+ (set_attr "predicable" "no")])
+
;; Vector operations
(include "vect.md")
;; Atomic operations
diff --git a/gcc/config/ia64/linux.h b/gcc/config/ia64/linux.h
index 00b0ddba1a0..0e3b9be459c 100644
--- a/gcc/config/ia64/linux.h
+++ b/gcc/config/ia64/linux.h
@@ -86,3 +86,6 @@ do { \
#undef TARGET_INIT_LIBFUNCS
#define TARGET_INIT_LIBFUNCS ia64_soft_fp_init_libfuncs
+
+/* Define this to be nonzero if static stack checking is supported. */
+#define STACK_CHECK_STATIC_BUILTIN 1
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 3e8e45ccbcd..73c800bbd04 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -5614,6 +5614,13 @@ the stack farthest from the current stack pointer that you need to validate.
Normally, on platforms where this pattern is needed, you would obtain the
stack limit from a global or thread-specific variable or register.
+@cindex @code{probe_stack_address} instruction pattern
+@item @samp{probe_stack_address}
+If stack checking (@pxref{Stack Checking}) can be done on your system by
+probing the stack but without the need to actually access it, define this
+pattern and signal an error if the stack has overflowed. The single operand
+is the memory address in the stack that needs to be probed.
+
@cindex @code{probe_stack} instruction pattern
@item @samp{probe_stack}
If stack checking (@pxref{Stack Checking}) can be done on your system by
diff --git a/gcc/explow.c b/gcc/explow.c
index cc4391c5e8d..5513a123e3d 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -1525,17 +1525,24 @@ set_stack_check_libfunc (const char *libfunc_name)
void
emit_stack_probe (rtx address)
{
- rtx memref = gen_rtx_MEM (word_mode, address);
+#ifdef HAVE_probe_stack_address
+ if (HAVE_probe_stack_address)
+ emit_insn (gen_probe_stack_address (address));
+ else
+#endif
+ {
+ rtx memref = gen_rtx_MEM (word_mode, address);
- MEM_VOLATILE_P (memref) = 1;
+ MEM_VOLATILE_P (memref) = 1;
- /* See if we have an insn to probe the stack. */
+ /* 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
+ if (HAVE_probe_stack)
+ emit_insn (gen_probe_stack (memref));
+ else
#endif
- emit_move_insn (memref, const0_rtx);
+ emit_move_insn (memref, const0_rtx);
+ }
}
/* Probe a range of stack addresses from FIRST to FIRST+SIZE, inclusive.