mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-15 22:21:53 +08:00
Fix nested function support for the ARM
From-SVN: r37503
This commit is contained in:
parent
cdb3cf8546
commit
68dfd979ac
@ -1,3 +1,15 @@
|
||||
2000-11-16 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
* config/arm/arm.c (output_arm_prologue): Note nested functions.
|
||||
(arm_expand_prologue): For nested functions preserve the
|
||||
static chain register during stack frame creation.
|
||||
|
||||
* config/arm/arm.h (STATIC_CHAIN_REGNUM): Change to 12.
|
||||
(ARM_INITIAL_FRAME_ELIMINATION_OFFSET): For a nested function
|
||||
with a stack frame there is a 4 byte gap between the arg
|
||||
pointer and the hard frame pointer (used to preserve the
|
||||
static chain register during stack frame creation).
|
||||
|
||||
2000-11-16 DJ Delorie <dj@redhat.com>
|
||||
|
||||
* rtl.c (read_rtx): Provide suitable names for unnamed
|
||||
|
@ -6776,6 +6776,9 @@ output_arm_prologue (f, frame_size)
|
||||
if (volatile_func)
|
||||
asm_fprintf (f, "\t%@ Volatile function.\n");
|
||||
|
||||
if (current_function_needs_context)
|
||||
asm_fprintf (f, "\t%@ Nested function.\n");
|
||||
|
||||
if (current_function_anonymous_args && current_function_pretend_args_size)
|
||||
store_arg_regs = 1;
|
||||
|
||||
@ -7318,6 +7321,9 @@ arm_expand_prologue ()
|
||||
the call-saved regs. */
|
||||
int volatile_func = arm_volatile_func ();
|
||||
rtx insn;
|
||||
rtx ip_rtx;
|
||||
int fp_offset = 0;
|
||||
|
||||
|
||||
/* Naked functions don't have prologues. */
|
||||
if (arm_naked_function_p (current_function_decl))
|
||||
@ -7345,11 +7351,59 @@ arm_expand_prologue ()
|
||||
live_regs_mask |= 1 << LR_REGNUM;
|
||||
}
|
||||
|
||||
ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
|
||||
|
||||
if (frame_pointer_needed)
|
||||
{
|
||||
if (current_function_needs_context)
|
||||
{
|
||||
/* The Static chain register is the same as the IP register
|
||||
used as a scratch register during stack frame creation.
|
||||
To get around this need to find somewhere to store IP
|
||||
whilst the frame is being created. We try the following
|
||||
places in order:
|
||||
|
||||
1. An unused argument register.
|
||||
2. A slot on the stack above the frame. (This only
|
||||
works if the function is not a varargs function).
|
||||
|
||||
If neither of these places is available, we abort (for now). */
|
||||
if (regs_ever_live[3] == 0)
|
||||
{
|
||||
insn = gen_rtx_REG (SImode, 3);
|
||||
insn = gen_rtx_SET (SImode, insn, ip_rtx);
|
||||
insn = emit_insn (insn);
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
else if (current_function_pretend_args_size == 0)
|
||||
{
|
||||
insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
|
||||
insn = gen_rtx_MEM (SImode, insn);
|
||||
insn = gen_rtx_SET (VOIDmode, insn, ip_rtx);
|
||||
insn = emit_insn (insn);
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
fp_offset = 4;
|
||||
}
|
||||
else
|
||||
/* FIXME - the way to handle this situation is to allow
|
||||
the pretend args to be dumped onto the stack, then
|
||||
reuse r3 to save IP. This would involve moving the
|
||||
copying os SP into IP until after the pretend args
|
||||
have been dumped, but this is not too hard. */
|
||||
error ("Unable to find a temporary location for static chanin register");
|
||||
}
|
||||
|
||||
live_regs_mask |= 0xD800;
|
||||
insn = emit_insn (gen_movsi (gen_rtx_REG (SImode, IP_REGNUM),
|
||||
stack_pointer_rtx));
|
||||
|
||||
if (fp_offset)
|
||||
{
|
||||
insn = gen_rtx_PLUS (SImode, stack_pointer_rtx, GEN_INT (fp_offset));
|
||||
insn = gen_rtx_SET (SImode, ip_rtx, insn);
|
||||
}
|
||||
else
|
||||
insn = gen_movsi (ip_rtx, stack_pointer_rtx);
|
||||
|
||||
insn = emit_insn (insn);
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
|
||||
@ -7426,11 +7480,29 @@ arm_expand_prologue ()
|
||||
|
||||
if (frame_pointer_needed)
|
||||
{
|
||||
insn = GEN_INT (-(4 + current_function_pretend_args_size));
|
||||
insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
|
||||
gen_rtx_REG (SImode, IP_REGNUM),
|
||||
insn));
|
||||
insn = GEN_INT (-(4 + current_function_pretend_args_size + fp_offset));
|
||||
insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn));
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
|
||||
if (current_function_needs_context)
|
||||
{
|
||||
/* Recover the static chain register. */
|
||||
if (regs_ever_live [3] == 0)
|
||||
{
|
||||
insn = gen_rtx_REG (SImode, 3);
|
||||
insn = gen_rtx_SET (SImode, ip_rtx, insn);
|
||||
insn = emit_insn (insn);
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
else /* if (current_function_pretend_args_size == 0) */
|
||||
{
|
||||
insn = gen_rtx_PLUS (SImode, hard_frame_pointer_rtx, GEN_INT (4));
|
||||
insn = gen_rtx_MEM (SImode, insn);
|
||||
insn = gen_rtx_SET (SImode, ip_rtx, insn);
|
||||
insn = emit_insn (insn);
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (amount != const0_rtx)
|
||||
|
@ -891,7 +891,7 @@ extern const char * structure_size_string;
|
||||
/* The native (Norcroft) Pascal compiler for the ARM passes the static chain
|
||||
as an invisible last argument (possible since varargs don't exist in
|
||||
Pascal), so the following is not true. */
|
||||
#define STATIC_CHAIN_REGNUM (TARGET_ARM ? 8 : 9)
|
||||
#define STATIC_CHAIN_REGNUM (TARGET_ARM ? 12 : 9)
|
||||
|
||||
/* Define this to be where the real frame pointer is if it is not possible to
|
||||
work out the offset between the frame pointer and the automatic variables
|
||||
@ -1600,7 +1600,12 @@ typedef struct
|
||||
{ \
|
||||
int volatile_func = arm_volatile_func (); \
|
||||
if ((FROM) == ARG_POINTER_REGNUM && (TO) == HARD_FRAME_POINTER_REGNUM)\
|
||||
(OFFSET) = 0; \
|
||||
{ \
|
||||
if (! current_function_needs_context || ! frame_pointer_needed) \
|
||||
(OFFSET) = 0; \
|
||||
else \
|
||||
(OFFSET) = 4; \
|
||||
} \
|
||||
else if ((FROM) == FRAME_POINTER_REGNUM \
|
||||
&& (TO) == STACK_POINTER_REGNUM) \
|
||||
(OFFSET) = current_function_outgoing_args_size \
|
||||
|
Loading…
x
Reference in New Issue
Block a user