This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Ping: C-family stack check for threads


Ye Joey wrote:
Thomas,

 I think your are working on a very useful feature. I have ARM MCU
 applications running of out stack space and resulting strange
 behaviors silently. I'd like to try your patch and probably give
 further comments

- Joey

Hi Due to convention of of thumb prologue to rtl, this patch needs to be modified too.

Regards
  Thomas Klein

gcc/ChangeLog
2011-07-03  Thomas Klein<th.r.klein@web.de>  <mailto:th.r.klein@web.de>

    * opts.c (common_handle_option): introduce additional stack checking
    parameters "direct" and "indirect"
    * flag-types.h (enum stack_check_type): Likewise
    * explow.c (allocate_dynamic_stack_space):
    - suppress stack probing if parameter "direct", "indirect" or if a
    stack-limit is given
    - do additional read of limit value if parameter "indirect" and a
    stack-limit symbol is given
    - emit a call to a stack_failure function [as an alternative to a trap
    call]
    (function probe_stack_range): if allowed to override the range probe
    emit generic_limit_check_stack
    * config/arm/arm.c (stack_check_output_function): new function to write
    the stack check code sequence to the assember file (inside prologue)
    (stack_check_work_registers): new function to find possible working
    registers [only used by "stack check"]
    (arm_expand_prologue): stack check integration for ARM and Thumb-2
    (thumb1_expand_prologue): stack check integration for Thumb-1
    * config/arm/arm.md (probe_stack): do not emit code when parameters
    "direct" or "indirect" given, emit move code as in gcc/explow.c
    [function emit_stack_probe]
    (probe_stack_done): dummy to make sure probe_stack insns are not
    optimized away
    (generic_limit_check_stack): if stack-limit and parameter "generic" is
    given use the limit the same way as in function
    allocate_dynamic_stack_space
    (stack_check): ARM/Thumb-2/Thumb-1 insn to output function
    stack_check_output_function
    (stack_failure): failure call used in function
    allocate_dynamic_stack_space [similar to a trap but avoid conflict with
    builtin_trap]

Index: gcc/flag-types.h
===================================================================
--- gcc/flag-types.h	(revision 175786)
+++ gcc/flag-types.h	(working copy)
@@ -153,7 +153,15 @@ enum stack_check_type

   /* Check the stack and entirely rely on the target configuration
      files, i.e. do not use the generic mechanism at all.  */
-  FULL_BUILTIN_STACK_CHECK
+  FULL_BUILTIN_STACK_CHECK,
+
+  /* Check the stack (if possible) before allocation of local variables at
+     each function entry. The stack limit is directly given e.g. by address
+     of a symbol */
+  DIRECT_STACK_CHECK,
+  /* Check the stack (if possible) before allocation of local variables at
+     each function entry. The stack limit is given by global variable. */
+  INDIRECT_STACK_CHECK
 };

 /* Names for the different levels of -Wstrict-overflow=N.  The numeric
Index: gcc/explow.c
===================================================================
--- gcc/explow.c	(revision 175786)
+++ gcc/explow.c	(working copy)
@@ -1358,7 +1358,12 @@ allocate_dynamic_stack_space (rtx size, unsigned s

   /* If needed, check that we have the required amount of stack.  Take into
      account what has already been checked.  */
-  if (STACK_CHECK_MOVING_SP)
+  if (  STACK_CHECK_MOVING_SP
+#ifdef HAVE_generic_limit_check_stack
+     || crtl->limit_stack
+#endif
+     || flag_stack_check == DIRECT_STACK_CHECK
+     || flag_stack_check == INDIRECT_STACK_CHECK)
     ;
   else if (flag_stack_check == GENERIC_STACK_CHECK)
     probe_stack_range (STACK_OLD_CHECK_PROTECT + STACK_CHECK_MAX_FRAME_SIZE,
@@ -1392,19 +1397,32 @@ allocate_dynamic_stack_space (rtx size, unsigned s
       /* Check stack bounds if necessary.  */
       if (crtl->limit_stack)
 	{
+          rtx limit_rtx;
 	  rtx available;
 	  rtx space_available = gen_label_rtx ();
+          if (  GET_CODE (stack_limit_rtx) == SYMBOL_REF
+&&  flag_stack_check == INDIRECT_STACK_CHECK)
+            limit_rtx = expand_unop (Pmode, mov_optab,
+				    gen_rtx_MEM (Pmode, stack_limit_rtx),
+				    NULL_RTX, 1);
+          else
+            limit_rtx = stack_limit_rtx;
 #ifdef STACK_GROWS_DOWNWARD
 	  available = expand_binop (Pmode, sub_optab,
-				    stack_pointer_rtx, stack_limit_rtx,
+				    stack_pointer_rtx, limit_rtx,
 				    NULL_RTX, 1, OPTAB_WIDEN);
 #else
 	  available = expand_binop (Pmode, sub_optab,
-				    stack_limit_rtx, stack_pointer_rtx,
+				    limit_rtx, stack_pointer_rtx,
 				    NULL_RTX, 1, OPTAB_WIDEN);
 #endif
 	  emit_cmp_and_jump_insns (available, size, GEU, NULL_RTX, Pmode, 1,
 				   space_available);
+#ifdef HAVE_stack_failure
+	  if (HAVE_stack_failure)
+	    emit_insn (gen_stack_failure ());
+	  else
+#endif
 #ifdef HAVE_trap
 	  if (HAVE_trap)
 	    emit_insn (gen_trap ());
@@ -1547,6 +1565,13 @@ probe_stack_range (HOST_WIDE_INT first, rtx size)
 	return;
     }
 #endif
+#ifdef HAVE_generic_limit_check_stack
+  else if (HAVE_generic_limit_check_stack)
+    {
+      rtx addr = memory_address (Pmode,stack_pointer_rtx);
+      emit_insn (gen_generic_limit_check_stack (addr));
+    }
+#endif

   /* Otherwise we have to generate explicit probes.  If we have a constant
      small number of them to generate, that's the easy case.  */
Index: gcc/config/arm/arm.c
===================================================================
--- gcc/config/arm/arm.c	(revision 175786)
+++ gcc/config/arm/arm.c	(working copy)
@@ -14625,6 +14625,283 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_I

}

+/*
+ * Write prolouge part of stack check into asm file.
+ * For Thumb this may look like this:
+ *   push {rsym,ramn}
+ *   ldr rsym, .LSPCHK0
+ *   ldr rsym, [rsym]
+ *   ldr ramn, .LSPCHK0 + 4
+ *   add rsym, rsym, ramn
+ *   cmp sp, rsym
+ *   bhs .LSPCHK1
+ *   push {lr}
+ *   bl __thumb_stack_failure
+ * .align 2
+ * .LSPCHK0:
+ *   .word symbol_addr_of(stack_limit_rtx)
+ *   .word lenght_of(amount)
+ * .LSPCHK1:
+ *   pop {rsym,ramn}
+ */
+void
+stack_check_output_function (FILE *f, int reg0, int reg1, unsigned amount,
+                             unsigned numregs)
+{
+  unsigned amount_needsreg;
+  bool amount_const_ok, is_non_opt_thumb2, is_thumb2_hi_reg[2];
+  bool issym=false;
+  static unsigned spchk_labelno = 0;
+  char ok_lable_str[256];
+  char pool_lable_str[256];
+
+  if (TARGET_THUMB1)
+    amount_const_ok = (amount<  256);
+  else
+    amount_const_ok = const_ok_for_arm (amount);
+
+  if (GET_CODE (stack_limit_rtx) == SYMBOL_REF) /*stack_limit_rtx*/
+    {
+      issym = true;
+      amount_needsreg = !amount_const_ok;
+    }
+  else
+    amount_needsreg = (amount>  0);
+	
+  is_non_opt_thumb2 = (TARGET_THUMB2&&  !(optimize_size || optimize>= 2));
+  is_thumb2_hi_reg[0] = (TARGET_THUMB2&&  reg0>7);
+  is_thumb2_hi_reg[1] = (TARGET_THUMB2&&  reg1>7);
+	
+  /*build labels for later use*/
+  if ( (issym&&  !(is_non_opt_thumb2 || is_thumb2_hi_reg[0]))
+     ||(amount&&  !amount_const_ok
+&&  !((issym&&  is_thumb2_hi_reg[1])
+	     || (!issym&&  is_thumb2_hi_reg[0])
+         || is_non_opt_thumb2)))
+    ASM_GENERATE_INTERNAL_LABEL (pool_lable_str, "LSPCHK", spchk_labelno++);
+  ASM_GENERATE_INTERNAL_LABEL (ok_lable_str, "LSPCHK", spchk_labelno++);
+
+  if (issym&&  amount) /*need temp regs for limit and amount*/
+    {
+      if (numregs>= 2)
+        ; /*have 2 regs =>  no need to push*/
+      else if (numregs == 1)
+        {
+          if (amount_needsreg)
+            {
+              /*have one reg but need two regs =>  push temp reg for amount*/
+              if (TARGET_ARM)
+                asm_fprintf (f, "\tstr\t%r, [%r, #-4]!\n", reg1, SP_REGNUM);
+              else
+                asm_fprintf (f, "\tpush\t{%r}\n", reg1);
+	      /*due to additional push try to correct amount*/
+	      if (amount>= 4)
+	        {
+		  if (amount_const_ok)
+		    {
+		      if (TARGET_THUMB1 || const_ok_for_arm(amount - 4))
+		        amount -= 4;
+		      /*on Thumb2 or ARM may not corrected; shouldn't hurt*/
+		    }
+		  else /*will be loaded from pool*/
+		    amount -= 4;
+	        }
+            }
+        }
+      else if (amount_needsreg)
+        {
+          /*have no reg but need two =>  push temp regs for limit and amount*/
+          if (TARGET_ARM)
+            asm_fprintf (f, "\tstmfd\t%r!, {%r,%r}\n", SP_REGNUM, reg0, reg1);
+          else
+            asm_fprintf (f, "\tpush\t{%r,%r}\n", reg0, reg1);
+          /*due to additional push try to correct amount*/
+          if (amount>= 8)
+            {
+              if (amount_const_ok)
+                {
+                  if (TARGET_THUMB1 || const_ok_for_arm(amount - 8))
+                    amount -= 8;
+                  /*on Thumb2 or ARM may not corrected; shouldn't hurt*/
+                }
+              else /*will be loaded from pool*/
+                amount -= 8;
+            }
+        }
+      else
+        {
+          /*have no reg but need one reg =>  push temp reg for limit*/
+          if (TARGET_ARM)
+            asm_fprintf (f, "\tstr\t%r, [%r, #-4]!\n", reg0, SP_REGNUM);
+          else
+            asm_fprintf (f, "\tpush\t{%r}\n", reg0);
+          /*due to additional push try to correct amount*/
+          if (amount>= 4)
+            {
+              if (amount_const_ok)
+                {
+                  if (TARGET_THUMB1 || const_ok_for_arm(amount - 4))
+                    amount -= 4;
+                  /*on Thumb2 or ARM may not corrected; shouldn't hurt*/
+                }
+              else /*will be loaded from pool*/
+                amount -= 4;
+            }
+        }
+    }
+  else if ((issym || amount_needsreg)&&  numregs == 0)
+    { /*push temp reg either for limit or amount*/
+      if (TARGET_ARM)
+        asm_fprintf (f, "\tstr\t%r, [%r, #-4]!\n", reg0, SP_REGNUM);
+      else
+        asm_fprintf (f, "\tpush\t{%r}\n", reg0);
+    }
+
+  if (issym)
+    {
+      if (is_non_opt_thumb2 || is_thumb2_hi_reg[0])
+        {
+          const char *str ;
+          str = (const char *) XSTR  (stack_limit_rtx, 0);
+          asm_fprintf (f, "\tmovw\t%r, #:lower16:%s\n", reg0, str);
+          asm_fprintf (f, "\tmovt\t%r, #:upper16:%s\n", reg0, str);
+        }
+      else
+        {
+          asm_fprintf (f, "\tldr\t%r, ", reg0);
+          assemble_name (f, pool_lable_str); /* =stack_limit_rtx */
+          fputs ("\n", f);
+        }
+
+      if (flag_stack_check == INDIRECT_STACK_CHECK)
+        asm_fprintf (f, "\tldr\t%r, [%r]\n", reg0, reg0);
+      if (amount)
+        {
+          if (amount_const_ok)
+            {
+              if (TARGET_32BIT)
+                asm_fprintf (f, "\tadds\t%r, %r, #%d\n", reg0, reg0, amount);
+              else
+                asm_fprintf (f, "\tadd\t%r, %r, #%d\n", reg0, reg0, amount);
+            }
+          else
+            {
+              if (is_non_opt_thumb2 || is_thumb2_hi_reg[1])
+                {
+                  asm_fprintf (f, "\tmovw\t%r, #0x%X\n", reg1, amount&0xFFFF);
+                  asm_fprintf (f, "\tmovt\t%r, #0x%X\n", reg1,
+				    (amount>>16)&0xFFFF);
+                }
+              else
+                {
+                  asm_fprintf (f, "\tldr\t%r, ", reg1);
+	              assemble_name (f, pool_lable_str); /* =amount */
+                  if (is_thumb2_hi_reg[0])
+                    fputs ("\n", f);
+                  else
+                    fputs (" + 4\n", f);
+                }
+              asm_fprintf (f, "\tadd\t%r, %r, %r\n", reg0, reg0, reg1);
+            }
+        }
+      asm_fprintf (f, "\tcmp\t%r, %r\n", SP_REGNUM, reg0);
+    }
+  else if (amount)
+    {
+      if (amount_const_ok)
+        asm_fprintf (f, "\tmov\t%r, #%d\n", reg0, amount);
+      else
+        {
+          if (is_non_opt_thumb2 || is_thumb2_hi_reg[0])
+            {
+              asm_fprintf (f, "\tmovw\t%r, #0x%X\n", reg0, amount&0xFFFF);
+              asm_fprintf (f, "\tmovt\t%r, #0x%X\n", reg0,(amount>>16)&0xFFFF);
+            }
+          else
+            {
+              asm_fprintf (f, "\tldr\t%r, ", reg0);
+              assemble_name (f, pool_lable_str); /* amount */
+              fputs ("\n", f);
+            }
+        }
+      asm_fprintf (f, "\tadd\t%r, %r, %r\n", reg0,reg0,REGNO(stack_limit_rtx));
+      asm_fprintf (f, "\tcmp\t%r, %r\n", SP_REGNUM, reg0);
+    }
+  else
+    asm_fprintf (f, "\tcmp\t%r, %r\n", SP_REGNUM, REGNO(stack_limit_rtx));
+  asm_fprintf (f, "\tbhs\t");
+  assemble_name (f, ok_lable_str);
+  fputs ("\n", f);
+
+  if (TARGET_ARM)
+    {
+      asm_fprintf (f, "\tstr\t%r, [%r, #-4]!\n", LR_REGNUM, SP_REGNUM);
+      asm_fprintf (f, "\tbl\t__arm_stack_failure\t%@ stack check\n");
+    }
+  else
+    {
+      asm_fprintf (f, "\tpush\t{%r}\n", LR_REGNUM);
+      asm_fprintf (f, "\tbl\t__thumb_stack_failure\t%@ stack check\n");
+    }
+	
+    /*pool*/
+    if ( (issym&&  !(is_non_opt_thumb2 || is_thumb2_hi_reg[0]))
+       ||(amount&&  !amount_const_ok
+&&  !(  (issym&&  is_thumb2_hi_reg[1])
+		     || (!issym&&  is_thumb2_hi_reg[0])
+	         || is_non_opt_thumb2)))
+    {
+      /*temp regs: collect values from here*/
+      if (!TARGET_ARM)
+        ASM_OUTPUT_ALIGN (f, 2);
+      ASM_OUTPUT_LABEL(f,pool_lable_str);
+	  if (issym&&  !(is_non_opt_thumb2 || is_thumb2_hi_reg[0]))
+	    assemble_aligned_integer (UNITS_PER_WORD, stack_limit_rtx);
+      if (amount&&  !amount_const_ok
+&&  !(  (issym&&  is_thumb2_hi_reg[1])
+		     || (!issym&&  is_thumb2_hi_reg[0])
+	         || is_non_opt_thumb2))
+		assemble_aligned_integer (UNITS_PER_WORD, GEN_INT (amount));
+	}
+  ASM_OUTPUT_LABEL(f,ok_lable_str);
+  if (issym&&  amount) /*pop temp regs used by limit and amount*/
+    {
+      if (numregs>= 2)
+        ; /*no need to pop*/
+      else if (numregs == 1)
+        {
+          if (amount_needsreg)
+            {
+              if (TARGET_ARM)
+                asm_fprintf (f, "\tldr\t%r, [%r, #4]!\n", reg1, SP_REGNUM);
+              else
+                asm_fprintf (f, "\tpop\t{%r}\n", reg1);
+            }
+        }
+      else if (amount_needsreg)
+        {
+          if (TARGET_ARM)
+            asm_fprintf (f, "\tldmfd\t%r!, {%r,%r}\n", SP_REGNUM, reg0, reg1);
+          else
+            asm_fprintf (f, "\tpop\t{%r,%r}\n", reg0, reg1);
+        }
+      else
+        {
+          if (TARGET_ARM)
+            asm_fprintf (f, "\tldr\t%r, [%r, #4]!\n", reg0, SP_REGNUM);
+          else
+            asm_fprintf (f, "\tpop\t{%r}\n", reg0);
+        }
+    }
+  else if ((issym || amount_needsreg)&&  numregs == 0)
+    { /*pop temp reg used by limit or amount*/
+      if (TARGET_ARM)
+        asm_fprintf (f, "\tldr\t%r, [%r, #4]!\n", reg0, SP_REGNUM);
+      else
+        asm_fprintf (f, "\tpop\t{%r}\n", reg0);
+    }
+}
+
 const char *
 arm_output_epilogue (rtx sibling)
 {
@@ -15797,6 +16074,72 @@ thumb_set_frame_pointer (arm_stack_offsets *offset
   RTX_FRAME_RELATED_P (insn) = 1;
 }

+/*search for possible work registers for stack-check operation at prologue
+ return the number of register that can be used without extra push/pop */
+
+static int
+stack_check_work_registers (rtx *workreg)
+{
+  int reg, i, k, n, nregs;
+
+  if (crtl->args.info.pcs_variant<= ARM_PCS_AAPCS_LOCAL)
+    {
+      nregs = crtl->args.info.aapcs_next_ncrn;
+    }
+  else
+    nregs = crtl->args.info.nregs;
+
+
+  n = 0;
+  i = 0;
+  /* check if we can use one of the argument registers r0..r3 as long as they
+   * not holding data*/
+  for (reg = 0; reg<= LAST_ARG_REGNUM&&  i<  2; reg++)
+    {
+      if (  !df_regs_ever_live_p (reg)
+         || (cfun->machine->uses_anonymous_args&&  crtl->args.pretend_args_size
+>  (LAST_ARG_REGNUM - reg) * UNITS_PER_WORD)
+         || (!cfun->machine->uses_anonymous_args&&  nregs<  reg + 1)
+         )
+        {
+	  workreg[i++] = gen_rtx_REG (SImode, reg);
+	  n = (reg + 1) % 4;
+        }
+    }
+
+  /* otherwise try to use r4..r7*/
+  for (reg = LAST_ARG_REGNUM + 1; reg<= LAST_LO_REGNUM&&  i<  2; reg++)
+    {
+      if (  df_regs_ever_live_p (reg)
+&&  !fixed_regs[reg]
+&&  reg != FP_REGNUM )
+        {
+	  workreg[i++] = gen_rtx_REG (SImode, reg);
+        }
+    }
+
+  if (TARGET_32BIT)
+    {
+      /* ARM and Thumb-2 can use high regs.  */
+      for (reg = FIRST_HI_REGNUM; reg<= LAST_HI_REGNUM&&  i<  2; reg ++)
+        if (  df_regs_ever_live_p (reg)
+&&  !fixed_regs[reg]
+&&  reg != FP_REGNUM )
+          {
+	    workreg[i++] = gen_rtx_REG (SImode, reg);
+          }
+    }
+
+  k = i;
+  /* if not enough found to be uses without extra push,
+   * collect next from r0..r4*/
+  for ( ; i<2; i++)
+    workreg[i] = gen_rtx_REG (SImode, n++);
+
+  return k;
+}
+
+
 /* Generate the prologue instructions for entry into an ARM or Thumb-2
    function.  */
 void
@@ -16046,6 +16389,23 @@ arm_expand_prologue (void)
     current_function_static_stack_size
       = offsets->outgoing_args - offsets->saved_args;

+  if (  crtl->limit_stack
+&&  !(IS_INTERRUPT (func_type))
+&&  (  flag_stack_check == DIRECT_STACK_CHECK
+        || flag_stack_check == INDIRECT_STACK_CHECK)
+&&  (offsets->outgoing_args - offsets->saved_args)>  0
+     )
+    {
+      rtx reg[2], num_temp_regs;
+
+      amount = GEN_INT (offsets->outgoing_args - saved_regs
+			- offsets->saved_args);
+      num_temp_regs = GEN_INT (stack_check_work_registers(reg));
+      insn = gen_stack_check (stack_pointer_rtx, reg[0], reg[1], amount,
+                              num_temp_regs);
+      insn = emit_insn (insn);
+    }
+
   if (offsets->outgoing_args != offsets->saved_args + saved_regs)
     {
       /* This add can produce multiple insns for a large constant, so we
@@ -21247,6 +21607,22 @@ thumb1_expand_prologue (void)

   amount = offsets->outgoing_args - offsets->saved_regs;
   amount -= 4 * thumb1_extra_regs_pushed (offsets, true);
+
+  if(  crtl->limit_stack
+&&  (  flag_stack_check == DIRECT_STACK_CHECK
+       || flag_stack_check == INDIRECT_STACK_CHECK)
+&&  (offsets->outgoing_args - offsets->saved_args)
+    )
+    {
+      rtx reg[2], num_temp_regs, tmp_amount;
+
+      tmp_amount = GEN_INT (amount);
+      num_temp_regs = GEN_INT (stack_check_work_registers(reg));
+      insn = gen_stack_check (stack_pointer_rtx, reg[0], reg[1], tmp_amount,
+                              num_temp_regs);
+      insn = emit_insn (insn);
+    }
+
   if (amount)
     {
       if (amount<  512)
@@ -21406,6 +21782,7 @@ thumb1_output_interwork (void)
   asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name);

   return "";
+
 }

 /* Handle the case of a double word load into a low register from
Index: gcc/config/arm/arm.md
===================================================================
--- gcc/config/arm/arm.md	(revision 175786)
+++ gcc/config/arm/arm.md	(working copy)
@@ -105,6 +105,8 @@
   UNSPEC_SYMBOL_OFFSET  ; The offset of the start of the symbol from
                         ; another symbolic address.
   UNSPEC_MEMORY_BARRIER ; Represent a memory barrier.
+  UNSPEC_PROBE_STACK    ; probe stack memory reference
+  UNSPEC_PROLOGUE_SPCHK ; stack pointer check using the stack_limit_rtx
 ])

 ;; UNSPEC_VOLATILE Usage:
@@ -10758,6 +10760,115 @@

;;

+(define_expand "probe_stack"
+  [(match_operand 0 "memory_operand" "")]
+  "TARGET_EITHER"
+{
+  if (  flag_stack_check == DIRECT_STACK_CHECK
+     || flag_stack_check == INDIRECT_STACK_CHECK)
+    ;
+  else
+    {
+      emit_move_insn (operands[0], const0_rtx);
+      emit_insn (gen_probe_stack_done ());
+      emit_insn (gen_blockage ());
+    }
+  DONE;
+}
+)
+
+(define_insn "probe_stack_done"
+  [(unspec_volatile [(const_int 0)] UNSPEC_PROBE_STACK)]
+  "TARGET_EITHER"
+  {return \"@ probe stack done\";}
+  [(set_attr "type" "store1")
+   (set_attr "length" "0")]
+)
+
+(define_expand "generic_limit_check_stack"
+  [(match_operand 0 "memory_operand" "")]
+  "crtl->limit_stack
+&&  flag_stack_check != DIRECT_STACK_CHECK
+&&  flag_stack_check != INDIRECT_STACK_CHECK"
+{
+  rtx label = gen_label_rtx ();
+  rtx addr = copy_rtx (operands[0]);
+  addr = gen_rtx_fmt_ee (MINUS, Pmode, addr, GEN_INT (0));
+  addr = force_operand (addr, NULL_RTX);
+  emit_insn (gen_blockage ());
+  emit_cmp_and_jump_insns (stack_limit_rtx, addr, LEU, NULL_RTX, Pmode, 1,
+                           label);
+  emit_insn (gen_stack_failure ());
+  emit_label (label);
+  emit_insn (gen_blockage ());
+  DONE;
+}
+)
+
+(define_insn "stack_check"
+  [(set
+   (match_operand:SI 0 "register_operand" "=k")
+   (unspec:SI
+    [
+   (match_operand:SI 1 "register_operand" "r")
+   (match_operand:SI 2 "register_operand" "r")
+   (match_operand:SI 3 "general_operand"  "i")
+   (match_operand:SI 4 "general_operand"  "i")
+    ]
+   UNSPEC_PROLOGUE_SPCHK )
+   )
+   (clobber (reg:CC CC_REGNUM))
+  ]
+  "TARGET_EITHER
+&&  (GET_CODE (operands[3]) == CONST_INT)
+&&  (GET_CODE (operands[4]) == CONST_INT)"
+  "*
+  {
+    int reg0, reg1;
+    unsigned amount, numregs;
+    extern void stack_check_output_function (FILE *, int, int, unsigned,
+                                            unsigned);
+
+    reg0 = REGNO (operands[1]);
+    reg1 = REGNO (operands[2]);
+    amount = INTVAL (operands[3]);
+    numregs = INTVAL (operands[4]);
+
+    stack_check_output_function  (asm_out_file, reg0, reg1, amount, numregs);
+  }
+  return \"\";
+  "
+  [(set_attr "conds" "clob")
+   (set (attr "length")
+   (if_then_else (eq_attr "is_thumb" "yes")
+      (const_int 44)
+      (const_int 52)))]
+)
+
+(define_insn "stack_failure"
+  [(trap_if (const_int 1) (const_int 0))]
+  "TARGET_EITHER"
+  "*
+  {
+    rtx ops[2];
+
+    ops[0] = stack_pointer_rtx;
+    ops[1] = gen_rtx_REG (SImode, LR_REGNUM);
+    if (TARGET_ARM)
+      {
+        output_asm_insn (\"str\\t%1, [%0, #-4]!\", ops);
+        output_asm_insn (\"bl\\t__arm_stack_failure\\t%@ trap call\", ops);
+      }
+    else
+      {
+        output_asm_insn (\"push\\t{%1}\", ops);
+        output_asm_insn (\"bl\\t__thumb_stack_failure\\t%@ trap call\", ops);
+      }
+  }
+  return \"\";
+  "
+)
+
 ;; We only care about the lower 16 bits of the constant
 ;; being inserted into the upper 16 bits of the register.
 (define_insn "*arm_movtas_ze"




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]