This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Patch for -mcaller-super-interworking & stack arguments
- From: Richard Sandiford <rsandifo at redhat dot com>
- To: Richard Earnshaw <rearnsha at gcc dot gnu dot org>
- Cc: gcc-patches <gcc-patches at gcc dot gnu dot org>
- Date: Wed, 01 Sep 2004 15:14:48 +0100
- Subject: Re: Patch for -mcaller-super-interworking & stack arguments
- References: <87isbsx07u.fsf@redhat.com><1093604695.22129.97.camel@pc960.cambridge.arm.com>
Richard Earnshaw <rearnsha@gcc.gnu.org> writes:
> Another approach would be to use r11 (fp) to hold the 'frame pointer' in
> the case where we didn't really need a frame (and continue to pretend
> that the function was frameless). It would mean a further function stub
> in libgcc (unless you always made it work that way) but would mean that
> we didn't loose a low register. You'd end up with a prologue sequence
> something like
>
> push {r4-r7, lr}
> mov r4, fp
> push {r4}
> sub sp, sp, #4
> mov fp, sp
>
> The interwork stub would be similar to the one in your proposed patch,
> but use fp instead of r7.
>
> To make this work you'd probably have to make r11 a fixed register for
> -mthumb -mcaller-super-interworking, but that wouldn't hurt very much.
OK, here's a patch to do that. In most other respects, it's the same
as the patch I posted before.
The main difficulty with using r11 is that we need to make it fixed
while at the same time:
(a) making sure it is treated as call-saved rather than call-clobbered and
(b) making sure that every CALL_INSN is treated as using r11.
(a) is easy enough to do with CALL_REALLY_USED_REGISTERS, but I believe
the standard way to achieve (b) is to either:
(1) add (use r11) to the call patterns or
(2) add (use r11) to CALL_INSN_FUNCTION_USAGE.
(1) would mean adding new patterns or complicating the existing ones.
(2) would mean changing the call expanders so that they do something like:
insn = emit_call_insn (gen_... (...));
if (...)
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), gen_rtx_REG (Pmode, 11));
DONE;
Both seemed too invasive for what is (I suspect) such a little-used feature.
The patch therefore just makes r11 global, which achieves (a) and (b) above,
and also has the benefit of warning if the user tries to use r11 as a true
global register.
In his review, Nick asked me to add a testcase to the testsuite.
This is a bit difficult because something like:
/* { dg-options "-mthumb -mcaller-super-interworking" } */
will cause lots of linker warnings if run on a non-thumb multilib.
For example, testglue (which arm-sim still uses) will not have been
compiled for thumb.
I think the only reliable way of testing -mcaller-super-interworking is
to add it to the --target_board list. If you do that, then like I said
in my original posting, you'll get a failure in gcc.dg/trampoline-1.c
that is fixed by this patch.
Tested on arm-elf with {,-mthumb,-mthumb/-mcaller-super-interworking}.
OK to install?
Richard
* config/arm/arm.h (CONDITIONAL_REGISTER_USAGE): Make r11 fixed and
global for -mcaller-super-interworking.
(CALLER_INTERWORKING_SLOT_SIZE): New macro.
* config/arm/arm.c (thumb_compute_save_reg_mask): Save r11 if
CALLER_INTERWORKING_SLOT_SIZE is nonzero and the function does
not need a frame pointer.
(arm_get_frame_offsets): Add CALLER_INTERWORKING_SLOT_SIZE bytes to
the soft frame pointer offset.
(thumb_expand_prologue): Set up r11 for -mcaller-super-interworking.
* config/arm/arm.md (*call_reg_thumb, *call_value_reg_thumb): Use
_interwork_{r7,r11}_call_via_rN if some arguments are passed on
the stack. Use frame_pointer_needed to choose between them.
* config/arm/lib1funcs.asm (_arm_return_{r7,r11}): New functions.
(interwork_with_frame): New macro.
(interwork): Add _interwork_{r7,r11}_call_via_rN().
Index: config/arm/arm.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.h,v
retrieving revision 1.255
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.255 arm.h
*** config/arm/arm.h 29 Aug 2004 22:18:25 -0000 1.255
--- config/arm/arm.h 1 Sep 2004 14:10:04 -0000
*************** #define CONDITIONAL_REGISTER_USAGE \
*** 917,926 ****
fixed_regs[10] = 1; \
call_used_regs[10] = 1; \
} \
! if (TARGET_APCS_FRAME) \
{ \
fixed_regs[ARM_HARD_FRAME_POINTER_REGNUM] = 1; \
call_used_regs[ARM_HARD_FRAME_POINTER_REGNUM] = 1; \
} \
SUBTARGET_CONDITIONAL_REGISTER_USAGE \
}
--- 917,932 ----
fixed_regs[10] = 1; \
call_used_regs[10] = 1; \
} \
! /* -mcaller-super-interworking reserves r11 for calls to \
! _interwork_r11_call_via_rN(). Making the register global \
! is an easy way of ensuring that it remains valid for all \
! calls. */ \
! if (TARGET_APCS_FRAME || TARGET_CALLER_INTERWORKING) \
{ \
fixed_regs[ARM_HARD_FRAME_POINTER_REGNUM] = 1; \
call_used_regs[ARM_HARD_FRAME_POINTER_REGNUM] = 1; \
+ if (TARGET_CALLER_INTERWORKING) \
+ global_regs[ARM_HARD_FRAME_POINTER_REGNUM] = 1; \
} \
SUBTARGET_CONDITIONAL_REGISTER_USAGE \
}
*************** #define STACK_GROWS_DOWNWARD 1
*** 1517,1522 ****
--- 1523,1542 ----
goes at a more negative offset in the frame. */
#define FRAME_GROWS_DOWNWARD 1
+ /* The amount of scratch space needed by _interwork_{r7,r11}_call_via_rN().
+ When present, it is one word in size, and sits at the top of the frame,
+ between the soft frame pointer and either r7 or r11.
+
+ We only need _interwork_rM_call_via_rN() for -mcaller-super-interworking,
+ and only then if some outgoing arguments are passed on the stack. It would
+ be tempting to also check whether the stack arguments are passed by indirect
+ calls, but there seems to be no reason in principle why a post-reload pass
+ couldn't convert a direct call into an indirect one. */
+ #define CALLER_INTERWORKING_SLOT_SIZE \
+ (!TARGET_CALLER_INTERWORKING ? 0 \
+ : current_function_outgoing_args_size == 0 ? 0 \
+ : UNITS_PER_WORD)
+
/* Offset within stack frame to start allocating local variables at.
If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
first local allocated. Otherwise, it is the offset to the BEGINNING
Index: config/arm/arm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.399
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.399 arm.c
*** config/arm/arm.c 25 Aug 2004 09:52:09 -0000 1.399
--- config/arm/arm.c 1 Sep 2004 14:10:18 -0000
*************** thumb_compute_save_reg_mask (void)
*** 8729,8734 ****
--- 8729,8737 ----
mask |= PIC_OFFSET_TABLE_REGNUM;
if (TARGET_SINGLE_PIC_BASE)
mask &= ~(1 << arm_pic_register);
+ /* See if we might need r11 for calls to _interwork_r11_call_via_rN(). */
+ if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0)
+ mask |= 1 << ARM_HARD_FRAME_POINTER_REGNUM;
/* lr will also be pushed if any lo regs are pushed. */
if (mask & 0xff || thumb_force_lr_save ())
*************** arm_get_frame_offsets (void)
*** 9808,9814 ****
/* Saved registers include the stack frame. */
offsets->saved_regs = offsets->saved_args + saved;
! offsets->soft_frame = offsets->saved_regs;
/* A leaf function does not need any stack alignment if it has nothing
on the stack. */
if (leaf && frame_size == 0)
--- 9811,9817 ----
/* Saved registers include the stack frame. */
offsets->saved_regs = offsets->saved_args + saved;
! offsets->soft_frame = offsets->saved_regs + CALLER_INTERWORKING_SLOT_SIZE;
/* A leaf function does not need any stack alignment if it has nothing
on the stack. */
if (leaf && frame_size == 0)
*************** thumb_expand_prologue (void)
*** 12903,12908 ****
--- 12906,12914 ----
stack_pointer_rtx));
RTX_FRAME_RELATED_P (insn) = 1;
}
+ else if (CALLER_INTERWORKING_SLOT_SIZE > 0)
+ emit_move_insn (gen_rtx_REG (Pmode, ARM_HARD_FRAME_POINTER_REGNUM),
+ stack_pointer_rtx);
live_regs_mask = thumb_compute_save_reg_mask ();
amount = offsets->outgoing_args - offsets->saved_regs;
Index: config/arm/arm.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.md,v
retrieving revision 1.181
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.181 arm.md
*** config/arm/arm.md 24 Aug 2004 20:16:34 -0000 1.181
--- config/arm/arm.md 1 Sep 2004 14:10:29 -0000
*************** (define_insn "*call_reg_thumb"
*** 7427,7436 ****
"TARGET_THUMB && !arm_arch5"
"*
{
! if (TARGET_CALLER_INTERWORKING)
return \"bl\\t%__interwork_call_via_%0\";
else
! return \"bl\\t%__call_via_%0\";
}"
[(set_attr "type" "call")]
)
--- 7427,7440 ----
"TARGET_THUMB && !arm_arch5"
"*
{
! if (!TARGET_CALLER_INTERWORKING)
! return \"bl\\t%__call_via_%0\";
! else if (operands[1] == const0_rtx)
return \"bl\\t%__interwork_call_via_%0\";
+ else if (frame_pointer_needed)
+ return \"bl\\t%__interwork_r7_call_via_%0\";
else
! return \"bl\\t%__interwork_r11_call_via_%0\";
}"
[(set_attr "type" "call")]
)
*************** (define_insn "*call_value_reg_thumb"
*** 7517,7526 ****
"TARGET_THUMB && !arm_arch5"
"*
{
! if (TARGET_CALLER_INTERWORKING)
return \"bl\\t%__interwork_call_via_%1\";
else
! return \"bl\\t%__call_via_%1\";
}"
[(set_attr "type" "call")]
)
--- 7521,7534 ----
"TARGET_THUMB && !arm_arch5"
"*
{
! if (!TARGET_CALLER_INTERWORKING)
! return \"bl\\t%__call_via_%1\";
! else if (operands[2] == const0_rtx)
return \"bl\\t%__interwork_call_via_%1\";
+ else if (frame_pointer_needed)
+ return \"bl\\t%__interwork_r7_call_via_%1\";
else
! return \"bl\\t%__interwork_r11_call_via_%1\";
}"
[(set_attr "type" "call")]
)
Index: config/arm/lib1funcs.asm
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/lib1funcs.asm,v
retrieving revision 1.33
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.33 lib1funcs.asm
*** config/arm/lib1funcs.asm 12 Aug 2004 16:14:52 -0000 1.33
--- config/arm/lib1funcs.asm 1 Sep 2004 14:10:30 -0000
*************** 1:
*** 1096,1102 ****
the target code cannot be relied upon to return via a BX instruction, so
instead we have to store the resturn address on the stack and allow the
called function to return here instead. Upon return we recover the real
! return address and use a BX to get back to Thumb mode. */
.text
.align 0
--- 1096,1115 ----
the target code cannot be relied upon to return via a BX instruction, so
instead we have to store the resturn address on the stack and allow the
called function to return here instead. Upon return we recover the real
! return address and use a BX to get back to Thumb mode.
!
! There are three variations of this code. The first,
! _interwork_call_via_rN(), will push the return address onto the
! stack and pop it in _arm_return(). It should only be used if all
! arguments are passed in registers.
!
! The second, _interwork_r7_call_via_rN(), instead stores the return
! address at [r7, #-4]. It is the caller's responsibility to ensure
! that this address is valid and contains no useful data.
!
! The third, _interwork_r11_call_via_rN(), works in the same way but
! uses r11 instead of r7. It is useful if the caller does not really
! need a frame pointer. */
.text
.align 0
*************** 1:
*** 1105,1111 ****
.globl _arm_return
_arm_return:
RETLDM
! .code 16
.macro interwork register
.code 16
--- 1118,1150 ----
.globl _arm_return
_arm_return:
RETLDM
!
! .globl _arm_return_r7
! _arm_return_r7:
! ldr lr, [r7, #-4]
! bx lr
!
! .globl _arm_return_r11
! _arm_return_r11:
! ldr lr, [r11, #-4]
! bx lr
!
! .macro interwork_with_frame frame, register, name, return
! .code 16
!
! THUMB_FUNC_START \name
!
! bx pc
! nop
!
! .code 32
! tst \register, #1
! streq lr, [\frame, #-4]
! adreq lr, _arm_return_\frame
! bx \register
!
! SIZE (\name)
! .endm
.macro interwork register
.code 16
*************** LSYM(Lchange_\register):
*** 1124,1129 ****
--- 1163,1171 ----
bx \register
SIZE (_interwork_call_via_\register)
+
+ interwork_with_frame r7,\register,_interwork_r7_call_via_\register
+ interwork_with_frame r11,\register,_interwork_r11_call_via_\register
.endm
interwork r0