diff options
author | Nick Clifton <nickc@redhat.com> | 2000-11-16 19:23:15 +0000 |
---|---|---|
committer | Nick Clifton <nickc@gcc.gnu.org> | 2000-11-16 19:23:15 +0000 |
commit | 68dfd979ac149deff93a104e4bb4d7a37ccd2123 (patch) | |
tree | d58f3745afa034b83e7ea37a2d5d605868500ef8 /gcc | |
parent | cdb3cf85467783c2820506f0e698056a10cd1109 (diff) | |
download | gcc-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/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/config/arm/arm.c | 84 | ||||
-rw-r--r-- | gcc/config/arm/arm.h | 9 |
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 \ |