Patch for stack bounds checking (supported on ppc, m68k, i960).

Geoff Keating geoffk@ozemail.com.au
Tue Nov 23 22:52:00 GMT 1999


This patch does stack bounds checking against either a register or a
symbol (the register is more useful in a threaded environment).  It
would have been easy except that:

- It needs to be done in the prologue, so it needs to be written for
  each machine; and
- It relies on the existence of a 'trap' pattern, which doesn't seem
  to be implemented/working for many ports.  I added a test case
  and some documentation to help port maintainers with this.

I have here implementations for ppc, m68k, and i960.  I'd appreciate
it if the port maintainers could look at those.  I've given it
extensive testing on ppc, and less on m68k and i960.

I'd like to make it work on a29k, but I don't know how and can't find
any documentation.  Does anyone have any suggestions?  I know there
_is_ a conditional-trap instruction, but don't know how it works.

-- 
Geoffrey Keating <geoffk@cygnus.com>

===File ~/patches/cygnus/ascend-stackcheck-2.patch==========
md5sum: e9ec01053e8ccaa9 8c00db303528cd6b 552265
Index: egcs/gcc/cp/ChangeLog
0a
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.

.
md5sum: 8a271cbb67117d2d c6843b0258f775e9 453152
Index: egcs/gcc/ChangeLog
0a
Wed Nov 24 00:26:12 1999  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.

.
md5sum: 1c337c1a246b3354 245800e6cb812674 124659
Index: egcs/gcc/testsuite/ChangeLog
0a
1999-11-23  Geoffrey Keating  <geoffk@cygnus.com>

	* gcc.c-torture/compile/991123-1.c: New test.

.
Changed files:
egcs/gcc/cp/ChangeLog
egcs/gcc/ChangeLog
egcs/gcc/testsuite/ChangeLog
egcs/gcc/cp/decl.c
egcs/gcc/c-common.c
egcs/gcc/c-decl.c
egcs/gcc/explow.c
egcs/gcc/flags.h
egcs/gcc/function.c
egcs/gcc/function.h
egcs/gcc/invoke.texi
egcs/gcc/md.texi
egcs/gcc/optabs.c
egcs/gcc/rtl.h
egcs/gcc/toplev.c
egcs/gcc/tree.h
egcs/gcc/config/i960/i960.c
egcs/gcc/config/i960/i960.md
egcs/gcc/config/m68k/m68k.c
egcs/gcc/config/m68k/m68k.h
egcs/gcc/config/m68k/m68k.md
egcs/gcc/config/rs6000/rs6000.c
egcs/gcc/config/rs6000/rs6000.md
egcs/gcc/testsuite/gcc.c-torture/compile/991123-1.c
md5sum: 7c7350c24b97785f 13308f9770b4b5e8 440396
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/cp/decl.c	Sun Nov 21 17:04:32 1999
+++ egcs/gcc/cp/decl.c	Tue Nov 23 16:57:47 1999
@@ -3365,6 +3365,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.  */
md5sum: fce864eaecdb5689 802927844dd28a1b 123895
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/c-common.c	Mon Nov  1 12:45:05 1999
+++ egcs/gcc/c-common.c	Wed Nov 24 00:26:12 1999
@@ -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_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS,
+	    A_NO_LIMIT_STACK};
 
 enum format_type { printf_format_type, scanf_format_type,
 		   strftime_format_type };
@@ -481,6 +482,7 @@ init_attributes ()
   add_attribute (A_ALIAS, "alias", 1, 1, 1);
   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_NO_LIMIT_STACK, "no_stack_limit", 0, 0, 1);
 }
 
 /* Default implementation of valid_lang_attribute, below.  By default, there
@@ -1029,6 +1031,23 @@ decl_attributes (node, attributes, prefi
 	    }
 	  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;
 	}
     }
md5sum: fc651f0ee00310f7 f777fab0a109fd91 224556
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/c-decl.c	Thu Nov  4 13:47:42 1999
+++ egcs/gcc/c-decl.c	Tue Nov 23 16:55:40 1999
@@ -1884,6 +1884,8 @@ duplicate_decls (newdecl, olddecl, diffe
 	    |= 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 ();
md5sum: aded7fe77fce68f8 7bbb9a470b18fc95 46197
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/explow.c	Wed Nov 17 13:35:52 1999
+++ egcs/gcc/explow.c	Tue Nov 23 23:10:31 1999
@@ -1333,6 +1333,33 @@ allocate_dynamic_stack_space (size, targ
       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)
md5sum: 239e5c883e5cc5d8 dfa64ff73633b1df 18075
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/flags.h	Fri Nov  5 10:45:44 1999
+++ egcs/gcc/flags.h	Wed Nov 24 00:35:47 1999
@@ -468,8 +468,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.  */
md5sum: 98c4266db33a45ca c3a0e060f79ffcf9 216937
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/function.c	Fri Nov 19 10:36:01 1999
+++ egcs/gcc/function.c	Tue Nov 23 17:01:35 1999
@@ -5946,6 +5946,9 @@ expand_function_start (subr, parms_have_
     = (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)
md5sum: 0d9322b6834c043f 7f33966ad4a7b67d 23745
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/function.h	Sat Nov  6 15:21:59 1999
+++ egcs/gcc/function.h	Tue Nov 23 17:00:49 1999
@@ -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)
md5sum: 3a129172fcc9e803 d128c7d43095ce02 293779
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/invoke.texi	Mon Nov 22 11:51:21 1999
+++ egcs/gcc/invoke.texi	Wed Nov 24 15:05:27 1999
@@ -435,6 +435,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
@@ -7026,6 +7027,25 @@ Generate code to verify that you do not 
 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
md5sum: 246c64998ff3c385 05a0d116614c98a8 171814
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/md.texi	Mon Oct 11 13:25:58 1999
+++ egcs/gcc/md.texi	Tue Nov 23 22:31:48 1999
@@ -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
md5sum: 0ad502fca1e0e9b4 2ad7068c95c44c59 141468
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/optabs.c	Mon Nov  1 12:45:14 1999
+++ egcs/gcc/optabs.c	Wed Nov 24 00:16:25 1999
@@ -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
 
md5sum: aeccac50f0372106 2c10d63403eeaf67 69261
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/rtl.h	Mon Nov 22 11:51:22 1999
+++ egcs/gcc/rtl.h	Tue Nov 23 20:38:17 1999
@@ -1576,6 +1576,8 @@ extern void reg_scan			PROTO ((rtx, 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 (
 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 */
md5sum: 9df75914da02bc50 b9a72f0f72751cdd 164191
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/toplev.c	Mon Nov 22 11:51:22 1999
+++ egcs/gcc/toplev.c	Wed Nov 24 01:25:55 1999
@@ -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.  */
@@ -4884,6 +4893,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.  */
@@ -5318,6 +5346,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 ();
md5sum: 7a47b3a80f001989 490339ebba716967 97185
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/tree.h	Sun Nov 14 16:28:44 1999
+++ egcs/gcc/tree.h	Tue Nov 23 16:54:36 1999
@@ -1302,6 +1302,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)
@@ -1370,6 +1374,7 @@ struct tree_decl
   unsigned no_instrument_function_entry_exit : 1;
   unsigned no_check_memory_usage : 1;
   unsigned comdat_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.
md5sum: b823de59d6142c31 ec75712de59d7b33 74151
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/config/i960/i960.c	Sun Nov 14 16:28:50 1999
+++ egcs/gcc/config/i960/i960.c	Wed Nov 24 16:27:41 1999
@@ -40,6 +40,7 @@ the Free Software Foundation, 59 Temple 
 #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 @@ static int
   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 @@ static int
   /* 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? */
md5sum: a595d1e083331885 1f98fd640e8dd9bd 83401
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/config/i960/i960.md	Fri Oct 15 18:39:48 1999
+++ egcs/gcc/config/i960/i960.md	Wed Nov 24 16:38:34 1999
@@ -540,6 +540,39 @@ (define_insn ""
   "cmp%S0%B0%X0	%2,%1,%l3"
   [(set_attr "type" "branch")])
 
+;; 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")
+
 ;; Normal move instructions.
 ;; This code is based on the sparc machine description.
 
md5sum: 2707739ef9d24cad f0f0ae9845783ed2 96842
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/config/m68k/m68k.c	Wed Oct  6 13:48:15 1999
+++ egcs/gcc/config/m68k/m68k.c	Tue Nov 23 23:42:01 1999
@@ -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, "\tcmp.l %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.
md5sum: 60940716816402f8 60940716816402f8 83663
md5sum: 682703b591c9cf4a 90a69ef5ee9cce35 227607
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/config/m68k/m68k.md	Fri Oct 15 18:39:48 1999
+++ egcs/gcc/config/m68k/m68k.md	Wed Nov 24 00:07:10 1999
@@ -7897,3 +7897,31 @@ (define_insn "cosxf2"
 	(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();
+  }
+}")
md5sum: d8c2013bf73ed0e6 a5e2afb8165ffc44 176707
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/config/rs6000/rs6000.c	Tue Nov 16 14:37:37 1999
+++ egcs/gcc/config/rs6000/rs6000.c	Tue Nov 23 21:42:08 1999
@@ -4176,6 +4176,53 @@ debug_stack_info (info)
      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)
md5sum: fd8de47ac12278a9 386e676807fc966d 359783
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/config/rs6000/rs6000.md	Thu Oct 28 10:15:32 1999
+++ egcs/gcc/config/rs6000/rs6000.md	Tue Nov 23 21:54:45 1999
@@ -7877,6 +7877,16 @@ (define_expand "allocate_stack"
 
   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.  */
@@ -11146,4 +11156,12 @@ (define_insn ""
                              (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")
--- /dev/null	Wed Nov 24 16:48:01 1999
+++ egcs/gcc/testsuite/gcc.c-torture/compile/991123-1.c	Tue Nov 23 18:04:27 1999
@@ -0,0 +1,29 @@
+void perhaps_trap (int a, unsigned b, int c, unsigned d)
+{
+  if (a > 10)
+    __builtin_trap();
+  if (a == 3)
+    __builtin_trap();
+  if (a < 2)
+    __builtin_trap();
+  if (b > 10)
+    __builtin_trap();
+  if (b == 3)
+    __builtin_trap();
+  if (b < 2)
+    __builtin_trap();
+  if (c >= 10)
+    __builtin_trap();
+  if (c <= 2)
+    __builtin_trap();
+  if (d >= 10)
+    __builtin_trap();
+  if (d <= 2)
+    __builtin_trap();
+}
+
+void no_perhaps_trap (void)
+{
+  __builtin_trap();
+}
+
============================================================


More information about the Gcc-patches mailing list