Removal of Return with Depressed Stack Pointer support

Removal of Return with Depressed Stack Pointer support
	* tree.h (TYPE_RETURNS_STACK_DEPRESSED): Delete.
	(ECF_SP_DEPRESSED): Likewise.
	(ECF_LIBCALL_BLOCK, ECF_NOVOPS): Adjust.
	* calls.c (emit_call_1): Do not test ECF_SP_DEPRESSED.
	(flags_from_decl_or_type): Do not test TYPE_RETURNS_STACK_DEPRESSED.
	(expand_call): Do not test ECF_SP_DEPRESSED.
	* dse.c (dse_step0): Do not test TYPE_RETURNS_STACK_DEPRESSED.
	* function.c (keep_stack_depressed): Delete.
	(handle_epilogue_set): Likewise.
	(update_epilogue_consts): Likewise.
	(emit_equiv_load): Likewise.
	(thread_prologue_and_epilogue_insns): Remove support for Return with
	Depressed Stack Pointer.
	* print-tree.c (print_node): Do not test TYPE_RETURNS_STACK_DEPRESSED.

ada/
	* gigi.h (create_subprog_type): Remove returns_with_dsp parameter.
	* decl.c (gnat_to_gnu_entity): Adjust for above new prototype.
	* utils.c (create_subprog_type): Remove returns_with_dsp parameter.
	* trans.c (gnat_to_gnu) <N_Return_Statement>: Remove code dealing with
	Return by Depressed Stack Pointer.

From-SVN: r133976
This commit is contained in:
Eric Botcazou 2008-04-07 09:37:51 +00:00 committed by Eric Botcazou
parent f9985df51b
commit 9dd9bf80a8
11 changed files with 53 additions and 475 deletions

View File

@ -1,3 +1,21 @@
2008-04-07 Eric Botcazou <ebotcazou@adacore.com>
Removal of Return with Depressed Stack Pointer support
* tree.h (TYPE_RETURNS_STACK_DEPRESSED): Delete.
(ECF_SP_DEPRESSED): Likewise.
(ECF_LIBCALL_BLOCK, ECF_NOVOPS): Adjust.
* calls.c (emit_call_1): Do not test ECF_SP_DEPRESSED.
(flags_from_decl_or_type): Do not test TYPE_RETURNS_STACK_DEPRESSED.
(expand_call): Do not test ECF_SP_DEPRESSED.
* dse.c (dse_step0): Do not test TYPE_RETURNS_STACK_DEPRESSED.
* function.c (keep_stack_depressed): Delete.
(handle_epilogue_set): Likewise.
(update_epilogue_consts): Likewise.
(emit_equiv_load): Likewise.
(thread_prologue_and_epilogue_insns): Remove support for Return with
Depressed Stack Pointer.
* print-tree.c (print_node): Do not test TYPE_RETURNS_STACK_DEPRESSED.
2008-04-06 Richard Guenther <rguenther@suse.de>
PR tree-optimization/35400

View File

@ -1,3 +1,11 @@
2008-04-07 Eric Botcazou <ebotcazou@adacore.com>
* gigi.h (create_subprog_type): Remove returns_with_dsp parameter.
* decl.c (gnat_to_gnu_entity): Adjust for above new prototype.
* utils.c (create_subprog_type): Remove returns_with_dsp parameter.
* trans.c (gnat_to_gnu) <N_Return_Statement>: Remove code dealing with
Return by Depressed Stack Pointer.
2008-04-06 Eric Botcazou <ebotcazou@adacore.com>
* decl.c (is_variable_size): Do not unconditionally return false

View File

@ -3863,17 +3863,13 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
gnu_type
= create_subprog_type (gnu_return_type, gnu_param_list,
gnu_return_list, returns_unconstrained,
returns_by_ref,
Function_Returns_With_DSP (gnat_entity),
returns_by_target_ptr);
returns_by_ref, returns_by_target_ptr);
if (has_stub)
gnu_stub_type
= create_subprog_type (gnu_return_type, gnu_stub_param_list,
gnu_return_list, returns_unconstrained,
returns_by_ref,
Function_Returns_With_DSP (gnat_entity),
returns_by_target_ptr);
returns_by_ref, returns_by_target_ptr);
/* A subprogram (something that doesn't return anything) shouldn't
be considered Pure since there would be no reason for such a

View File

@ -522,13 +522,11 @@ extern void rest_of_record_type_compilation (tree record_type);
copy-in/copy-out list to be stored into TYPE_CI_CO_LIST.
RETURNS_UNCONSTRAINED is true if the function returns an unconstrained
object. RETURNS_BY_REF is true if the function returns by reference.
RETURNS_WITH_DSP is true if the function is to return with a
depressed stack pointer. RETURNS_BY_TARGET_PTR is true if the function
is to be passed (as its first parameter) the address of the place to copy
its result. */
RETURNS_BY_TARGET_PTR is true if the function is to be passed (as its
first parameter) the address of the place to copy its result. */
extern tree create_subprog_type (tree return_type, tree param_decl_list,
tree cico_list, bool returns_unconstrained,
bool returns_by_ref, bool returns_with_dsp,
bool returns_by_ref,
bool returns_by_target_ptr);
/* Return a copy of TYPE, but safe to modify in any way. */

View File

@ -4182,26 +4182,13 @@ gnat_to_gnu (Node_Id gnat_node)
else if (TYPE_RETURNS_UNCONSTRAINED_P (gnu_subprog_type))
{
gnu_ret_val = maybe_unconstrained_array (gnu_ret_val);
/* We have two cases: either the function returns with
depressed stack or not. If not, we allocate on the
secondary stack. If so, we allocate in the stack frame.
if no copy is needed, the front end will set By_Ref,
which we handle in the case above. */
if (TYPE_RETURNS_STACK_DEPRESSED (gnu_subprog_type))
gnu_ret_val
= build_allocator (TREE_TYPE (gnu_ret_val),
gnu_ret_val,
TREE_TYPE (gnu_subprog_type),
0, -1, gnat_node, false);
else
gnu_ret_val
= build_allocator (TREE_TYPE (gnu_ret_val),
gnu_ret_val,
TREE_TYPE (gnu_subprog_type),
Procedure_To_Call (gnat_node),
Storage_Pool (gnat_node),
gnat_node, false);
gnu_ret_val
= build_allocator (TREE_TYPE (gnu_ret_val),
gnu_ret_val,
TREE_TYPE (gnu_subprog_type),
Procedure_To_Call (gnat_node),
Storage_Pool (gnat_node),
gnat_node, false);
}
}
}

View File

@ -1255,17 +1255,15 @@ split_plus (tree in, tree *pvar)
otherwise we are dealing with a function. PARAM_DECL_LIST is a list of
PARM_DECL nodes that are the subprogram arguments. CICO_LIST is the
copy-in/copy-out list to be stored into TYPE_CICO_LIST.
RETURNS_UNCONSTRAINED is nonzero if the function returns an unconstrained
object. RETURNS_BY_REF is nonzero if the function returns by reference.
RETURNS_WITH_DSP is nonzero if the function is to return with a
depressed stack pointer. RETURNS_BY_TARGET_PTR is true if the function
is to be passed (as its first parameter) the address of the place to copy
its result. */
RETURNS_UNCONSTRAINED is true if the function returns an unconstrained
object. RETURNS_BY_REF is true if the function returns by reference.
RETURNS_BY_TARGET_PTR is true if the function is to be passed (as its
first parameter) the address of the place to copy its result. */
tree
create_subprog_type (tree return_type, tree param_decl_list, tree cico_list,
bool returns_unconstrained, bool returns_by_ref,
bool returns_with_dsp, bool returns_by_target_ptr)
bool returns_by_target_ptr)
{
/* A chain of TREE_LIST nodes whose TREE_VALUEs are the data type nodes of
the subprogram formal parameters. This list is generated by traversing the
@ -1302,7 +1300,6 @@ create_subprog_type (tree return_type, tree param_decl_list, tree cico_list,
TYPE_CI_CO_LIST (type) = cico_list;
TYPE_RETURNS_UNCONSTRAINED_P (type) = returns_unconstrained;
TYPE_RETURNS_STACK_DEPRESSED (type) = returns_with_dsp;
TYPE_RETURNS_BY_REF_P (type) = returns_by_ref;
TYPE_RETURNS_BY_TARGET_PTR_P (type) = returns_by_target_ptr;
return type;

View File

@ -297,7 +297,7 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
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 && ! (ecf_flags & ECF_SP_DEPRESSED))
&& n_popped > 0)
#else
if (HAVE_call_pop && HAVE_call_value_pop)
#endif
@ -432,7 +432,7 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
if (rounded_stack_size != 0)
{
if (ecf_flags & (ECF_SP_DEPRESSED | ECF_NORETURN))
if (ecf_flags & ECF_NORETURN)
/* Just pretend we did the pop. */
stack_pointer_delta -= rounded_stack_size;
else if (flag_defer_pop && inhibit_defer_pop == 0
@ -602,14 +602,6 @@ flags_from_decl_or_type (const_tree exp)
if (TREE_THIS_VOLATILE (exp))
flags |= ECF_NORETURN;
/* Mark if the function returns with the stack pointer depressed. We
cannot consider it pure or constant in that case. */
if (TREE_CODE (type) == FUNCTION_TYPE && TYPE_RETURNS_STACK_DEPRESSED (type))
{
flags |= ECF_SP_DEPRESSED;
flags &= ~(ECF_PURE | ECF_CONST);
}
return flags;
}
@ -2354,13 +2346,12 @@ expand_call (tree exp, rtx target, int ignore)
/* Don't let pending stack adjusts add up to too much.
Also, do all pending adjustments now if there is any chance
this might be a call to alloca or if we are expanding a sibling
call sequence or if we are calling a function that is to return
with stack pointer depressed.
call sequence.
Also do the adjustments before a throwing call, otherwise
exception handling can fail; PR 19225. */
if (pending_stack_adjust >= 32
|| (pending_stack_adjust > 0
&& (flags & (ECF_MAY_BE_ALLOCA | ECF_SP_DEPRESSED)))
&& (flags & ECF_MAY_BE_ALLOCA))
|| (pending_stack_adjust > 0
&& flag_exceptions && !(flags & ECF_NOTHROW))
|| pass == 0)
@ -3071,7 +3062,7 @@ expand_call (tree exp, rtx target, int 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 && ! (flags & ECF_SP_DEPRESSED))
if (old_stack_level)
{
emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
stack_pointer_delta = old_stack_pointer_delta;
@ -3177,16 +3168,6 @@ expand_call (tree exp, rtx target, int 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);
}
if (stack_usage_map_buf)
free (stack_usage_map_buf);

View File

@ -522,11 +522,8 @@ struct clear_alias_mode_holder
static alloc_pool clear_alias_mode_pool;
/* This is true except for two cases:
(1) current_function_stdarg -- i.e. we cannot do this
for vararg functions because they play games with the frame.
(2) In ada, it is sometimes not safe to do assume that any stores
based off the stack frame go dead at the exit to a function. */
/* This is true except if current_function_stdarg -- i.e. we cannot do
this for vararg functions because they play games with the frame. */
static bool stores_off_frame_dead_at_return;
/* Counter for stats. */
@ -712,10 +709,7 @@ dse_step0 (void)
bb_table = XCNEWVEC (bb_info_t, last_basic_block);
rtx_group_next_id = 0;
stores_off_frame_dead_at_return =
(!(TREE_CODE (TREE_TYPE (current_function_decl)) == FUNCTION_TYPE
&& (TYPE_RETURNS_STACK_DEPRESSED (TREE_TYPE (current_function_decl)))))
&& (!current_function_stdarg);
stores_off_frame_dead_at_return = !current_function_stdarg;
init_alias_analysis ();

View File

@ -207,9 +207,6 @@ static int contains (const_rtx, VEC(int,heap) **);
#ifdef HAVE_return
static void emit_return_into_block (basic_block);
#endif
#if defined(HAVE_epilogue) && defined(INCOMING_RETURN_ADDR_RTX)
static rtx keep_stack_depressed (rtx);
#endif
static void prepare_function_start (void);
static void do_clobber_return_reg (rtx, void *);
static void do_use_return_reg (rtx, void *);
@ -4720,383 +4717,6 @@ emit_return_into_block (basic_block bb)
}
#endif /* HAVE_return */
#if defined(HAVE_epilogue) && defined(INCOMING_RETURN_ADDR_RTX)
/* These functions convert the epilogue into a variant that does not
modify the stack pointer. This is used in cases where a function
returns an object whose size is not known until it is computed.
The called function leaves the object on the stack, leaves the
stack depressed, and returns a pointer to the object.
What we need to do is track all modifications and references to the
stack pointer, deleting the modifications and changing the
references to point to the location the stack pointer would have
pointed to had the modifications taken place.
These functions need to be portable so we need to make as few
assumptions about the epilogue as we can. However, the epilogue
basically contains three things: instructions to reset the stack
pointer, instructions to reload registers, possibly including the
frame pointer, and an instruction to return to the caller.
We must be sure of what a relevant epilogue insn is doing. We also
make no attempt to validate the insns we make since if they are
invalid, we probably can't do anything valid. The intent is that
these routines get "smarter" as more and more machines start to use
them and they try operating on different epilogues.
We use the following structure to track what the part of the
epilogue that we've already processed has done. We keep two copies
of the SP equivalence, one for use during the insn we are
processing and one for use in the next insn. The difference is
because one part of a PARALLEL may adjust SP and the other may use
it. */
struct epi_info
{
rtx sp_equiv_reg; /* REG that SP is set from, perhaps SP. */
HOST_WIDE_INT sp_offset; /* Offset from SP_EQUIV_REG of present SP. */
rtx new_sp_equiv_reg; /* REG to be used at end of insn. */
HOST_WIDE_INT new_sp_offset; /* Offset to be used at end of insn. */
rtx equiv_reg_src; /* If nonzero, the value that SP_EQUIV_REG
should be set to once we no longer need
its value. */
rtx const_equiv[FIRST_PSEUDO_REGISTER]; /* Any known constant equivalences
for registers. */
};
static void handle_epilogue_set (rtx, struct epi_info *);
static void update_epilogue_consts (rtx, const_rtx, void *);
static void emit_equiv_load (struct epi_info *);
/* Modify INSN, a list of one or more insns that is part of the epilogue, to
no modifications to the stack pointer. Return the new list of insns. */
static rtx
keep_stack_depressed (rtx insns)
{
int j;
struct epi_info info;
rtx insn, next;
/* If the epilogue is just a single instruction, it must be OK as is. */
if (NEXT_INSN (insns) == NULL_RTX)
return insns;
/* Otherwise, start a sequence, initialize the information we have, and
process all the insns we were given. */
start_sequence ();
info.sp_equiv_reg = stack_pointer_rtx;
info.sp_offset = 0;
info.equiv_reg_src = 0;
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
info.const_equiv[j] = 0;
insn = insns;
next = NULL_RTX;
while (insn != NULL_RTX)
{
next = NEXT_INSN (insn);
if (!INSN_P (insn))
{
add_insn (insn);
insn = next;
continue;
}
/* If this insn references the register that SP is equivalent to and
we have a pending load to that register, we must force out the load
first and then indicate we no longer know what SP's equivalent is. */
if (info.equiv_reg_src != 0
&& reg_referenced_p (info.sp_equiv_reg, PATTERN (insn)))
{
emit_equiv_load (&info);
info.sp_equiv_reg = 0;
}
info.new_sp_equiv_reg = info.sp_equiv_reg;
info.new_sp_offset = info.sp_offset;
/* If this is a (RETURN) and the return address is on the stack,
update the address and change to an indirect jump. */
if (GET_CODE (PATTERN (insn)) == RETURN
|| (GET_CODE (PATTERN (insn)) == PARALLEL
&& GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == RETURN))
{
rtx retaddr = INCOMING_RETURN_ADDR_RTX;
rtx base = 0;
HOST_WIDE_INT offset = 0;
rtx jump_insn, jump_set;
/* If the return address is in a register, we can emit the insn
unchanged. Otherwise, it must be a MEM and we see what the
base register and offset are. In any case, we have to emit any
pending load to the equivalent reg of SP, if any. */
if (REG_P (retaddr))
{
emit_equiv_load (&info);
add_insn (insn);
insn = next;
continue;
}
else
{
rtx ret_ptr;
gcc_assert (MEM_P (retaddr));
ret_ptr = XEXP (retaddr, 0);
if (REG_P (ret_ptr))
{
base = gen_rtx_REG (Pmode, REGNO (ret_ptr));
offset = 0;
}
else
{
gcc_assert (GET_CODE (ret_ptr) == PLUS
&& REG_P (XEXP (ret_ptr, 0))
&& GET_CODE (XEXP (ret_ptr, 1)) == CONST_INT);
base = gen_rtx_REG (Pmode, REGNO (XEXP (ret_ptr, 0)));
offset = INTVAL (XEXP (ret_ptr, 1));
}
}
/* If the base of the location containing the return pointer
is SP, we must update it with the replacement address. Otherwise,
just build the necessary MEM. */
retaddr = plus_constant (base, offset);
if (base == stack_pointer_rtx)
retaddr = simplify_replace_rtx (retaddr, stack_pointer_rtx,
plus_constant (info.sp_equiv_reg,
info.sp_offset));
retaddr = gen_rtx_MEM (Pmode, retaddr);
MEM_NOTRAP_P (retaddr) = 1;
/* If there is a pending load to the equivalent register for SP
and we reference that register, we must load our address into
a scratch register and then do that load. */
if (info.equiv_reg_src
&& reg_overlap_mentioned_p (info.equiv_reg_src, retaddr))
{
unsigned int regno;
rtx reg;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (HARD_REGNO_MODE_OK (regno, Pmode)
&& !fixed_regs[regno]
&& TEST_HARD_REG_BIT (regs_invalidated_by_call, regno)
&& !REGNO_REG_SET_P
(DF_LR_IN (EXIT_BLOCK_PTR), regno)
&& !refers_to_regno_p (regno,
end_hard_regno (Pmode, regno),
info.equiv_reg_src, NULL)
&& info.const_equiv[regno] == 0)
break;
gcc_assert (regno < FIRST_PSEUDO_REGISTER);
reg = gen_rtx_REG (Pmode, regno);
emit_move_insn (reg, retaddr);
retaddr = reg;
}
emit_equiv_load (&info);
jump_insn = emit_jump_insn (gen_indirect_jump (retaddr));
/* Show the SET in the above insn is a RETURN. */
jump_set = single_set (jump_insn);
gcc_assert (jump_set);
SET_IS_RETURN_P (jump_set) = 1;
}
/* If SP is not mentioned in the pattern and its equivalent register, if
any, is not modified, just emit it. Otherwise, if neither is set,
replace the reference to SP and emit the insn. If none of those are
true, handle each SET individually. */
else if (!reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))
&& (info.sp_equiv_reg == stack_pointer_rtx
|| !reg_set_p (info.sp_equiv_reg, insn)))
add_insn (insn);
else if (! reg_set_p (stack_pointer_rtx, insn)
&& (info.sp_equiv_reg == stack_pointer_rtx
|| !reg_set_p (info.sp_equiv_reg, insn)))
{
int changed;
changed = validate_replace_rtx (stack_pointer_rtx,
plus_constant (info.sp_equiv_reg,
info.sp_offset),
insn);
gcc_assert (changed);
add_insn (insn);
}
else if (GET_CODE (PATTERN (insn)) == SET)
handle_epilogue_set (PATTERN (insn), &info);
else if (GET_CODE (PATTERN (insn)) == PARALLEL)
{
for (j = 0; j < XVECLEN (PATTERN (insn), 0); j++)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET)
handle_epilogue_set (XVECEXP (PATTERN (insn), 0, j), &info);
}
else
add_insn (insn);
info.sp_equiv_reg = info.new_sp_equiv_reg;
info.sp_offset = info.new_sp_offset;
/* Now update any constants this insn sets. */
note_stores (PATTERN (insn), update_epilogue_consts, &info);
insn = next;
}
insns = get_insns ();
end_sequence ();
return insns;
}
/* SET is a SET from an insn in the epilogue. P is a pointer to the epi_info
structure that contains information about what we've seen so far. We
process this SET by either updating that data or by emitting one or
more insns. */
static void
handle_epilogue_set (rtx set, struct epi_info *p)
{
/* First handle the case where we are setting SP. Record what it is being
set from, which we must be able to determine */
if (reg_set_p (stack_pointer_rtx, set))
{
gcc_assert (SET_DEST (set) == stack_pointer_rtx);
if (GET_CODE (SET_SRC (set)) == PLUS)
{
p->new_sp_equiv_reg = XEXP (SET_SRC (set), 0);
if (GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT)
p->new_sp_offset = INTVAL (XEXP (SET_SRC (set), 1));
else
{
gcc_assert (REG_P (XEXP (SET_SRC (set), 1))
&& (REGNO (XEXP (SET_SRC (set), 1))
< FIRST_PSEUDO_REGISTER)
&& p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))]);
p->new_sp_offset
= INTVAL (p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))]);
}
}
else
p->new_sp_equiv_reg = SET_SRC (set), p->new_sp_offset = 0;
/* If we are adjusting SP, we adjust from the old data. */
if (p->new_sp_equiv_reg == stack_pointer_rtx)
{
p->new_sp_equiv_reg = p->sp_equiv_reg;
p->new_sp_offset += p->sp_offset;
}
gcc_assert (p->new_sp_equiv_reg && REG_P (p->new_sp_equiv_reg));
return;
}
/* Next handle the case where we are setting SP's equivalent
register. We must not already have a value to set it to. We
could update, but there seems little point in handling that case.
Note that we have to allow for the case where we are setting the
register set in the previous part of a PARALLEL inside a single
insn. But use the old offset for any updates within this insn.
We must allow for the case where the register is being set in a
different (usually wider) mode than Pmode). */
else if (p->new_sp_equiv_reg != 0 && reg_set_p (p->new_sp_equiv_reg, set))
{
gcc_assert (!p->equiv_reg_src
&& REG_P (p->new_sp_equiv_reg)
&& REG_P (SET_DEST (set))
&& (GET_MODE_BITSIZE (GET_MODE (SET_DEST (set)))
<= BITS_PER_WORD)
&& REGNO (p->new_sp_equiv_reg) == REGNO (SET_DEST (set)));
p->equiv_reg_src
= simplify_replace_rtx (SET_SRC (set), stack_pointer_rtx,
plus_constant (p->sp_equiv_reg,
p->sp_offset));
}
/* Otherwise, replace any references to SP in the insn to its new value
and emit the insn. */
else
{
SET_SRC (set) = simplify_replace_rtx (SET_SRC (set), stack_pointer_rtx,
plus_constant (p->sp_equiv_reg,
p->sp_offset));
SET_DEST (set) = simplify_replace_rtx (SET_DEST (set), stack_pointer_rtx,
plus_constant (p->sp_equiv_reg,
p->sp_offset));
emit_insn (set);
}
}
/* Update the tracking information for registers set to constants. */
static void
update_epilogue_consts (rtx dest, const_rtx x, void *data)
{
struct epi_info *p = (struct epi_info *) data;
rtx new;
if (!REG_P (dest) || REGNO (dest) >= FIRST_PSEUDO_REGISTER)
return;
/* If we are either clobbering a register or doing a partial set,
show we don't know the value. */
else if (GET_CODE (x) == CLOBBER || ! rtx_equal_p (dest, SET_DEST (x)))
p->const_equiv[REGNO (dest)] = 0;
/* If we are setting it to a constant, record that constant. */
else if (GET_CODE (SET_SRC (x)) == CONST_INT)
p->const_equiv[REGNO (dest)] = SET_SRC (x);
/* If this is a binary operation between a register we have been tracking
and a constant, see if we can compute a new constant value. */
else if (ARITHMETIC_P (SET_SRC (x))
&& REG_P (XEXP (SET_SRC (x), 0))
&& REGNO (XEXP (SET_SRC (x), 0)) < FIRST_PSEUDO_REGISTER
&& p->const_equiv[REGNO (XEXP (SET_SRC (x), 0))] != 0
&& GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
&& 0 != (new = simplify_binary_operation
(GET_CODE (SET_SRC (x)), GET_MODE (dest),
p->const_equiv[REGNO (XEXP (SET_SRC (x), 0))],
XEXP (SET_SRC (x), 1)))
&& GET_CODE (new) == CONST_INT)
p->const_equiv[REGNO (dest)] = new;
/* Otherwise, we can't do anything with this value. */
else
p->const_equiv[REGNO (dest)] = 0;
}
/* Emit an insn to do the load shown in p->equiv_reg_src, if needed. */
static void
emit_equiv_load (struct epi_info *p)
{
if (p->equiv_reg_src != 0)
{
rtx dest = p->sp_equiv_reg;
if (GET_MODE (p->equiv_reg_src) != GET_MODE (dest))
dest = gen_rtx_REG (GET_MODE (p->equiv_reg_src),
REGNO (p->sp_equiv_reg));
emit_move_insn (dest, p->equiv_reg_src);
p->equiv_reg_src = 0;
}
}
#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. */
@ -5274,17 +4894,7 @@ thread_prologue_and_epilogue_insns (void)
{
start_sequence ();
epilogue_end = emit_note (NOTE_INSN_EPILOGUE_BEG);
seq = gen_epilogue ();
#ifdef INCOMING_RETURN_ADDR_RTX
/* If this function returns with the stack depressed and we can support
it, massage the epilogue to actually do that. */
if (TREE_CODE (TREE_TYPE (current_function_decl)) == FUNCTION_TYPE
&& TYPE_RETURNS_STACK_DEPRESSED (TREE_TYPE (current_function_decl)))
seq = keep_stack_depressed (seq);
#endif
emit_jump_insn (seq);
/* Retain a map of the epilogue insns. */

View File

@ -565,9 +565,6 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
else if (TREE_CODE (node) == INTEGER_TYPE
&& TYPE_IS_SIZETYPE (node))
fputs (" sizetype", file);
else if (TREE_CODE (node) == FUNCTION_TYPE
&& TYPE_RETURNS_STACK_DEPRESSED (node))
fputs (" returns-stack-depressed", file);
if (TYPE_STRING_FLAG (node))
fputs (" string-flag", file);

View File

@ -2207,11 +2207,6 @@ struct tree_block GTY(())
#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) (TYPE_CHECK (NODE)->base.volatile_flag)
@ -5002,14 +4997,11 @@ extern tree build_duplicate_type (tree);
/* Nonzero if this is a call to "pure" function (like const function,
but may read memory. */
#define ECF_PURE 128
/* Nonzero if this is a call to a function that returns with the stack
pointer depressed. */
#define ECF_SP_DEPRESSED 256
/* Create libcall block around the call. */
#define ECF_LIBCALL_BLOCK 512
#define ECF_LIBCALL_BLOCK 256
/* Function does not read or write memory (but may have side effects, so
it does not necessarily fit ECF_CONST). */
#define ECF_NOVOPS 1024
#define ECF_NOVOPS 512
extern int flags_from_decl_or_type (const_tree);
extern int call_expr_flags (const_tree);