aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorGeoff Keating <geoffk@cygnus.com>1999-12-04 03:00:04 +0000
committerGeoffrey Keating <geoffk@gcc.gnu.org>1999-12-04 03:00:04 +0000
commita157febd0ca69d5b4570fc714c141fd5da555a7a (patch)
tree9c9c8b5fa8e01f95d849e7b0f24402c7081b73d4 /gcc
parent3c12fcc27809a223032e1b0ad2beba1f6844a5c6 (diff)
downloadgcc-a157febd0ca69d5b4570fc714c141fd5da555a7a.zip
gcc-a157febd0ca69d5b4570fc714c141fd5da555a7a.tar.gz
gcc-a157febd0ca69d5b4570fc714c141fd5da555a7a.tar.bz2
c-common.c (enum attrs): Add A_NO_LIMIT_STACK.
* 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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog48
-rw-r--r--gcc/c-common.c21
-rw-r--r--gcc/c-decl.c2
-rw-r--r--gcc/config/i960/i960.c31
-rw-r--r--gcc/config/i960/i960.md33
-rw-r--r--gcc/config/m68k/m68k.c31
-rw-r--r--gcc/config/m68k/m68k.md28
-rw-r--r--gcc/config/rs6000/rs6000.c47
-rw-r--r--gcc/config/rs6000/rs6000.md20
-rw-r--r--gcc/cp/ChangeLog7
-rw-r--r--gcc/cp/decl.c10
-rw-r--r--gcc/explow.c27
-rw-r--r--gcc/flags.h4
-rw-r--r--gcc/function.c3
-rw-r--r--gcc/function.h5
-rw-r--r--gcc/invoke.texi20
-rw-r--r--gcc/md.texi23
-rw-r--r--gcc/optabs.c8
-rw-r--r--gcc/rtl.h6
-rw-r--r--gcc/toplev.c29
-rw-r--r--gcc/tree.h5
21 files changed, 401 insertions, 7 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2fbc072..5e5489a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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>
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 10c1624..866f53f 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -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);
}
/* 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;
}
}
}
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 39ec856..2eba0e4 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -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 ();
diff --git a/gcc/config/i960/i960.c b/gcc/config/i960/i960.c
index c7dc008..0c9ae30 100644
--- a/gcc/config/i960/i960.c
+++ b/gcc/config/i960/i960.c
@@ -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? */
diff --git a/gcc/config/i960/i960.md b/gcc/config/i960/i960.md
index 1e5c112..38c14ba 100644
--- a/gcc/config/i960/i960.md
+++ b/gcc/config/i960/i960.md
@@ -540,6 +540,39 @@
"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.
diff --git a/gcc/config/m68k/m68k.c b/gcc/config/m68k/m68k.c
index f718ccd..8a798b7 100644
--- a/gcc/config/m68k/m68k.c
+++ b/gcc/config/m68k/m68k.c
@@ -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.
diff --git a/gcc/config/m68k/m68k.md b/gcc/config/m68k/m68k.md
index 8a95259..6217719 100644
--- a/gcc/config/m68k/m68k.md
+++ b/gcc/config/m68k/m68k.md
@@ -7897,3 +7897,31 @@
(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();
+ }
+}")
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 250c8cd..a8db6d0 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -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)
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 8d6e85c..bde6369 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -7882,6 +7882,16 @@
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. */
@@ -11151,4 +11161,12 @@
(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")
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 5e34a57..a8b5235 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b05775b..deea199 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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. */
diff --git a/gcc/explow.c b/gcc/explow.c
index 437c935..ca4259a 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -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)
diff --git a/gcc/flags.h b/gcc/flags.h
index c93784c..92d121c 100644
--- a/gcc/flags.h
+++ b/gcc/flags.h
@@ -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. */
diff --git a/gcc/function.c b/gcc/function.c
index 7014a8b..587fdff 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -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)
diff --git a/gcc/function.h b/gcc/function.h
index f476bbe..3c912bc 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -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)
diff --git a/gcc/invoke.texi b/gcc/invoke.texi
index ea90467..5e4eb75 100644
--- a/gcc/invoke.texi
+++ b/gcc/invoke.texi
@@ -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
diff --git a/gcc/md.texi b/gcc/md.texi
index 2910473..4830167 100644
--- a/gcc/md.texi
+++ b/gcc/md.texi
@@ -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
diff --git a/gcc/optabs.c b/gcc/optabs.c
index db0a078..5d80241 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -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
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 136cb92..3677c4e 100644
--- 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 */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 70ea2a1..fbbbb64 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -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 ();
diff --git a/gcc/tree.h b/gcc/tree.h
index fcfa219..7d18160 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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.