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]

Patch for -mcaller-super-interworking & stack arguments


-mcaller-super-interworking causes all indirect calls to use an
_interwork_call_via_rN stub.  If the target address is an ARM function,
this stub will push the (thumb) return address onto the stack and get
the ARM function to return to _arm_return instead.

Unfortunately, pushing the return address onto the stack means that thumb
functions can't pass stack arguments to ARM functions.  The suggested fix
is to define alternative interworking functions that store the return
address at [r7, #-4] instead.  This of course requires the caller to
use a frame pointer and to provide appropriate scratch space there.

If the caller used a frame pointer anyway, I think the overhead of this
approach should be very low.  We just need to bump up the size of the
frame and fiddle with the elimination offsets.  The only source of
extra insns should be from frame accesses that are on the borderline
between being in-range and out-of-range.

On the other hand, if the function _didn't_ need a frame pointer for
anything else, then there is definitely a big overhead.  The patch
therefore only uses these new functions if there are some outgoing
stack arguments.  (As per the comment in the patch, I don't think
we can really refine the condition much more than that.)

This patch has been regression tested on arm-elf, test pattern:

    arm-sim{,-mthumb,-mthumb/-mcaller-super-interworking}

I admit this doesn't exercise thumb->ARM calls that much since the
third pattern will link against the thumb multilibs.  Trying to test
against a --disable-multilib build is useless because of all the extra
linker warnings.

Even so, the thumb->ARM route does get some testing from compiler-generated
trampolines and thunks, and the patch does fix gcc.dg/trampoline-1.c and
g++.old-deja/g++.jason/thunk3.C.  There were no regressions.  OK to install?

Richard


	* config/arm/arm.h (CALLER_INTERWORKING_SLOT_SIZE): New macro.
	(FRAME_POINTER_REQUIRED): True if CALLER_INTERWORKING_SLOT_SIZE > 0.
	* config/arm/arm.c (arm_get_frame_offsets): Add
	CALLER_INTERWORKING_SLOT_SIZE bytes to the soft frame pointer offset.
	* config/arm/arm.md (*call_reg_thumb, *call_value_reg_thumb): Use
	_interwork_fp_call_via_rN if some arguments are passed on the stack.
	* config/arm/lib1funcs.asm (_arm_fp_return): New function.
	(interwork): Add _interwork_fp_call_via_rN() functions.

Index: config/arm/lib1funcs.asm
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/lib1funcs.asm,v
retrieving revision 1.31
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.31 lib1funcs.asm
*** config/arm/lib1funcs.asm	15 May 2004 17:31:51 -0000	1.31
--- config/arm/lib1funcs.asm	5 Aug 2004 06:43:18 -0000
*************** 1:
*** 1035,1041 ****
     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
--- 1035,1049 ----
     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 two 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_fp_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.  */
  	
  	.text
  	.align 0
*************** 1:
*** 1044,1050 ****
  	.globl _arm_return
  _arm_return:
  	RETLDM
! 	.code   16
  
  .macro interwork register
  	.code	16
--- 1052,1062 ----
  	.globl _arm_return
  _arm_return:
  	RETLDM
! 
! 	.globl _arm_fp_return
! _arm_fp_return:
! 	ldr	lr, [r7, #-4]
! 	bx	lr
  
  .macro interwork register
  	.code	16
*************** LSYM(Lchange_\register):
*** 1063,1068 ****
--- 1075,1097 ----
  	bx	\register
  
  	SIZE	(_interwork_call_via_\register)
+ 
+ 	.code	16
+ 
+ 	THUMB_FUNC_START _interwork_fp_call_via_\register
+ 
+ 	bx	pc
+ 	nop
+ 
+ 	.code	32
+ 	.globl LSYM(Lfp_change_\register)
+ LSYM(Lfp_change_\register):
+ 	tst	\register, #1
+ 	streq	lr, [r7, #-4]
+ 	adreq	lr, _arm_fp_return
+ 	bx	\register
+ 
+ 	SIZE	(_interwork_fp_call_via_\register)
  .endm
  	
  	interwork r0
Index: config/arm/arm.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.h,v
retrieving revision 1.245
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.245 arm.h
*** config/arm/arm.h	14 Jul 2004 17:51:18 -0000	1.245
--- config/arm/arm.h	5 Aug 2004 06:43:21 -0000
*************** #define FIRST_PSEUDO_REGISTER   96
*** 1043,1048 ****
--- 1043,1049 ----
     functions, or simple tail call functions.  */
  #define FRAME_POINTER_REQUIRED					\
    (current_function_has_nonlocal_label				\
+    || CALLER_INTERWORKING_SLOT_SIZE > 0				\
     || (TARGET_ARM && TARGET_APCS_FRAME && ! leaf_function_p ()))
  
  /* Return number of consecutive hard regs needed starting at reg REGNO
*************** #define STACK_GROWS_DOWNWARD  1
*** 1501,1506 ****
--- 1502,1522 ----
     goes at a more negative offset in the frame.  */
  #define FRAME_GROWS_DOWNWARD 1
  
+ /* The amount of scratch space needed by _interwork_fp_call_via_rN().
+    When present, it is one word in size, and sits at the top of the frame,
+    between FRAME_POINTER_REGNUM and THUMB_HARD_FRAME_POINTER_REGNUM.
+ 
+    We only need _interwork_fp_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.381
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.381 arm.c
*** config/arm/arm.c	3 Aug 2004 14:30:46 -0000	1.381
--- config/arm/arm.c	5 Aug 2004 06:43:35 -0000
*************** arm_get_frame_offsets (void)
*** 10116,10122 ****
  
    /* 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)
--- 10116,10122 ----
  
    /* 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)
Index: config/arm/arm.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.md,v
retrieving revision 1.174
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.174 arm.md
*** config/arm/arm.md	3 Aug 2004 13:27:02 -0000	1.174
--- config/arm/arm.md	5 Aug 2004 06:43:46 -0000
*************** (define_insn "*call_reg_thumb"
*** 7430,7439 ****
    "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")]
  )
--- 7430,7441 ----
    "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
!       return \"bl\\t%__interwork_fp_call_via_%0\";
    }"
    [(set_attr "type" "call")]
  )
*************** (define_insn "*call_value_reg_thumb"
*** 7520,7529 ****
    "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")]
  )
--- 7522,7533 ----
    "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
!       return \"bl\\t%__interwork_fp_call_via_%1\";
    }"
    [(set_attr "type" "call")]
  )


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