c-common.c (enum attrs): Add A_NO_LIMIT_STACK.
authorGeoff Keating <geoffk@cygnus.com>
Sat, 4 Dec 1999 03:00:04 +0000 (03:00 +0000)
committerGeoffrey Keating <geoffk@gcc.gnu.org>
Sat, 4 Dec 1999 03:00:04 +0000 (03:00 +0000)
* c-common.c (enum attrs): Add A_NO_LIMIT_STACK.
(init_attributes): Add A_NO_LIMIT_STACK.
(decl_attributes): Handle A_NO_LIMIT_STACK.
* c-decl.c (duplicate_decls): Handle DECL_NO_LIMIT_STACK.
* explow.c (allocate_dynamic_stack_space) [!HAVE_allocate_stack]:
Handle stack bounds checking.
* flags.h (flag_stack_check): Use the word 'probe' rather than
'check', because the flag doesn't actually cause any checking to
be done.
* function.c (expand_function_start): Set
current_function_limit_stack.
* function.h (struct function): Add limit_stack.
(current_function_limit_stack): Define.
* invoke.texi (Code Gen Options): Document new options.
* rtl.h: Declare stack_limit_rtx.
* toplev.c (stack_limit_rtx): New variable.
(decode_f_option): Handle new options -fstack-limit-register=REG,
-fstack-limit-symbol=IDENT, -fno-stack-limit.
(main): Add stack_limit_rtx as GC root.
* tree.h (DECL_NO_LIMIT_STACK): New macro.
(struct tree_decl): New member no_limit_stack.

* config/rs6000/rs6000.c (rs6000_allocate_stack_space): Handle
stack_limit_rtx.
* config/rs6000/rs6000.md (allocate_stack): Handle stack_limit_rtx.
(conditional_trap+1): Get new mnemonic correct.
(conditional_trap+2): New pattern for DImode traps.

* config/m68k/m68k.c (output_function_prologue): Handle
stack_limit_rtx.
* config/m68k/m68k.md (trap): New insn.
(conditional_trap): New insn.
* md.texi (Standard Names): Document `trap' and
`conditional_trap'.
* optabs.c (gen_cond_trap): Use start_sequence()/end_sequence()
so a cc0 setter doesn't get emitted at some random place in the
function.

* config/i960/i960.md (trap): New insn.
(conditional_trap): New expander.
(conditional_trap+1, conditional_trap+2): New insns for signed
and unsigned cases.
* config/i960/i960.c (i960_function_prologue): Use
STARTING_FRAME_OFFSET.  Handle stack_limit_rtx.

Co-Authored-By: Greg McGary <gkm@gnu.org>
From-SVN: r30771

21 files changed:
gcc/ChangeLog
gcc/c-common.c
gcc/c-decl.c
gcc/config/i960/i960.c
gcc/config/i960/i960.md
gcc/config/m68k/m68k.c
gcc/config/m68k/m68k.md
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.md
gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/explow.c
gcc/flags.h
gcc/function.c
gcc/function.h
gcc/invoke.texi
gcc/md.texi
gcc/optabs.c
gcc/rtl.h
gcc/toplev.c
gcc/tree.h

index 2fbc0721964bf3b2def003aba20d1ab279ddafad..5e5489ab740e0be111a1dcae2a9d0ea665af746b 100644 (file)
@@ -1,3 +1,51 @@
+1999-12-04  Geoffrey Keating  <geoffk@cygnus.com>
+           Greg McGary  <gkm@gnu.org>
+
+       * c-common.c (enum attrs): Add A_NO_LIMIT_STACK.
+       (init_attributes): Add A_NO_LIMIT_STACK.
+       (decl_attributes): Handle A_NO_LIMIT_STACK.
+       * c-decl.c (duplicate_decls): Handle DECL_NO_LIMIT_STACK.
+       * explow.c (allocate_dynamic_stack_space) [!HAVE_allocate_stack]:
+       Handle stack bounds checking.
+       * flags.h (flag_stack_check): Use the word 'probe' rather than
+       'check', because the flag doesn't actually cause any checking to
+       be done.
+       * function.c (expand_function_start): Set
+       current_function_limit_stack.
+       * function.h (struct function): Add limit_stack.
+       (current_function_limit_stack): Define.
+       * invoke.texi (Code Gen Options): Document new options.
+       * rtl.h: Declare stack_limit_rtx.
+       * toplev.c (stack_limit_rtx): New variable.
+       (decode_f_option): Handle new options -fstack-limit-register=REG,
+       -fstack-limit-symbol=IDENT, -fno-stack-limit.
+       (main): Add stack_limit_rtx as GC root.
+       * tree.h (DECL_NO_LIMIT_STACK): New macro.
+       (struct tree_decl): New member no_limit_stack.
+
+       * config/rs6000/rs6000.c (rs6000_allocate_stack_space): Handle
+       stack_limit_rtx.
+       * config/rs6000/rs6000.md (allocate_stack): Handle stack_limit_rtx.
+       (conditional_trap+1): Get new mnemonic correct.
+       (conditional_trap+2): New pattern for DImode traps.
+
+       * config/m68k/m68k.c (output_function_prologue): Handle
+       stack_limit_rtx.
+       * config/m68k/m68k.md (trap): New insn.
+       (conditional_trap): New insn.
+       * md.texi (Standard Names): Document `trap' and
+       `conditional_trap'.
+       * optabs.c (gen_cond_trap): Use start_sequence()/end_sequence()
+       so a cc0 setter doesn't get emitted at some random place in the
+       function.
+
+       * config/i960/i960.md (trap): New insn.
+       (conditional_trap): New expander.
+       (conditional_trap+1, conditional_trap+2): New insns for signed
+       and unsigned cases.
+       * config/i960/i960.c (i960_function_prologue): Use 
+       STARTING_FRAME_OFFSET.  Handle stack_limit_rtx.
+
 Thu Dec  2 21:22:45 1999  Greg McGary  <gkm@gnu.org>
                          Geoffrey Keating  <geoffk@cygnus.com>
 
index 10c162402844f6fb57283c70884b71f0d5a9f93e..866f53fa7282e72d581d6120b73ca01e2bdf0962 100644 (file)
@@ -140,7 +140,8 @@ int skip_evaluation;
 enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION,
            A_NO_CHECK_MEMORY_USAGE, A_NO_INSTRUMENT_FUNCTION,
            A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED,
-           A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS, A_MALLOC};
+           A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS, A_MALLOC,
+           A_NO_LIMIT_STACK};
 
 enum format_type { printf_format_type, scanf_format_type,
                   strftime_format_type };
@@ -482,6 +483,7 @@ init_attributes ()
   add_attribute (A_NO_INSTRUMENT_FUNCTION, "no_instrument_function", 0, 0, 1);
   add_attribute (A_NO_CHECK_MEMORY_USAGE, "no_check_memory_usage", 0, 0, 1);
   add_attribute (A_MALLOC, "malloc", 0, 0, 1);
+  add_attribute (A_NO_LIMIT_STACK, "no_stack_limit", 0, 0, 1);
 }
 \f
 /* Default implementation of valid_lang_attribute, below.  By default, there
@@ -1038,6 +1040,23 @@ decl_attributes (node, attributes, prefix_attributes)
          else
            DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
          break;
+
+        case A_NO_LIMIT_STACK:
+         if (TREE_CODE (decl) != FUNCTION_DECL)
+           {
+             error_with_decl (decl,
+                              "`%s' attribute applies only to functions",
+                              IDENTIFIER_POINTER (name));
+           }
+         else if (DECL_INITIAL (decl))
+           {
+             error_with_decl (decl,
+                              "can't set `%s' attribute after definition",
+                              IDENTIFIER_POINTER (name));
+           }
+         else
+           DECL_NO_LIMIT_STACK (decl) = 1;
+         break;
        }
     }
 }
index 39ec85666e6ce2c11047cb5b690e37bb3b8e5621..2eba0e43b9bf523bc5bfee0e945e08a3d397688a 100644 (file)
@@ -1884,6 +1884,8 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
            |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
          DECL_NO_CHECK_MEMORY_USAGE (newdecl)
            |= DECL_NO_CHECK_MEMORY_USAGE (olddecl);
+         DECL_NO_LIMIT_STACK (newdecl)
+           |= DECL_NO_LIMIT_STACK (olddecl);
        }
 
       pop_obstacks ();
index c7dc0088d49e71805b50acd6e412c4275dd0f0d5..0c9ae30028eccde5a19c64759d98ab24010689cf 100644 (file)
@@ -40,6 +40,7 @@ Boston, MA 02111-1307, USA.  */
 #include "except.h"
 #include "function.h"
 #include "recog.h"
+#include "toplev.h"
 #include <math.h>
 
 /* Save the operands last given to a compare for use when we
@@ -1431,6 +1432,34 @@ i960_function_prologue (file, size)
   actual_fsize = (actual_fsize + 15) & ~0xF;
 #endif
 
+  /* Check stack limit if necessary.  */
+  if (current_function_limit_stack)
+    {
+      rtx min_stack = stack_limit_rtx;
+      if (actual_fsize != 0)
+       min_stack = plus_constant (stack_limit_rtx, -actual_fsize);
+
+      /* Now, emulate a little bit of reload.  We want to turn 'min_stack'
+        into an arith_operand.  Use register 20 as the temporary.  */
+      if (legitimate_address_p (Pmode, min_stack, 1) 
+         && !arith_operand (min_stack, Pmode))
+       {
+         rtx tmp = gen_rtx_MEM (Pmode, min_stack);
+         fputs ("\tlda\t", file);
+         i960_print_operand (file, tmp, 0);
+         fputs (",r4\n", file);
+         min_stack = gen_rtx_REG (Pmode, 20);
+       }
+      if (arith_operand (min_stack, Pmode))
+       {
+         fputs ("\tcmpo\tsp,", file);
+         i960_print_operand (file, min_stack, 0);
+         fputs ("\n\tfaultge.f\n", file);
+       }
+      else
+       warning ("stack limit expression is not supported");
+    }
+
   /* Allocate space for register save and locals.  */
   if (actual_fsize > 0)
     {
@@ -1443,7 +1472,7 @@ i960_function_prologue (file, size)
   /* Take hardware register save area created by the call instruction
      into account, but store them before the argument block area.  */
   lvar_size = actual_fsize - compute_frame_size (0) - n_saved_regs * 4;
-  offset = 64 + lvar_size;
+  offset = STARTING_FRAME_OFFSET + lvar_size;
   /* Save registers on stack if needed.  */
   /* ??? Is it worth to use the same algorithm as one for saving
      global registers in local registers? */
index 1e5c1124f1057f10f06fdf0ee197c821d4f5ed72..38c14bae72a9ac4ed4ece62c07ed550c339caf2e 100644 (file)
   "cmp%S0%B0%X0        %2,%1,%l3"
   [(set_attr "type" "branch")])
 \f
+;; Now the trap instructions.  The i960 appears to only have conditional
+;; traps...
+
+(define_insn ("trap")
+  [(trap_if (const_int 1) (const_int 0))]
+  ""
+  "cmpo g0,g0 ; faulteq.t")
+
+(define_expand "conditional_trap"
+  [(trap_if (match_operator 0 "comparison_operator"
+            [(match_dup 2) (const_int 0)]) 
+           (match_operand 1 "const_int_operand" "i"))]
+  ""
+  "
+{
+  operands[2] = gen_compare_reg (GET_CODE (operands[0]), 
+                                i960_compare_op0, i960_compare_op1);
+}")
+
+(define_insn ""
+  [(trap_if (match_operator 0 "comparison_operator"
+            [(reg:CC 36) (const_int 0)]) 
+           (match_operand 1 "const_int_operand" "i"))]
+  ""
+  "fault%C0.f")
+
+(define_insn ""
+  [(trap_if (match_operator 0 "comparison_operator"
+            [(reg:CC_UNS 36) (const_int 0)]) 
+           (match_operand 1 "const_int_operand" "i"))]
+  ""
+  "fault%C0.f")
+\f
 ;; Normal move instructions.
 ;; This code is based on the sparc machine description.
 
index f718ccd4fd127ebe285f1ff6deb9a2a5f1e811d1..8a798b7df656ddaecb395b7a14275e0842e35d83 100644 (file)
@@ -151,6 +151,19 @@ output_function_prologue (stream, size)
   int fsize = (size + 3) & -4;
   int cfa_offset = INCOMING_FRAME_SP_OFFSET, cfa_store_offset = cfa_offset;
   
+  /* If the stack limit is a symbol, we can check it here,
+     before actually allocating the space.  */
+  if (current_function_limit_stack
+      && GET_CODE (stack_limit_rtx) == SYMBOL_REF)
+    {
+#if defined (MOTOROLA)
+      asm_fprintf (stream, "\tcmp.l %0I%s+%d,%Rsp\n\ttrapcs\n",
+                  XSTR (stack_limit_rtx, 0), fsize + 4);
+#else
+      asm_fprintf (stream, "\tcmpl %0I%s+%d,%Rsp\n\ttrapcs\n",
+                  XSTR (stack_limit_rtx, 0), fsize + 4);
+#endif
+    }
 
   if (frame_pointer_needed)
     {
@@ -374,6 +387,24 @@ output_function_prologue (stream, size)
 #endif
 #endif
 
+  /* If the stack limit is not a symbol, check it here.  
+     This has the disadvantage that it may be too late...  */
+  if (current_function_limit_stack)
+    {
+      if (REG_P (stack_limit_rtx))
+       {
+#if defined (MOTOROLA)
+         asm_fprintf (stream, "\tcmp.l %s,%Rsp\n\ttrapcs\n",
+                      reg_names[REGNO (stack_limit_rtx)]);
+#else
+         asm_fprintf (stream, "\tcmpl %s,%Rsp\n\ttrapcs\n",
+                      reg_names[REGNO (stack_limit_rtx)]);
+#endif
+       }
+      else if (GET_CODE (stack_limit_rtx) != SYMBOL_REF)
+       warning ("stack limit expression is not supported");
+    }
+  
   if (num_saved_regs <= 2)
     {
       /* Store each separately in the same order moveml uses.
index 8a952590ec59c86c63762d5391f1d7a94417ffc6..62177190667ea142ef1354c0fc30fb8f9a7b7ca0 100644 (file)
        (unspec:XF [(match_operand:XF 1 "nonimmediate_operand" "fm")] 2))]
   "TARGET_68881 && flag_fast_math"
   "fcos%.x %1,%0")
+
+(define_insn "trap"
+  [(trap_if (const_int -1) (const_int 7))]
+  ""
+  "trap %#7")
+
+(define_insn "conditional_trap"
+  [(trap_if (match_operator 0 "valid_dbcc_comparison_p"
+                           [(cc0) (const_int 0)])
+           (match_operand:SI 1 "const_int_operand" "I"))]
+  "TARGET_68020 && ! flags_in_68881 ()"
+  "*
+{
+  switch (GET_CODE (operands[0]))
+  {
+  case EQ:  return \"trapeq\";
+  case NE:  return \"trapne\";
+  case GT:  return \"trapgt\";
+  case GTU: return \"traphi\";
+  case LT:  return \"traplt\";
+  case LTU: return \"trapcs\";
+  case GE:  return \"trapge\";
+  case GEU: return \"trapcc\";
+  case LE:  return \"traple\";
+  case LEU: return \"trapls\";
+  default: abort();
+  }
+}")
index 250c8cd42d4e5f121fe47bba00ee94fd1b44c0af..a8db6d035c3a5d6008d6f90576dbfa313e87e223 100644 (file)
@@ -4176,6 +4176,53 @@ rs6000_allocate_stack_space (file, size, copy_r12)
      int copy_r12;
 {
   int neg_size = -size;
+
+  if (current_function_limit_stack)
+    {
+      if (REG_P (stack_limit_rtx)
+         && REGNO (stack_limit_rtx) > 1 
+         && REGNO (stack_limit_rtx) <= 31)
+       {
+         if (size <= 32767)
+           asm_fprintf (file, "\t{cal %s,%d(%s)|addi %s,%s,%d}\n",
+                        reg_names[0], reg_names[REGNO (stack_limit_rtx)], 
+                        size);
+         else
+           {
+             asm_fprintf (file, "\t{cau|addis} %s,%s,0x%x\n",
+                          reg_names[0], reg_names[REGNO (stack_limit_rtx)], 
+                          ((size + 0x8000) >> 16) & 0xffff);
+             asm_fprintf (file, "\t{ai|addic} %s,%s,%d\n",
+                          reg_names[0], reg_names[0], 
+                          (size & 0x7fff) | -(size & 0x8000));
+           }
+         if (TARGET_32BIT)
+           asm_fprintf (file, "\t{t|tw}llt %s,%s\n", 
+                        reg_names[1], reg_names[0]);
+         else
+           asm_fprintf (file, "\ttdllt %s,%s\n", reg_names[1], reg_names[0]);
+       }
+      else if (GET_CODE (stack_limit_rtx) == SYMBOL_REF
+              && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS))
+       {
+         char * l_name = XSTR (stack_limit_rtx, 0);
+         const char * stripped_name;
+
+         STRIP_NAME_ENCODING (stripped_name, l_name);
+         asm_fprintf (file, "\t{liu|lis} %s,%s@ha+%d\n",
+                      reg_names[0], stripped_name, size);
+         asm_fprintf (file, "\t{ai|addic} %s,%s,%s@l+%d\n",
+                      reg_names[0], reg_names[0], stripped_name, size);
+         if (TARGET_32BIT)
+           asm_fprintf (file, "\t{t|tw}llt %s,%s\n", 
+                        reg_names[1], reg_names[0]);
+         else
+           asm_fprintf (file, "\ttdllt %s,%s\n", reg_names[1], reg_names[0]);
+       }
+      else
+       warning ("stack limit expression is not supported");
+    }
+
   if (TARGET_UPDATE)
     {
       if (size < 32767)
index 8d6e85cb21b6247f2041e975c220a5ec6eea19a5..bde6369f184e9a422fe0a95f41f86415b708e46f 100644 (file)
 
   emit_move_insn (chain, stack_bot);
 
+  /* Check stack bounds if necessary.  */
+  if (current_function_limit_stack)
+    {
+      rtx available;
+      available = expand_binop (Pmode, sub_optab, 
+                               stack_pointer_rtx, stack_limit_rtx,
+                               NULL_RTX, 1, OPTAB_WIDEN);
+      emit_insn (gen_cond_trap (LTU, available, operands[1], const0_rtx));
+    }
+
   /* Under Windows NT, we need to add stack probes for large/variable
      allocations, so do it via a call to the external function alloca
      instead of doing it inline.  */
                              (match_operand:SI 2 "reg_or_short_operand" "rI")])
            (const_int 0))]
   ""
-  "t%V0%I2 %1,%2")
+  "{t|tw}%V0%I2 %1,%2")
+
+(define_insn ""
+  [(trap_if (match_operator 0 "trap_comparison_operator"
+                            [(match_operand:DI 1 "register_operand" "r")
+                             (match_operand:DI 2 "reg_or_short_operand" "rI")])
+           (const_int 0))]
+  "TARGET_POWERPC64"
+  "td%V0%I2 %1,%2")
index 5e34a578cbfe2c47d4cc0ae10ef915022631e7a7..a8b5235521466d6c2e6f6c70c9cf778880f2fc0d 100644 (file)
@@ -1,3 +1,10 @@
+1999-11-24  Geoffrey Keating  <geoffk@cygnus.com>
+            Greg McGary  <gkm@gnu.org>
+
+       * decl.c (duplicate_decls): Merge
+       DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT,
+       DECL_NO_CHECK_MEMORY_USAGE, DECL_NO_LIMIT_STACK.
+
 1999-12-02  Mike Stump  <mrs@wrs.com>
 
        * init.c (perform_member_init): Handle parse errors better.
index b05775b2bdd409774e3c54daf4b661e58cc226b5..deea199ddbdf6dafdfcb96097a17f158703e779c 100644 (file)
@@ -3364,6 +3364,16 @@ duplicate_decls (newdecl, olddecl)
 
       /* Keep the old rtl since we can safely use it.  */
       DECL_RTL (newdecl) = DECL_RTL (olddecl);
+
+      if (TREE_CODE (newdecl) == FUNCTION_DECL)
+       {
+         DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
+           |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
+         DECL_NO_CHECK_MEMORY_USAGE (newdecl)
+           |= DECL_NO_CHECK_MEMORY_USAGE (olddecl);
+         DECL_NO_LIMIT_STACK (newdecl)
+           |= DECL_NO_LIMIT_STACK (olddecl);
+       }
     }
   /* If cannot merge, then use the new type and qualifiers,
      and don't preserve the old rtl.  */
index 437c9352631022249f501c230a1c121a3f2e7984..ca4259a7fa4a18ace717d28b23834968cce7bbee 100644 (file)
@@ -1333,6 +1333,33 @@ allocate_dynamic_stack_space (size, target, known_align)
       emit_move_insn (target, virtual_stack_dynamic_rtx);
 #endif
       size = convert_modes (Pmode, ptr_mode, size, 1);
+
+      /* Check stack bounds if necessary.  */
+      if (current_function_limit_stack)
+       {
+         rtx available;
+         rtx space_available = gen_label_rtx ();
+#ifdef STACK_GROWS_DOWNWARD
+         available = expand_binop (Pmode, sub_optab, 
+                                   stack_pointer_rtx, stack_limit_rtx,
+                                   NULL_RTX, 1, OPTAB_WIDEN);
+#else
+         available = expand_binop (Pmode, sub_optab, 
+                                   stack_limit_rtx, stack_pointer_rtx,
+                                   NULL_RTX, 1, OPTAB_WIDEN);
+#endif
+         emit_cmp_and_jump_insns (available, size, GEU, NULL_RTX, Pmode, 1,
+                                  0, space_available);
+#ifdef HAVE_trap
+         if (HAVE_trap)
+           emit_insn (gen_trap ());
+         else
+#endif
+           error ("stack limits not supported on this target");
+         emit_barrier ();
+         emit_label (space_available);
+       }
+
       anti_adjust_stack (size);
 #ifdef SETJMP_VIA_SAVE_AREA
       if (setjmpless_size != NULL_RTX)
index c93784cdee6a5713741e55385ba17f3555ef6370..92d121cb6ed97182cf4349b0c19684c42e4adf93 100644 (file)
@@ -476,8 +476,8 @@ extern int flag_argument_noalias;
    if alias analysis (in general) is enabled.  */
 extern int flag_strict_aliasing;
 
-/* Emit code to check for stack overflow; also may cause large objects
-   to be allocated dynamically.  */
+/* Emit code to probe the stack, to help detect stack overflow; also
+   may cause large objects to be allocated dynamically.  */
 extern int flag_stack_check;
 
 /* Do the full regmove optimization pass.  */
index 7014a8b1b6c9d43126aa5af31a4c711a65f34ed7..587fdfffe7dfd923055fecf4ba905e0f83d85e31 100644 (file)
@@ -5946,6 +5946,9 @@ expand_function_start (subr, parms_have_cleanups)
     = (flag_instrument_function_entry_exit
        && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr));
 
+  current_function_limit_stack
+    = (stack_limit_rtx != NULL_RTX && ! DECL_NO_LIMIT_STACK (subr));
+
   /* If function gets a static chain arg, store it in the stack frame.
      Do this first, so it gets the first stack slot offset.  */
   if (current_function_needs_context)
index f476bbee93736f1794d7c1c49b995b1faef8175e..3c912bcf7ba5ca9c9c4bb558a13df43f7a80ce16 100644 (file)
@@ -290,6 +290,10 @@ struct function
   /* Nonzero if memory access checking be enabled in the current function.  */
   int check_memory_usage;
 
+  /* Nonzero if stack limit checking should be enabled in the current
+     function.  */
+  int limit_stack;
+
   /* Number of function calls seen so far in current function.  */
   int x_function_call_count;
 
@@ -490,6 +494,7 @@ extern struct function *all_functions;
 #define current_function_return_rtx (current_function->return_rtx)
 #define current_function_instrument_entry_exit (current_function->instrument_entry_exit)
 #define current_function_check_memory_usage (current_function->check_memory_usage)
+#define current_function_limit_stack (current_function->limit_stack)
 #define current_function_uses_pic_offset_table (current_function->uses_pic_offset_table)
 #define current_function_uses_const_pool (current_function->uses_const_pool)
 #define current_function_cannot_inline (current_function->cannot_inline)
index ea90467f4747fbd4127f370b65e15a17d53d548b..5e4eb757d27128dd3ed6d7fdfda1c25eb9321fde 100644 (file)
@@ -439,6 +439,7 @@ in the following sections.
 -freg-struct-return  -fshared-data  -fshort-enums
 -fshort-double  -fvolatile  -fvolatile-global -fvolatile-static
 -fverbose-asm -fpack-struct  -fstack-check
+-fstack-limit-register=@var{reg}  -fstack-limit-symbol=@var{sym}
 -fargument-alias  -fargument-noalias
 -fargument-noalias-global
 -fleading-underscore
@@ -7085,6 +7086,25 @@ environment with multiple threads, but only rarely need to specify it in
 a single-threaded environment since stack overflow is automatically
 detected on nearly all systems if there is only one stack.
 
+Note that this switch does not actually cause checking to be done; the
+operating system must do that.  The switch causes generation of code
+to ensure that the operating system sees the stack being extended.
+
+@item -fstack-limit-register=@var{reg}
+@itemx -fstack-limit-symbol=@var{sym}
+@itemx -fno-stack-limit
+Generate code to ensure that the stack does not grow beyond a certain value,
+either the value of a register or the address of a symbol.  If the stack
+would grow beyond the value, a signal is raised.  For most targets,
+the signal is raised before the stack overruns the boundary, so
+it is possible to catch the signal without taking special precautions.
+
+For instance, if the stack starts at address @samp{0x80000000} and grows
+downwards you can use the flags
+@samp{-fstack-limit-symbol=__stack_limit}
+@samp{-Wl,--defsym,__stack_limit=0x7ffe0000} which will enforce a stack
+limit of 128K.
+
 @cindex aliasing of parameters
 @cindex parameters, aliased
 @item -fargument-alias
index 2910473de026a8f9fe4816bd42ac96856b7ef584..483016794c822f52d9f3ef7fe0283f637618f718 100644 (file)
@@ -2549,6 +2549,29 @@ sibling call (aka tail call) sites.
 The @code{sibcall_epilogue} pattern must not clobber any arguments used for
 parameter passing or any stack slots for arguments passed to the current
 function.  
+
+@cindex @code{trap} instruction pattern
+@item @samp{trap}
+This pattern, if defined, signals an error, typically by causing some
+kind of signal to be raised.  Among other places, it is used by the Java
+frontend to signal `invalid array index' exceptions.
+
+@cindex @code{conditional_trap} instruction pattern
+@item @samp{conditional_trap}
+Conditional trap instruction.  Operand 0 is a piece of RTL which
+performs a comparison.  Operand 1 is the trap code, an integer.
+
+A typical @code{conditional_trap} pattern looks like
+
+@smallexample
+(define_insn "conditional_trap"
+  [(trap_if (match_operator 0 "trap_operator" 
+             [(cc0) (const_int 0)])
+            (match_operand 1 "const_int_operand" "i"))]
+  ""
+  "@dots{}")
+@end smallexample
+
 @end table
 
 @node Pattern Ordering
index db0a078c4303fef058182ac5e7d04d0a84ae4efc..5d80241969bc36e42e6ea91dc0b2a216537548d7 100644 (file)
@@ -4806,11 +4806,17 @@ gen_cond_trap (code, op1, op2, tcode)
       && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
     {
       rtx insn;
+      start_sequence();
       emit_insn (GEN_FCN (cmp_optab->handlers[(int) mode].insn_code) (op1, op2));
       PUT_CODE (trap_rtx, code);
       insn = gen_conditional_trap (trap_rtx, tcode);
       if (insn)
-       return insn;
+       {
+         emit_insn (insn);
+         insn = gen_sequence ();
+       }
+      end_sequence();
+      return insn;
     }
 #endif
 
index 136cb9248251542763687129f8fab0007eb5f6be..3677c4e967d03d2a6f81204781604590397c3d1f 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1576,6 +1576,8 @@ extern void reg_scan                      PROTO ((rtx, int, int));
 extern void reg_scan_update            PROTO ((rtx, rtx, int));
 extern void fix_register               PROTO ((const char *, int, int));
 
+extern void delete_null_pointer_checks PROTO ((rtx));
+
 /* In regmove.c */
 #ifdef BUFSIZ
 extern void regmove_optimize           PROTO ((rtx, int, FILE *));
@@ -1703,6 +1705,8 @@ extern rtx addr_side_effect_eval  PROTO ((rtx, int, int));
 extern int stack_regs_mentioned                PROTO((rtx insn));
 #endif
 
+/* In toplev.c */
+
+extern rtx stack_limit_rtx;
 
-extern void delete_null_pointer_checks PROTO ((rtx));
 #endif /* _RTL_H */
index 70ea2a15945b81841d1a6b13f482e5801e8c6ba2..fbbbb648916a2630ab4f111863f0a1fa732ce4ad 100644 (file)
@@ -720,6 +720,15 @@ int flag_pack_struct = 0;
    to be allocated dynamically.  */
 int flag_stack_check;
 
+/* When non-NULL, indicates that whenever space is allocated on the
+   stack, the resulting stack pointer must not pass this
+   address---that is, for stacks that grow downward, the stack pointer
+   must always be greater than or equal to this address; for stacks
+   that grow upward, the stack pointer must be less than this address.
+   At present, the rtx may be either a REG or a SYMBOL_REF, although
+   the support provided depends on the backend.  */
+rtx stack_limit_rtx;
+
 /* -fcheck-memory-usage causes extra code to be generated in order to check
    memory accesses.  This is used by a detector of bad memory accesses such
    as Checker.  */
@@ -4889,6 +4898,25 @@ decode_f_option (arg)
     align_jumps = read_integral_parameter (arg + 12, arg - 2, align_jumps);
   else if (!strncmp (arg, "align-labels=", 13))
     align_labels = read_integral_parameter (arg + 13, arg - 2, align_labels);
+  else if (!strncmp (arg, "stack-limit-register=", 21))
+    {
+      int reg = decode_reg_name (arg + 21);
+      if (reg < 0)
+       error ("unrecognized register name `%s'", arg + 21);
+      else
+       stack_limit_rtx = gen_rtx_REG (Pmode, reg);
+    }
+  else if (!strncmp (arg, "stack-limit-symbol=", 19))
+    {
+      char *nm;
+      if (ggc_p)
+       nm = ggc_alloc_string (arg + 19, strlen (arg + 19));
+      else
+       nm = xstrdup (arg + 19);
+      stack_limit_rtx = gen_rtx_SYMBOL_REF (Pmode, nm);
+    }
+  else if (!strcmp (arg, "no-stack-limit"))
+    stack_limit_rtx = NULL_RTX;
   else if (!strcmp (arg, "preprocessed"))
     /* Recognise this switch but do nothing.  This prevents warnings
        about an unrecognised switch if cpplib has not been linked in.  */
@@ -5323,6 +5351,7 @@ main (argc, argv)
   init_ggc ();
   ggc_add_root (&input_file_stack, 1, sizeof input_file_stack,
                &mark_file_stack);
+  ggc_add_rtx_root (&stack_limit_rtx, 1);
 
   /* Perform language-specific options intialization.  */
   lang_init_options ();
index fcfa2190b362bdc36846d9b11dd144ffeca5d33a..7d181607a51b930cf14e91b818395cc269591e38 100644 (file)
@@ -1307,6 +1307,10 @@ struct tree_type
    disabled in this function.  */
 #define DECL_NO_CHECK_MEMORY_USAGE(NODE) ((NODE)->decl.no_check_memory_usage)
 
+/* Used in FUNCTION_DECLs to indicate that limit-stack-* should be
+   disabled in this function.  */
+#define DECL_NO_LIMIT_STACK(NODE) ((NODE)->decl.no_limit_stack)
+
 /* Additional flags for language-specific uses.  */
 #define DECL_LANG_FLAG_0(NODE) (DECL_CHECK (NODE)->decl.lang_flag_0)
 #define DECL_LANG_FLAG_1(NODE) (DECL_CHECK (NODE)->decl.lang_flag_1)
@@ -1376,6 +1380,7 @@ struct tree_decl
   unsigned no_check_memory_usage : 1;
   unsigned comdat_flag : 1;
   unsigned malloc_flag : 1;
+  unsigned no_limit_stack : 1;
 
   /* For a FUNCTION_DECL, if inline, this is the size of frame needed.
      If built-in, this is the code for which built-in function.