This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Patch for -mcaller-super-interworking & stack arguments


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]