Commit 7393c642 by Richard Kenner Committed by Richard Kenner

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
parent 81baa09a
Tue Aug 15 17:33:05 2000 Richard Kenner <kenner@vlsi1.ultra.nyu.edu> 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. * diagnostic.c (fatal_function): New variable.
(set_fatal_function): New function. (set_fatal_function): New function.
(fatal): Call it. (fatal): Call it.
......
...@@ -184,6 +184,9 @@ static int calls_function_1 PARAMS ((tree, int)); ...@@ -184,6 +184,9 @@ static int calls_function_1 PARAMS ((tree, int));
/* Nonzero if this is a call to "pure" function (like const function, /* Nonzero if this is a call to "pure" function (like const function,
but may read memory. */ but may read memory. */
#define ECF_PURE 512 #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, static void emit_call_1 PARAMS ((rtx, tree, tree, HOST_WIDE_INT,
HOST_WIDE_INT, HOST_WIDE_INT, rtx, HOST_WIDE_INT, HOST_WIDE_INT, rtx,
...@@ -278,6 +281,9 @@ calls_function_1 (exp, which) ...@@ -278,6 +281,9 @@ calls_function_1 (exp, which)
case CALL_EXPR: case CALL_EXPR:
if (which == 0) if (which == 0)
return 1; 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 else if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
&& (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
== FUNCTION_DECL) == FUNCTION_DECL)
...@@ -428,8 +434,8 @@ prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen) ...@@ -428,8 +434,8 @@ prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen)
We restore `inhibit_defer_pop' to that value. We restore `inhibit_defer_pop' to that value.
CALL_FUSAGE is either empty or an EXPR_LIST of USE expressions that 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 static void
emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
struct_value_size, next_arg_reg, valreg, old_inhibit_defer_pop, 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, ...@@ -495,7 +501,7 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
even if the call has no arguments to pop. */ even if the call has no arguments to pop. */
#if defined (HAVE_call) && defined (HAVE_call_value) #if defined (HAVE_call) && defined (HAVE_call_value)
if (HAVE_call && HAVE_call_value && HAVE_call_pop && HAVE_call_value_pop 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 #else
if (HAVE_call_pop && HAVE_call_value_pop) if (HAVE_call_pop && HAVE_call_value_pop)
#endif #endif
...@@ -624,10 +630,10 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, ...@@ -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 If returning from the subroutine does pop the args, indicate that the
stack pointer will be changed. */ 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 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; pending_stack_adjust += rounded_stack_size;
else else
adjust_stack (rounded_stack_size_rtx); adjust_stack (rounded_stack_size_rtx);
...@@ -756,6 +762,7 @@ special_function_p (fndecl, flags) ...@@ -756,6 +762,7 @@ special_function_p (fndecl, flags)
} }
/* Return nonzero when tree represent call to longjmp. */ /* Return nonzero when tree represent call to longjmp. */
int int
setjmp_call_p (fndecl) setjmp_call_p (fndecl)
tree fndecl; tree fndecl;
...@@ -764,11 +771,13 @@ setjmp_call_p (fndecl) ...@@ -764,11 +771,13 @@ setjmp_call_p (fndecl)
} }
/* Detect flags (function attributes) from the function type node. */ /* Detect flags (function attributes) from the function type node. */
static int static int
flags_from_decl_or_type (exp) flags_from_decl_or_type (exp)
tree exp; tree exp;
{ {
int flags = 0; int flags = 0;
/* ??? We can't set IS_MALLOC for function types? */ /* ??? We can't set IS_MALLOC for function types? */
if (DECL_P (exp)) if (DECL_P (exp))
{ {
...@@ -784,7 +793,7 @@ flags_from_decl_or_type (exp) ...@@ -784,7 +793,7 @@ flags_from_decl_or_type (exp)
flags |= ECF_NOTHROW; flags |= ECF_NOTHROW;
} }
if (TREE_READONLY (exp) && !TREE_THIS_VOLATILE (exp)) if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
flags |= ECF_CONST; flags |= ECF_CONST;
if (TREE_THIS_VOLATILE (exp)) if (TREE_THIS_VOLATILE (exp))
...@@ -2131,7 +2140,7 @@ expand_call (exp, target, ignore) ...@@ -2131,7 +2140,7 @@ expand_call (exp, target, ignore)
int old_inhibit_defer_pop = inhibit_defer_pop; int old_inhibit_defer_pop = inhibit_defer_pop;
int old_stack_allocated; int old_stack_allocated;
rtx call_fusage; rtx call_fusage;
register tree p; register tree p = TREE_OPERAND (exp, 0);
register int i; register int i;
/* The alignment of the stack, in bits. */ /* The alignment of the stack, in bits. */
HOST_WIDE_INT preferred_stack_boundary; HOST_WIDE_INT preferred_stack_boundary;
...@@ -2183,9 +2192,13 @@ expand_call (exp, target, ignore) ...@@ -2183,9 +2192,13 @@ expand_call (exp, target, ignore)
/* If we don't have specific function to call, see if we have a /* If we don't have specific function to call, see if we have a
attributes set in the type. */ attributes set in the type. */
else 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 |= ECF_SP_DEPRESSED;
flags |= flags_from_decl_or_type (TREE_TYPE (TREE_TYPE (p))); flags &= ~ (ECF_PURE | ECF_CONST);
} }
#ifdef REG_PARM_STACK_SPACE #ifdef REG_PARM_STACK_SPACE
...@@ -3271,7 +3284,7 @@ expand_call (exp, target, ignore) ...@@ -3271,7 +3284,7 @@ expand_call (exp, target, ignore)
/* If size of args is variable or this was a constructor call for a stack /* If size of args is variable or this was a constructor call for a stack
argument, restore saved stack-pointer value. */ 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); emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
pending_stack_adjust = old_pending_adj; pending_stack_adjust = old_pending_adj;
...@@ -3412,6 +3425,17 @@ expand_call (exp, target, ignore) ...@@ -3412,6 +3425,17 @@ expand_call (exp, target, ignore)
currently_expanding_call--; 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; return target;
} }
......
...@@ -4402,7 +4402,8 @@ extract_muldiv (t, c, code, wide_type) ...@@ -4402,7 +4402,8 @@ extract_muldiv (t, c, code, wide_type)
|| TREE_CODE_CLASS (TREE_CODE (op0)) == '2' || TREE_CODE_CLASS (TREE_CODE (op0)) == '2'
|| TREE_CODE_CLASS (TREE_CODE (op0)) == 'e') || TREE_CODE_CLASS (TREE_CODE (op0)) == 'e')
&& TREE_UNSIGNED (TREE_TYPE (op0)) && 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 (ctype))
> GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0))))) > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))))
break; break;
...@@ -4527,7 +4528,7 @@ extract_muldiv (t, c, code, wide_type) ...@@ -4527,7 +4528,7 @@ extract_muldiv (t, c, code, wide_type)
the operation since it will change the result if the original the operation since it will change the result if the original
computation overflowed. */ computation overflowed. */
if (TREE_UNSIGNED (ctype) if (TREE_UNSIGNED (ctype)
&& ! TYPE_IS_SIZETYPE (ctype) && ! (TREE_CODE (ctype) == INTEGER_TYPE && TYPE_IS_SIZETYPE (ctype))
&& ctype != type) && ctype != type)
break; break;
...@@ -4591,7 +4592,7 @@ extract_muldiv (t, c, code, wide_type) ...@@ -4591,7 +4592,7 @@ extract_muldiv (t, c, code, wide_type)
this since it will change the result if the original computation this since it will change the result if the original computation
overflowed. */ overflowed. */
if ((! TREE_UNSIGNED (ctype) if ((! TREE_UNSIGNED (ctype)
|| TYPE_IS_SIZETYPE (ctype)) || (TREE_CODE (ctype) == INTEGER_TYPE && TYPE_IS_SIZETYPE (ctype)))
&& ((code == MULT_EXPR && tcode == EXACT_DIV_EXPR) && ((code == MULT_EXPR && tcode == EXACT_DIV_EXPR)
|| (tcode == MULT_EXPR || (tcode == MULT_EXPR
&& code != TRUNC_MOD_EXPR && code != CEIL_MOD_EXPR && code != TRUNC_MOD_EXPR && code != CEIL_MOD_EXPR
......
...@@ -294,6 +294,9 @@ static void emit_return_into_block PARAMS ((basic_block, rtx)); ...@@ -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 void put_addressof_into_stack PARAMS ((rtx, struct hash_table *));
static boolean purge_addressof_1 PARAMS ((rtx *, rtx, int, int, static boolean purge_addressof_1 PARAMS ((rtx *, rtx, int, int,
struct hash_table *)); struct hash_table *));
#ifdef HAVE_epilogue
static void keep_stack_depressed PARAMS ((rtx));
#endif
static int is_addressof PARAMS ((rtx *, void *)); static int is_addressof PARAMS ((rtx *, void *));
static struct hash_entry *insns_for_mem_newfunc PARAMS ((struct hash_entry *, static struct hash_entry *insns_for_mem_newfunc PARAMS ((struct hash_entry *,
struct hash_table *, struct hash_table *,
...@@ -6808,6 +6811,68 @@ emit_return_into_block (bb, line_note) ...@@ -6808,6 +6811,68 @@ emit_return_into_block (bb, line_note)
} }
#endif /* HAVE_return */ #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 /* Generate the prologue and epilogue RTL if the machine supports it. Thread
this into place with notes indicating where the prologue ends and where this into place with notes indicating where the prologue ends and where
the epilogue begins. Update the basic block information when possible. */ the epilogue begins. Update the basic block information when possible. */
...@@ -6990,6 +7055,12 @@ thread_prologue_and_epilogue_insns (f) ...@@ -6990,6 +7055,12 @@ thread_prologue_and_epilogue_insns (f)
epilogue_end = emit_note (NULL, NOTE_INSN_EPILOGUE_BEG); epilogue_end = emit_note (NULL, NOTE_INSN_EPILOGUE_BEG);
seq = gen_epilogue (); 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); emit_jump_insn (seq);
/* Retain a map of the epilogue insns. */ /* Retain a map of the epilogue insns. */
......
...@@ -903,7 +903,15 @@ expand_goto_internal (body, label, last_insn) ...@@ -903,7 +903,15 @@ expand_goto_internal (body, label, last_insn)
deleted as dead by flow. */ deleted as dead by flow. */
clear_pending_stack_adjust (); clear_pending_stack_adjust ();
do_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)) if (body != 0 && DECL_TOO_LATE (body))
...@@ -1182,7 +1190,10 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in) ...@@ -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 /* Restore stack level for the biggest contour that this
jump jumps out of. */ 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); emit_stack_restore (SAVE_BLOCK, f->stack_level, f->before_jump);
/* Finish up the sequence containing the insns which implement the /* Finish up the sequence containing the insns which implement the
...@@ -3667,6 +3678,23 @@ expand_end_bindings (vars, mark_ends, dont_jump_in) ...@@ -3667,6 +3678,23 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
pop_temp_slots (); 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. /* Generate RTL for the automatic variable declaration DECL.
(Other kinds of declarations are simply ignored if seen here.) */ (Other kinds of declarations are simply ignored if seen here.) */
...@@ -3777,14 +3805,8 @@ expand_decl (decl) ...@@ -3777,14 +3805,8 @@ expand_decl (decl)
/* Record the stack pointer on entry to block, if have /* Record the stack pointer on entry to block, if have
not already done so. */ not already done so. */
if (thisblock->data.block.stack_level == 0) do_pending_stack_adjust ();
{ save_stack_pointer ();
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;
}
/* In function-at-a-time mode, variable_size doesn't expand this, /* In function-at-a-time mode, variable_size doesn't expand this,
so do it now. */ so do it now. */
......
...@@ -954,7 +954,13 @@ struct tree_block ...@@ -954,7 +954,13 @@ struct tree_block
/* In an INTEGER_TYPE, it means the type represents a size. We use this /* 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 both for validity checking and to permit optimziations that are unsafe
for other types. */ 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. */ /* Nonzero in a type considered volatile as a whole. */
#define TYPE_VOLATILE(NODE) ((NODE)->common.volatile_flag) #define TYPE_VOLATILE(NODE) ((NODE)->common.volatile_flag)
...@@ -2811,6 +2817,7 @@ extern int drop_through_at_end_p PARAMS ((void)); ...@@ -2811,6 +2817,7 @@ extern int drop_through_at_end_p PARAMS ((void));
extern void expand_start_target_temps PARAMS ((void)); extern void expand_start_target_temps PARAMS ((void));
extern void expand_end_target_temps PARAMS ((void)); extern void expand_end_target_temps PARAMS ((void));
extern void expand_elseif PARAMS ((tree)); extern void expand_elseif PARAMS ((tree));
extern void save_stack_pointer PARAMS ((void));
extern void expand_decl PARAMS ((tree)); extern void expand_decl PARAMS ((tree));
extern int expand_decl_cleanup PARAMS ((tree, tree)); extern int expand_decl_cleanup PARAMS ((tree, tree));
extern void expand_anon_union_decl PARAMS ((tree, tree, tree)); extern void expand_anon_union_decl PARAMS ((tree, tree, tree));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment