arm.h (CONDITIONAL_REGISTER_USAGE): Make r11 fixed and global for -mcaller-super...
authorRichard Sandiford <rsandifo@redhat.com>
Thu, 14 Oct 2004 07:37:11 +0000 (07:37 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Thu, 14 Oct 2004 07:37:11 +0000 (07:37 +0000)
* 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().

From-SVN: r89031

gcc/ChangeLog
gcc/config/arm/arm.c
gcc/config/arm/arm.h
gcc/config/arm/arm.md
gcc/config/arm/lib1funcs.asm

index 9eb34ecb7f5ea6ae025b437cdcbbaf8256fbfbbc..bc9ad2a90426f6fe193925b6c950870d51c45993 100644 (file)
@@ -1,3 +1,21 @@
+2004-10-14  Richard Sandiford  <rsandifo@redhat.com>
+
+       * 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().
+
 2004-10-14  Ben Elliston  <bje@au.ibm.com>
 
        PR other/17900
index 02ee7cad19d2688f250adacba3203668bccd8de8..498218d077b2e213bdc329f1fdda45740d4320bf 100644 (file)
@@ -8741,6 +8741,9 @@ thumb_compute_save_reg_mask (void)
     mask |= (1 << 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 ())
@@ -9820,7 +9823,7 @@ arm_get_frame_offsets (void)
 
   /* Saved registers include the stack frame.  */
   offsets->saved_regs = offsets->saved_args + saved;
-  offsets->soft_frame = offsets->saved_regs;
+  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)
@@ -12977,6 +12980,9 @@ thumb_expand_prologue (void)
                                   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);
 
   amount = offsets->outgoing_args - offsets->saved_regs;
   if (amount)
index 446062feea9b4339db02724e99cfd0215d7533c7..8e3844787eff10950c5ae8b46c91f33927a7b75e 100644 (file)
@@ -917,10 +917,16 @@ extern const char * structure_size_string;
       fixed_regs[10]     = 1;                                  \
       call_used_regs[10] = 1;                                  \
     }                                                          \
-  if (TARGET_APCS_FRAME)                                       \
+  /* -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                         \
 }
@@ -1519,6 +1525,20 @@ enum reg_class
    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                          \
+   && current_function_outgoing_args_size != 0         \
+   ? UNITS_PER_WORD : 0)
+
 /* 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 6c07a85488363e8fa7e973c25326b7dff5293a42..375f92eef54fd73938115c331a9eebb2fcfc88cf 100644 (file)
   "TARGET_THUMB && !arm_arch5"
   "*
   {
-    if (TARGET_CALLER_INTERWORKING)
+    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%__call_via_%0\";
+      return \"bl\\t%__interwork_r11_call_via_%0\";
   }"
   [(set_attr "type" "call")]
 )
   "TARGET_THUMB && !arm_arch5"
   "*
   {
-    if (TARGET_CALLER_INTERWORKING)
+    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%__call_via_%1\";
+      return \"bl\\t%__interwork_r11_call_via_%1\";
   }"
   [(set_attr "type" "call")]
 )
index a432ef22fa8dc57fa3ca0169e7b402bb4d3df930..d6bf195ee2d610a1d7a9fd959ade02efa17e82bb 100644 (file)
@@ -1098,7 +1098,20 @@ LSYM(Lover12):
    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.  */
+   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
@@ -1107,7 +1120,33 @@ LSYM(Lover12):
        .globl _arm_return
 _arm_return:
        RETLDM
-       .code   16
+
+       .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
@@ -1126,6 +1165,9 @@ LSYM(Lchange_\register):
        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