aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <rsandifo@redhat.com>2004-10-14 07:37:11 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2004-10-14 07:37:11 +0000
commita25036452a7713a01174787b1b13c96eff1534c6 (patch)
treeea8dff30aa2a512ad4558c2e8c0f0d85f3ed1300
parentef9af07733703a8309a44b80b1b2d0e35bdd0d87 (diff)
downloadgcc-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/ChangeLog18
-rw-r--r--gcc/config/arm/arm.c8
-rw-r--r--gcc/config/arm/arm.h22
-rw-r--r--gcc/config/arm/arm.md16
-rw-r--r--gcc/config/arm/lib1funcs.asm46
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