diff mbox

[IA-64] Implement static stack checking

Message ID 201203062308.20673.ebotcazou@adacore.com
State New
Headers show

Commit Message

Eric Botcazou March 6, 2012, 10:08 p.m. UTC
This at last implements static stack checking for the IA-64, i.e. stack 
checking of the static part of the frame, and makes it possible to pass the 
entire ACATS testsuite.  The peculiarity is the second stack in memory, namely 
the Backing Store of the Register Stack Engine, that needs to be dealt with.

This also introduces full support for "unknown" insns in the bundling code (the 
only other "unknown" insn, namely set_bsp, didn't need that because it comes 
always last in a function).

Bootstrapped/regtested on IA-64/Linux (and also tested on IA-64/HP-UX and VMS), 
OK for the mainline?


2012-03-06  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.

Comments

Tristan Gingold April 4, 2012, 7:33 a.m. UTC | #1
Hi,

I'd like to ping this patch, as it hasn't been reviewed for 4 weeks.

Tristan.

On Mar 6, 2012, at 11:08 PM, Eric Botcazou wrote:

> This at last implements static stack checking for the IA-64, i.e. stack 
> checking of the static part of the frame, and makes it possible to pass the 
> entire ACATS testsuite.  The peculiarity is the second stack in memory, namely 
> the Backing Store of the Register Stack Engine, that needs to be dealt with.
> 
> This also introduces full support for "unknown" insns in the bundling code (the 
> only other "unknown" insn, namely set_bsp, didn't need that because it comes 
> always last in a function).
> 
> Bootstrapped/regtested on IA-64/Linux (and also tested on IA-64/HP-UX and VMS), 
> OK for the mainline?
> 
> 
> 2012-03-06  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.
> 
> 
> -- 
> Eric Botcazou
> <p2.diff>
diff mbox

Patch

Index: doc/md.texi
===================================================================
--- doc/md.texi	(revision 184852)
+++ doc/md.texi	(working copy)
@@ -5610,6 +5610,13 @@  the stack farthest from the current stac
 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
Index: explow.c
===================================================================
--- explow.c	(revision 184852)
+++ explow.c	(working copy)
@@ -1518,17 +1518,24 @@  set_stack_check_libfunc (const char *lib
 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.
Index: config/ia64/ia64.c
===================================================================
--- config/ia64/ia64.c	(revision 184852)
+++ config/ia64/ia64.c	(working copy)
@@ -47,6 +47,7 @@  along with GCC; see the file COPYING3.
 #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,
@@ -2695,6 +2701,10 @@  ia64_compute_frame_size (HOST_WIDE_INT s
   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.  */
@@ -3252,6 +3262,213 @@  gen_fr_restore_x (rtx dest, rtx src, rtx
   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
@@ -3287,6 +3504,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 "
@@ -6558,6 +6781,7 @@  rtx_needs_barrier (rtx x, struct reg_fla
 	  return 1;
 
 	case UNSPECV_SET_BSP:
+	case UNSPECV_PROBE_STACK_RANGE:
 	  need_barrier = 1;
           break;
 
@@ -6568,6 +6792,10 @@  rtx_needs_barrier (rtx x, struct reg_fla
 	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 ();
 	}
@@ -6729,10 +6957,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;
@@ -7426,8 +7651,7 @@  ia64_dfa_new_cycle (FILE *dump, int verb
 	       && 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 ();
 
@@ -7452,8 +7676,7 @@  ia64_dfa_new_cycle (FILE *dump, int verb
 
       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
 	    {
@@ -8569,8 +8792,7 @@  issue_nops_and_insn (struct bundle_state
       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++;
@@ -8596,8 +8818,7 @@  issue_nops_and_insn (struct bundle_state
       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
@@ -8731,6 +8952,7 @@  get_template (state_t state, int pos)
 }
 
 /* True when INSN is important for bundling.  */
+
 static bool
 important_for_bundling_p (rtx insn)
 {
@@ -8752,6 +8974,17 @@  get_next_important_insn (rtx insn, rtx t
   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
@@ -8879,19 +9112,14 @@  bundling (FILE *dump, int verbose, rtx p
        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);
@@ -8903,10 +9131,7 @@  bundling (FILE *dump, int verbose, rtx p
        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++;
@@ -8923,7 +9148,7 @@  bundling (FILE *dump, int verbose, rtx p
 	  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
@@ -9007,8 +9232,7 @@  bundling (FILE *dump, int verbose, rtx p
        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)
 	{
@@ -9084,8 +9308,7 @@  bundling (FILE *dump, int verbose, rtx p
       /* 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)
@@ -9093,8 +9316,7 @@  bundling (FILE *dump, int verbose, rtx p
       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.  */
@@ -9168,8 +9390,7 @@  bundling (FILE *dump, int verbose, rtx p
 	    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;
@@ -9299,8 +9520,7 @@  final_emit_insn_group_barriers (FILE *du
 		   && 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));
 	}
     }
 }
Index: config/ia64/linux.h
===================================================================
--- config/ia64/linux.h	(revision 184852)
+++ config/ia64/linux.h	(working copy)
@@ -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
Index: config/ia64/ia64.md
===================================================================
--- config/ia64/ia64.md	(revision 184852)
+++ config/ia64/ia64.md	(working copy)
@@ -105,6 +105,8 @@  (define_c_enum "unspecv" [
    UNSPECV_PSAC_NORMAL
    UNSPECV_SETJMP_RECEIVER
    UNSPECV_GOTO_RECEIVER
+   UNSPECV_PROBE_STACK_ADDRESS
+   UNSPECV_PROBE_STACK_RANGE
   ])
 
 (include "predicates.md")
@@ -5182,6 +5184,26 @@  (define_insn "ip_value"
  "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
Index: config/ia64/hpux.h
===================================================================
--- config/ia64/hpux.h	(revision 184852)
+++ config/ia64/hpux.h	(working copy)
@@ -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)
Index: config/ia64/ia64-protos.h
===================================================================
--- config/ia64/ia64-protos.h	(revision 184852)
+++ config/ia64/ia64-protos.h	(working copy)
@@ -61,6 +61,7 @@  extern int ia64_hard_regno_rename_ok (in
 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]);