From a157febd0ca69d5b4570fc714c141fd5da555a7a Mon Sep 17 00:00:00 2001 From: Geoff Keating Date: Sat, 4 Dec 1999 03:00:04 +0000 Subject: [PATCH] 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 From-SVN: r30771 --- gcc/ChangeLog | 48 +++++++++++++++++++++++++++++++++++++ gcc/c-common.c | 21 +++++++++++++++- gcc/c-decl.c | 2 ++ gcc/config/i960/i960.c | 31 +++++++++++++++++++++++- gcc/config/i960/i960.md | 33 +++++++++++++++++++++++++ gcc/config/m68k/m68k.c | 31 ++++++++++++++++++++++++ gcc/config/m68k/m68k.md | 28 ++++++++++++++++++++++ gcc/config/rs6000/rs6000.c | 47 ++++++++++++++++++++++++++++++++++++ gcc/config/rs6000/rs6000.md | 20 +++++++++++++++- gcc/cp/ChangeLog | 7 ++++++ gcc/cp/decl.c | 10 ++++++++ gcc/explow.c | 27 +++++++++++++++++++++ gcc/flags.h | 4 ++-- gcc/function.c | 3 +++ gcc/function.h | 5 ++++ gcc/invoke.texi | 20 ++++++++++++++++ gcc/md.texi | 23 ++++++++++++++++++ gcc/optabs.c | 8 ++++++- gcc/rtl.h | 6 ++++- gcc/toplev.c | 29 ++++++++++++++++++++++ gcc/tree.h | 5 ++++ 21 files changed, 401 insertions(+), 7 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2fbc0721964..5e5489ab740 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,51 @@ +1999-12-04 Geoffrey Keating + Greg McGary + + * 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 Geoffrey Keating diff --git a/gcc/c-common.c b/gcc/c-common.c index 10c16240284..866f53fa728 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 39ec85666e6..2eba0e43b9b 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 c7dc0088d49..0c9ae30028e 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 /* 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 1e5c1124f10..38c14bae72a 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 f718ccd4fd1..8a798b7df65 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 8a952590ec5..62177190667 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 250c8cd42d4..a8db6d035c3 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 8d6e85cb21b..bde6369f184 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 5e34a578cbf..a8b52355214 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +1999-11-24 Geoffrey Keating + Greg McGary + + * 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 * init.c (perform_member_init): Handle parse errors better. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index b05775b2bdd..deea199ddbd 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 437c9352631..ca4259a7fa4 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 c93784cdee6..92d121cb6ed 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 7014a8b1b6c..587fdfffe7d 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 f476bbee937..3c912bcf7ba 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 ea90467f474..5e4eb757d27 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 2910473de02..483016794c8 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 db0a078c430..5d80241969b 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 136cb924825..3677c4e967d 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 70ea2a15945..fbbbb648916 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 fcfa2190b36..7d181607a51 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. -- 2.30.2