aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2000-11-16 19:23:15 +0000
committerNick Clifton <nickc@gcc.gnu.org>2000-11-16 19:23:15 +0000
commit68dfd979ac149deff93a104e4bb4d7a37ccd2123 (patch)
treed58f3745afa034b83e7ea37a2d5d605868500ef8 /gcc
parentcdb3cf85467783c2820506f0e698056a10cd1109 (diff)
downloadgcc-68dfd979ac149deff93a104e4bb4d7a37ccd2123.zip
gcc-68dfd979ac149deff93a104e4bb4d7a37ccd2123.tar.gz
gcc-68dfd979ac149deff93a104e4bb4d7a37ccd2123.tar.bz2
Fix nested function support for the ARM
From-SVN: r37503
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/config/arm/arm.c84
-rw-r--r--gcc/config/arm/arm.h9
3 files changed, 97 insertions, 8 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7f1cea5..9866dc4 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,15 @@
+2000-11-16 Nick Clifton <nickc@redhat.com>
+
+ * config/arm/arm.c (output_arm_prologue): Note nested functions.
+ (arm_expand_prologue): For nested functions preserve the
+ static chain register during stack frame creation.
+
+ * config/arm/arm.h (STATIC_CHAIN_REGNUM): Change to 12.
+ (ARM_INITIAL_FRAME_ELIMINATION_OFFSET): For a nested function
+ with a stack frame there is a 4 byte gap between the arg
+ pointer and the hard frame pointer (used to preserve the
+ static chain register during stack frame creation).
+
2000-11-16 DJ Delorie <dj@redhat.com>
* rtl.c (read_rtx): Provide suitable names for unnamed
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 7a04dd7..3bb5522 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -6776,6 +6776,9 @@ output_arm_prologue (f, frame_size)
if (volatile_func)
asm_fprintf (f, "\t%@ Volatile function.\n");
+ if (current_function_needs_context)
+ asm_fprintf (f, "\t%@ Nested function.\n");
+
if (current_function_anonymous_args && current_function_pretend_args_size)
store_arg_regs = 1;
@@ -7318,6 +7321,9 @@ arm_expand_prologue ()
the call-saved regs. */
int volatile_func = arm_volatile_func ();
rtx insn;
+ rtx ip_rtx;
+ int fp_offset = 0;
+
/* Naked functions don't have prologues. */
if (arm_naked_function_p (current_function_decl))
@@ -7345,11 +7351,59 @@ arm_expand_prologue ()
live_regs_mask |= 1 << LR_REGNUM;
}
+ ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
+
if (frame_pointer_needed)
{
+ if (current_function_needs_context)
+ {
+ /* The Static chain register is the same as the IP register
+ used as a scratch register during stack frame creation.
+ To get around this need to find somewhere to store IP
+ whilst the frame is being created. We try the following
+ places in order:
+
+ 1. An unused argument register.
+ 2. A slot on the stack above the frame. (This only
+ works if the function is not a varargs function).
+
+ If neither of these places is available, we abort (for now). */
+ if (regs_ever_live[3] == 0)
+ {
+ insn = gen_rtx_REG (SImode, 3);
+ insn = gen_rtx_SET (SImode, insn, ip_rtx);
+ insn = emit_insn (insn);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ else if (current_function_pretend_args_size == 0)
+ {
+ insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
+ insn = gen_rtx_MEM (SImode, insn);
+ insn = gen_rtx_SET (VOIDmode, insn, ip_rtx);
+ insn = emit_insn (insn);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ fp_offset = 4;
+ }
+ else
+ /* FIXME - the way to handle this situation is to allow
+ the pretend args to be dumped onto the stack, then
+ reuse r3 to save IP. This would involve moving the
+ copying os SP into IP until after the pretend args
+ have been dumped, but this is not too hard. */
+ error ("Unable to find a temporary location for static chanin register");
+ }
+
live_regs_mask |= 0xD800;
- insn = emit_insn (gen_movsi (gen_rtx_REG (SImode, IP_REGNUM),
- stack_pointer_rtx));
+
+ if (fp_offset)
+ {
+ insn = gen_rtx_PLUS (SImode, stack_pointer_rtx, GEN_INT (fp_offset));
+ insn = gen_rtx_SET (SImode, ip_rtx, insn);
+ }
+ else
+ insn = gen_movsi (ip_rtx, stack_pointer_rtx);
+
+ insn = emit_insn (insn);
RTX_FRAME_RELATED_P (insn) = 1;
}
@@ -7426,11 +7480,29 @@ arm_expand_prologue ()
if (frame_pointer_needed)
{
- insn = GEN_INT (-(4 + current_function_pretend_args_size));
- insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
- gen_rtx_REG (SImode, IP_REGNUM),
- insn));
+ insn = GEN_INT (-(4 + current_function_pretend_args_size + fp_offset));
+ insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn));
RTX_FRAME_RELATED_P (insn) = 1;
+
+ if (current_function_needs_context)
+ {
+ /* Recover the static chain register. */
+ if (regs_ever_live [3] == 0)
+ {
+ insn = gen_rtx_REG (SImode, 3);
+ insn = gen_rtx_SET (SImode, ip_rtx, insn);
+ insn = emit_insn (insn);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ else /* if (current_function_pretend_args_size == 0) */
+ {
+ insn = gen_rtx_PLUS (SImode, hard_frame_pointer_rtx, GEN_INT (4));
+ insn = gen_rtx_MEM (SImode, insn);
+ insn = gen_rtx_SET (SImode, ip_rtx, insn);
+ insn = emit_insn (insn);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
}
if (amount != const0_rtx)
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 3078a03..f9d5cd8 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -891,7 +891,7 @@ extern const char * structure_size_string;
/* The native (Norcroft) Pascal compiler for the ARM passes the static chain
as an invisible last argument (possible since varargs don't exist in
Pascal), so the following is not true. */
-#define STATIC_CHAIN_REGNUM (TARGET_ARM ? 8 : 9)
+#define STATIC_CHAIN_REGNUM (TARGET_ARM ? 12 : 9)
/* Define this to be where the real frame pointer is if it is not possible to
work out the offset between the frame pointer and the automatic variables
@@ -1600,7 +1600,12 @@ typedef struct
{ \
int volatile_func = arm_volatile_func (); \
if ((FROM) == ARG_POINTER_REGNUM && (TO) == HARD_FRAME_POINTER_REGNUM)\
- (OFFSET) = 0; \
+ { \
+ if (! current_function_needs_context || ! frame_pointer_needed) \
+ (OFFSET) = 0; \
+ else \
+ (OFFSET) = 4; \
+ } \
else if ((FROM) == FRAME_POINTER_REGNUM \
&& (TO) == STACK_POINTER_REGNUM) \
(OFFSET) = current_function_outgoing_args_size \