diff options
author | Richard Sandiford <rsandifo@redhat.com> | 2004-10-14 07:37:11 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2004-10-14 07:37:11 +0000 |
commit | a25036452a7713a01174787b1b13c96eff1534c6 (patch) | |
tree | ea8dff30aa2a512ad4558c2e8c0f0d85f3ed1300 | |
parent | ef9af07733703a8309a44b80b1b2d0e35bdd0d87 (diff) | |
download | gcc-a25036452a7713a01174787b1b13c96eff1534c6.zip gcc-a25036452a7713a01174787b1b13c96eff1534c6.tar.gz gcc-a25036452a7713a01174787b1b13c96eff1534c6.tar.bz2 |
arm.h (CONDITIONAL_REGISTER_USAGE): Make r11 fixed and global for -mcaller-super-interworking.
* 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
-rw-r--r-- | gcc/ChangeLog | 18 | ||||
-rw-r--r-- | gcc/config/arm/arm.c | 8 | ||||
-rw-r--r-- | gcc/config/arm/arm.h | 22 | ||||
-rw-r--r-- | gcc/config/arm/arm.md | 16 | ||||
-rw-r--r-- | gcc/config/arm/lib1funcs.asm | 46 |
5 files changed, 102 insertions, 8 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9eb34ec..bc9ad2a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 02ee7ca..498218d 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -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) diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 446062f..8e38447 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -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 diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 6c07a85..375f92e 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -7435,10 +7435,14 @@ "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")] ) @@ -7525,10 +7529,14 @@ "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")] ) diff --git a/gcc/config/arm/lib1funcs.asm b/gcc/config/arm/lib1funcs.asm index a432ef2..d6bf195 100644 --- a/gcc/config/arm/lib1funcs.asm +++ b/gcc/config/arm/lib1funcs.asm @@ -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 |