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
This commit is contained in:
parent
3c12fcc278
commit
a157febd0c
@ -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>
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 ();
|
||||
|
@ -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? */
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
}")
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
|
@ -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.
|
||||
|
@ -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. */
|
||||
|
27
gcc/explow.c
27
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)
|
||||
|
@ -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. */
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
23
gcc/md.texi
23
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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
|
29
gcc/toplev.c
29
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 ();
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user