Nested functions on ARM (mk II)
Nick Clifton
nickc@redhat.com
Tue Nov 14 17:41:00 GMT 2000
Hi Guys,
OK, here is a revised patch to fix nested functions for the ARM.
This patch uses the same solution as the previous version (changing
the static chain register from the call-saved register r8 to the
call-clobbered r12). This time however, if r12 is going to be
clobbered by stack frame creation the code attempts to find a viable
alternative place to store the static chain (either an unused
argument register, or an *allocated* slot on the stack). If no
slot can be found, an error message is emitted, rather than silently
producing bad code. This should only happen with nested functions
that use varargs.
The patch still does not address the corruption of r12 by the PIC
support code, but if this turns out to be a real issue, it should be
simple enough to duplicate the solution in this case.
Here are a couple of example code sequences to show the patch in
action. Firstly using a spare argument register:
mov r3, ip
mov ip, sp
stmfd sp!, {fp, ip, lr, pc}
sub fp, ip, #4
sub sp, sp, #4
mov ip, r3
Secondly using a spare stack slot:
str ip, [sp, #-4]!
add ip, sp, #4
stmfd sp!, {r4, fp, ip, lr, pc}
sub fp, ip, #4
ldr ip, [fp, #4]
Any objections to my applying this version ?
Cheers
Nick
PS. I was unable to reproduce the problem I saw of stack slots being
used before they were allocated due to the scheduling of instructions
into the prologue.
2000-11-14 Nick Clifton <nickc@redhat.com>
* config/arm/arm.c (arm_expand_prologue): IF the static chain
register is needed and going to be corrupted by stack frame
creation, attempt to find a place to preserve it. If none can
be found, issue an error message.
Index: gcc/config/arm/arm.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/arm/arm.c,v
retrieving revision 1.113
diff -p -r1.113 arm.c
*** arm.c 2000/11/10 16:01:21 1.113
--- arm.c 2000/11/15 01:35:34
*************** output_arm_prologue (f, frame_size)
*** 6776,6781 ****
--- 6776,6784 ----
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;
*************** arm_expand_prologue ()
*** 7318,7323 ****
--- 7321,7327 ----
the call-saved regs. */
int volatile_func = arm_volatile_func ();
rtx insn;
+ rtx ip_rtx;
/* Naked functions don't have prologues. */
if (arm_naked_function_p (current_function_decl))
*************** arm_expand_prologue ()
*** 7345,7355 ****
live_regs_mask |= 1 << LR_REGNUM;
}
if (frame_pointer_needed)
{
live_regs_mask |= 0xD800;
! insn = emit_insn (gen_movsi (gen_rtx_REG (SImode, IP_REGNUM),
! stack_pointer_rtx));
RTX_FRAME_RELATED_P (insn) = 1;
}
--- 7349,7404 ----
live_regs_mask |= 1 << LR_REGNUM;
}
+ ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
+
if (frame_pointer_needed)
{
+ int offset = 0;
+
+ 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;
+ offset = 4;
+ }
+ else
+ error ("Unable to find a temporary location for static chanin register");
+ }
+
live_regs_mask |= 0xD800;
!
! if (offset)
! {
! insn = gen_rtx_PLUS (SImode, stack_pointer_rtx, GEN_INT (4));
! 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;
}
*************** arm_expand_prologue ()
*** 7427,7436 ****
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));
RTX_FRAME_RELATED_P (insn) = 1;
}
if (amount != const0_rtx)
--- 7476,7503 ----
if (frame_pointer_needed)
{
insn = GEN_INT (-(4 + current_function_pretend_args_size));
! 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)
More information about the Gcc-bugs
mailing list