calls.c (ECF_SP_DEPRESSED): New macro.
* calls.c (ECF_SP_DEPRESSED): New macro. (calls_function_1): Treat calling sp-depressed function as alloca. (emit_call_1): Don't adjust SP if calling sp-depressed function. (expand_call): Set ECF_SP_DEPRESSED if TYPE_RETURNS_STACK_DEPRESSED. If sp-depressed, ensure block saves and restores SP. * fold-const.c (extract_muldiv): Only check TYPE_IS_SIZETYPE for INTEGER_TYPE. * function.c (keep_stack_depressed): New function. (thread_prologue_and_epilogue_insns): Call it. * print-tree.c (print_node): Use HOST_WIDE_INT_PRINT_UNSIGNED to print DECL_OFFSET_ALIGN. Print no-force-blk and transparent-union flags properly. * stmt.c (expand_goto_internal): Don't restore stack if last block and function returns with sp depressed. (fixup_gotos): Likewise. (save_stack_pointer): New function, from code in expand_decl. (expand_decl): Call new function. * tree.h (TYPE_IS_SIZETYPE): Call INTEGER_TYPE_CHECK. (TYPE_RETURNS_STACK_DEPRESSED): New macro. (save_stack_pointer): New declaration. From-SVN: r35734
This commit is contained in:
parent
81baa09a56
commit
7393c6422b
|
@ -1,5 +1,26 @@
|
|||
Tue Aug 15 17:33:05 2000 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
|
||||
|
||||
* calls.c (ECF_SP_DEPRESSED): New macro.
|
||||
(calls_function_1): Treat calling sp-depressed function as alloca.
|
||||
(emit_call_1): Don't adjust SP if calling sp-depressed function.
|
||||
(expand_call): Set ECF_SP_DEPRESSED if TYPE_RETURNS_STACK_DEPRESSED.
|
||||
If sp-depressed, ensure block saves and restores SP.
|
||||
* fold-const.c (extract_muldiv): Only check TYPE_IS_SIZETYPE
|
||||
for INTEGER_TYPE.
|
||||
* function.c (keep_stack_depressed): New function.
|
||||
(thread_prologue_and_epilogue_insns): Call it.
|
||||
* print-tree.c (print_node): Use HOST_WIDE_INT_PRINT_UNSIGNED
|
||||
to print DECL_OFFSET_ALIGN.
|
||||
Print no-force-blk and transparent-union flags properly.
|
||||
* stmt.c (expand_goto_internal): Don't restore stack if last block
|
||||
and function returns with sp depressed.
|
||||
(fixup_gotos): Likewise.
|
||||
(save_stack_pointer): New function, from code in expand_decl.
|
||||
(expand_decl): Call new function.
|
||||
* tree.h (TYPE_IS_SIZETYPE): Call INTEGER_TYPE_CHECK.
|
||||
(TYPE_RETURNS_STACK_DEPRESSED): New macro.
|
||||
(save_stack_pointer): New declaration.
|
||||
|
||||
* diagnostic.c (fatal_function): New variable.
|
||||
(set_fatal_function): New function.
|
||||
(fatal): Call it.
|
||||
|
|
44
gcc/calls.c
44
gcc/calls.c
|
@ -184,6 +184,9 @@ static int calls_function_1 PARAMS ((tree, int));
|
|||
/* Nonzero if this is a call to "pure" function (like const function,
|
||||
but may read memory. */
|
||||
#define ECF_PURE 512
|
||||
/* Nonzero if this is a call to a function that returns with the stack
|
||||
pointer depressed. */
|
||||
#define ECF_SP_DEPRESSED 1024
|
||||
|
||||
static void emit_call_1 PARAMS ((rtx, tree, tree, HOST_WIDE_INT,
|
||||
HOST_WIDE_INT, HOST_WIDE_INT, rtx,
|
||||
|
@ -278,6 +281,9 @@ calls_function_1 (exp, which)
|
|||
case CALL_EXPR:
|
||||
if (which == 0)
|
||||
return 1;
|
||||
else if (TYPE_RETURNS_STACK_DEPRESSED
|
||||
(TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
|
||||
return 1;
|
||||
else if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
|
||||
&& (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
|
||||
== FUNCTION_DECL)
|
||||
|
@ -428,8 +434,8 @@ prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen)
|
|||
We restore `inhibit_defer_pop' to that value.
|
||||
|
||||
CALL_FUSAGE is either empty or an EXPR_LIST of USE expressions that
|
||||
denote registers used by the called function. */
|
||||
|
||||
denote registers used by the called function. */
|
||||
|
||||
static void
|
||||
emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
|
||||
struct_value_size, next_arg_reg, valreg, old_inhibit_defer_pop,
|
||||
|
@ -495,7 +501,7 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
|
|||
even if the call has no arguments to pop. */
|
||||
#if defined (HAVE_call) && defined (HAVE_call_value)
|
||||
if (HAVE_call && HAVE_call_value && HAVE_call_pop && HAVE_call_value_pop
|
||||
&& n_popped > 0)
|
||||
&& n_popped > 0 && ! (ecf_flags & ECF_SP_DEPRESSED))
|
||||
#else
|
||||
if (HAVE_call_pop && HAVE_call_value_pop)
|
||||
#endif
|
||||
|
@ -624,10 +630,10 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
|
|||
If returning from the subroutine does pop the args, indicate that the
|
||||
stack pointer will be changed. */
|
||||
|
||||
if (rounded_stack_size != 0)
|
||||
if (rounded_stack_size != 0 && ! (ecf_flags & ECF_SP_DEPRESSED))
|
||||
{
|
||||
if (flag_defer_pop && inhibit_defer_pop == 0
|
||||
&& !(ecf_flags & (ECF_CONST | ECF_PURE)))
|
||||
&& ! (ecf_flags & (ECF_CONST | ECF_PURE)))
|
||||
pending_stack_adjust += rounded_stack_size;
|
||||
else
|
||||
adjust_stack (rounded_stack_size_rtx);
|
||||
|
@ -756,6 +762,7 @@ special_function_p (fndecl, flags)
|
|||
}
|
||||
|
||||
/* Return nonzero when tree represent call to longjmp. */
|
||||
|
||||
int
|
||||
setjmp_call_p (fndecl)
|
||||
tree fndecl;
|
||||
|
@ -764,11 +771,13 @@ setjmp_call_p (fndecl)
|
|||
}
|
||||
|
||||
/* Detect flags (function attributes) from the function type node. */
|
||||
|
||||
static int
|
||||
flags_from_decl_or_type (exp)
|
||||
tree exp;
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
/* ??? We can't set IS_MALLOC for function types? */
|
||||
if (DECL_P (exp))
|
||||
{
|
||||
|
@ -784,7 +793,7 @@ flags_from_decl_or_type (exp)
|
|||
flags |= ECF_NOTHROW;
|
||||
}
|
||||
|
||||
if (TREE_READONLY (exp) && !TREE_THIS_VOLATILE (exp))
|
||||
if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
|
||||
flags |= ECF_CONST;
|
||||
|
||||
if (TREE_THIS_VOLATILE (exp))
|
||||
|
@ -2131,7 +2140,7 @@ expand_call (exp, target, ignore)
|
|||
int old_inhibit_defer_pop = inhibit_defer_pop;
|
||||
int old_stack_allocated;
|
||||
rtx call_fusage;
|
||||
register tree p;
|
||||
register tree p = TREE_OPERAND (exp, 0);
|
||||
register int i;
|
||||
/* The alignment of the stack, in bits. */
|
||||
HOST_WIDE_INT preferred_stack_boundary;
|
||||
|
@ -2183,9 +2192,13 @@ expand_call (exp, target, ignore)
|
|||
/* If we don't have specific function to call, see if we have a
|
||||
attributes set in the type. */
|
||||
else
|
||||
flags |= flags_from_decl_or_type (TREE_TYPE (TREE_TYPE (p)));
|
||||
|
||||
/* Mark if the function returns with the stack pointer depressed. */
|
||||
if (TYPE_RETURNS_STACK_DEPRESSED (TREE_TYPE (TREE_TYPE (p))))
|
||||
{
|
||||
p = TREE_OPERAND (exp, 0);
|
||||
flags |= flags_from_decl_or_type (TREE_TYPE (TREE_TYPE (p)));
|
||||
flags |= ECF_SP_DEPRESSED;
|
||||
flags &= ~ (ECF_PURE | ECF_CONST);
|
||||
}
|
||||
|
||||
#ifdef REG_PARM_STACK_SPACE
|
||||
|
@ -3271,7 +3284,7 @@ expand_call (exp, target, ignore)
|
|||
/* If size of args is variable or this was a constructor call for a stack
|
||||
argument, restore saved stack-pointer value. */
|
||||
|
||||
if (old_stack_level)
|
||||
if (old_stack_level && ! (flags & ECF_SP_DEPRESSED))
|
||||
{
|
||||
emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
|
||||
pending_stack_adjust = old_pending_adj;
|
||||
|
@ -3412,6 +3425,17 @@ expand_call (exp, target, ignore)
|
|||
|
||||
currently_expanding_call--;
|
||||
|
||||
/* If this function returns with the stack pointer depressed, ensure
|
||||
this block saves and restores the stack pointer, show it was
|
||||
changed, and adjust for any outgoing arg space. */
|
||||
if (flags & ECF_SP_DEPRESSED)
|
||||
{
|
||||
clear_pending_stack_adjust ();
|
||||
emit_insn (gen_rtx (CLOBBER, VOIDmode, stack_pointer_rtx));
|
||||
emit_move_insn (virtual_stack_dynamic_rtx, stack_pointer_rtx);
|
||||
save_stack_pointer ();
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
|
|
@ -4402,7 +4402,8 @@ extract_muldiv (t, c, code, wide_type)
|
|||
|| TREE_CODE_CLASS (TREE_CODE (op0)) == '2'
|
||||
|| TREE_CODE_CLASS (TREE_CODE (op0)) == 'e')
|
||||
&& TREE_UNSIGNED (TREE_TYPE (op0))
|
||||
&& ! TYPE_IS_SIZETYPE (TREE_TYPE (op0))
|
||||
&& ! (TREE_CODE (TREE_TYPE (op0)) == INTEGER_TYPE
|
||||
&& TYPE_IS_SIZETYPE (TREE_TYPE (op0)))
|
||||
&& (GET_MODE_SIZE (TYPE_MODE (ctype))
|
||||
> GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))))
|
||||
break;
|
||||
|
@ -4527,7 +4528,7 @@ extract_muldiv (t, c, code, wide_type)
|
|||
the operation since it will change the result if the original
|
||||
computation overflowed. */
|
||||
if (TREE_UNSIGNED (ctype)
|
||||
&& ! TYPE_IS_SIZETYPE (ctype)
|
||||
&& ! (TREE_CODE (ctype) == INTEGER_TYPE && TYPE_IS_SIZETYPE (ctype))
|
||||
&& ctype != type)
|
||||
break;
|
||||
|
||||
|
@ -4591,7 +4592,7 @@ extract_muldiv (t, c, code, wide_type)
|
|||
this since it will change the result if the original computation
|
||||
overflowed. */
|
||||
if ((! TREE_UNSIGNED (ctype)
|
||||
|| TYPE_IS_SIZETYPE (ctype))
|
||||
|| (TREE_CODE (ctype) == INTEGER_TYPE && TYPE_IS_SIZETYPE (ctype)))
|
||||
&& ((code == MULT_EXPR && tcode == EXACT_DIV_EXPR)
|
||||
|| (tcode == MULT_EXPR
|
||||
&& code != TRUNC_MOD_EXPR && code != CEIL_MOD_EXPR
|
||||
|
|
|
@ -294,6 +294,9 @@ static void emit_return_into_block PARAMS ((basic_block, rtx));
|
|||
static void put_addressof_into_stack PARAMS ((rtx, struct hash_table *));
|
||||
static boolean purge_addressof_1 PARAMS ((rtx *, rtx, int, int,
|
||||
struct hash_table *));
|
||||
#ifdef HAVE_epilogue
|
||||
static void keep_stack_depressed PARAMS ((rtx));
|
||||
#endif
|
||||
static int is_addressof PARAMS ((rtx *, void *));
|
||||
static struct hash_entry *insns_for_mem_newfunc PARAMS ((struct hash_entry *,
|
||||
struct hash_table *,
|
||||
|
@ -6808,6 +6811,68 @@ emit_return_into_block (bb, line_note)
|
|||
}
|
||||
#endif /* HAVE_return */
|
||||
|
||||
#ifdef HAVE_epilogue
|
||||
|
||||
/* Modify SEQ, a SEQUENCE that is part of the epilogue, to no modifications
|
||||
to the stack pointer. */
|
||||
|
||||
static void
|
||||
keep_stack_depressed (seq)
|
||||
rtx seq;
|
||||
{
|
||||
int i;
|
||||
rtx sp_from_reg = 0;
|
||||
int sp_modified_unknown = 0;
|
||||
|
||||
/* If the epilogue is just a single instruction, it's OK as is */
|
||||
|
||||
if (GET_CODE (seq) != SEQUENCE) return;
|
||||
|
||||
/* Scan all insns in SEQ looking for ones that modified the stack
|
||||
pointer. Record if it modified the stack pointer by copying it
|
||||
from the frame pointer or if it modified it in some other way.
|
||||
Then modify any subsequent stack pointer references to take that
|
||||
into account. We start by only allowing SP to be copied from a
|
||||
register (presumably FP) and then be subsequently referenced. */
|
||||
|
||||
for (i = 0; i < XVECLEN (seq, 0); i++)
|
||||
{
|
||||
rtx insn = XVECEXP (seq, 0, i);
|
||||
|
||||
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
|
||||
continue;
|
||||
|
||||
if (reg_set_p (stack_pointer_rtx, insn))
|
||||
{
|
||||
rtx set = single_set (insn);
|
||||
|
||||
/* If SP is set as a side-effect, we can't support this. */
|
||||
if (set == 0)
|
||||
abort ();
|
||||
|
||||
if (GET_CODE (SET_SRC (set)) == REG)
|
||||
sp_from_reg = SET_SRC (set);
|
||||
else
|
||||
sp_modified_unknown = 1;
|
||||
|
||||
/* Don't allow the SP modification to happen. */
|
||||
PUT_CODE (insn, NOTE);
|
||||
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
|
||||
NOTE_SOURCE_FILE (insn) = 0;
|
||||
}
|
||||
else if (reg_referenced_p (stack_pointer_rtx, PATTERN (insn)))
|
||||
{
|
||||
if (sp_modified_unknown)
|
||||
abort ();
|
||||
|
||||
else if (sp_from_reg != 0)
|
||||
PATTERN (insn)
|
||||
= replace_rtx (PATTERN (insn), stack_pointer_rtx, sp_from_reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Generate the prologue and epilogue RTL if the machine supports it. Thread
|
||||
this into place with notes indicating where the prologue ends and where
|
||||
the epilogue begins. Update the basic block information when possible. */
|
||||
|
@ -6990,6 +7055,12 @@ thread_prologue_and_epilogue_insns (f)
|
|||
epilogue_end = emit_note (NULL, NOTE_INSN_EPILOGUE_BEG);
|
||||
|
||||
seq = gen_epilogue ();
|
||||
|
||||
/* If this function returns with the stack depressed, massage
|
||||
the epilogue to actually do that. */
|
||||
if (TYPE_RETURNS_STACK_DEPRESSED (TREE_TYPE (current_function_decl)))
|
||||
keep_stack_depressed (seq);
|
||||
|
||||
emit_jump_insn (seq);
|
||||
|
||||
/* Retain a map of the epilogue insns. */
|
||||
|
|
42
gcc/stmt.c
42
gcc/stmt.c
|
@ -903,7 +903,15 @@ expand_goto_internal (body, label, last_insn)
|
|||
deleted as dead by flow. */
|
||||
clear_pending_stack_adjust ();
|
||||
do_pending_stack_adjust ();
|
||||
emit_stack_restore (SAVE_BLOCK, stack_level, NULL_RTX);
|
||||
|
||||
/* Don't do this adjust if it's to the end label and this function
|
||||
is to return with a depressed stack pointer. */
|
||||
if (label == return_label
|
||||
&& (TYPE_RETURNS_STACK_DEPRESSED
|
||||
(TREE_TYPE (current_function_decl))))
|
||||
;
|
||||
else
|
||||
emit_stack_restore (SAVE_BLOCK, stack_level, NULL_RTX);
|
||||
}
|
||||
|
||||
if (body != 0 && DECL_TOO_LATE (body))
|
||||
|
@ -1182,7 +1190,10 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
|
|||
|
||||
/* Restore stack level for the biggest contour that this
|
||||
jump jumps out of. */
|
||||
if (f->stack_level)
|
||||
if (f->stack_level
|
||||
&& ! (f->target_rtl == return_label
|
||||
&& (TYPE_RETURNS_STACK_DEPRESSED
|
||||
(TREE_TYPE (current_function_decl)))))
|
||||
emit_stack_restore (SAVE_BLOCK, f->stack_level, f->before_jump);
|
||||
|
||||
/* Finish up the sequence containing the insns which implement the
|
||||
|
@ -3667,6 +3678,23 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
|
|||
pop_temp_slots ();
|
||||
}
|
||||
|
||||
/* Generate code to save the stack pointer at the start of the current block
|
||||
and set up to restore it on exit. */
|
||||
|
||||
void
|
||||
save_stack_pointer ()
|
||||
{
|
||||
struct nesting *thisblock = block_stack;
|
||||
|
||||
if (thisblock->data.block.stack_level == 0)
|
||||
{
|
||||
emit_stack_save (thisblock->next ? SAVE_BLOCK : SAVE_FUNCTION,
|
||||
&thisblock->data.block.stack_level,
|
||||
thisblock->data.block.first_insn);
|
||||
stack_block_stack = thisblock;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate RTL for the automatic variable declaration DECL.
|
||||
(Other kinds of declarations are simply ignored if seen here.) */
|
||||
|
||||
|
@ -3777,14 +3805,8 @@ expand_decl (decl)
|
|||
|
||||
/* Record the stack pointer on entry to block, if have
|
||||
not already done so. */
|
||||
if (thisblock->data.block.stack_level == 0)
|
||||
{
|
||||
do_pending_stack_adjust ();
|
||||
emit_stack_save (thisblock->next ? SAVE_BLOCK : SAVE_FUNCTION,
|
||||
&thisblock->data.block.stack_level,
|
||||
thisblock->data.block.first_insn);
|
||||
stack_block_stack = thisblock;
|
||||
}
|
||||
do_pending_stack_adjust ();
|
||||
save_stack_pointer ();
|
||||
|
||||
/* In function-at-a-time mode, variable_size doesn't expand this,
|
||||
so do it now. */
|
||||
|
|
|
@ -954,7 +954,13 @@ struct tree_block
|
|||
/* In an INTEGER_TYPE, it means the type represents a size. We use this
|
||||
both for validity checking and to permit optimziations that are unsafe
|
||||
for other types. */
|
||||
#define TYPE_IS_SIZETYPE(NODE) (TYPE_CHECK (NODE)->type.no_force_blk_flag)
|
||||
#define TYPE_IS_SIZETYPE(NODE) \
|
||||
(INTEGER_TYPE_CHECK (NODE)->type.no_force_blk_flag)
|
||||
|
||||
/* In a FUNCTION_TYPE, indicates that the function returns with the stack
|
||||
pointer depressed. */
|
||||
#define TYPE_RETURNS_STACK_DEPRESSED(NODE) \
|
||||
(FUNCTION_TYPE_CHECK(NODE)->type.no_force_blk_flag)
|
||||
|
||||
/* Nonzero in a type considered volatile as a whole. */
|
||||
#define TYPE_VOLATILE(NODE) ((NODE)->common.volatile_flag)
|
||||
|
@ -2811,6 +2817,7 @@ extern int drop_through_at_end_p PARAMS ((void));
|
|||
extern void expand_start_target_temps PARAMS ((void));
|
||||
extern void expand_end_target_temps PARAMS ((void));
|
||||
extern void expand_elseif PARAMS ((tree));
|
||||
extern void save_stack_pointer PARAMS ((void));
|
||||
extern void expand_decl PARAMS ((tree));
|
||||
extern int expand_decl_cleanup PARAMS ((tree, tree));
|
||||
extern void expand_anon_union_decl PARAMS ((tree, tree, tree));
|
||||
|
|
Loading…
Reference in New Issue