From a25036452a7713a01174787b1b13c96eff1534c6 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 14 Oct 2004 07:37:11 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 18 ++++++++++++++ gcc/config/arm/arm.c | 8 ++++++- gcc/config/arm/arm.h | 22 ++++++++++++++++- gcc/config/arm/arm.md | 16 +++++++++---- gcc/config/arm/lib1funcs.asm | 46 ++++++++++++++++++++++++++++++++++-- 5 files changed, 102 insertions(+), 8 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9eb34ecb7f5..bc9ad2a9042 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2004-10-14 Richard Sandiford + + * 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 PR other/17900 diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 02ee7cad19d..498218d077b 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 446062feea9..8e3844787ef 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 6c07a854883..375f92eef54 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 a432ef22fa8..d6bf195ee2d 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 -- 2.30.2