diff options
author | Andrew Jenner <andrew@codesourcery.com> | 2008-07-30 16:28:01 +0000 |
---|---|---|
committer | Andrew Jenner <andrewjenner@gcc.gnu.org> | 2008-07-30 16:28:01 +0000 |
commit | 35596784bce48f0115713211d8a50a8fcbf5765d (patch) | |
tree | 6fba9d2332e924a4748f8bebafcd41d640341793 /gcc/config/arm | |
parent | 5cc6fa4136cc864b40250c61bffda2f506249192 (diff) | |
download | gcc-35596784bce48f0115713211d8a50a8fcbf5765d.zip gcc-35596784bce48f0115713211d8a50a8fcbf5765d.tar.gz gcc-35596784bce48f0115713211d8a50a8fcbf5765d.tar.bz2 |
arm.c (arm_compute_static_chain_stack_bytes): New function.
* config/arm/arm.c (arm_compute_static_chain_stack_bytes): New
function.
(arm_compute_initial_elimination_offset): Use it.
(arm_compute_save_reg_mask): Include static chain save slot when
calculating alignment.
(arm_get_frame_offsets): Ditto.
(thumb1_compute_save_reg_mask): Ensure we have a low register saved
that we can use to decrement the stack when the stack decrement
could be too big for an immediate value in a single insn.
(thumb1_expand_prologue): Avoid using r12 for stack decrement.
From-SVN: r138327
Diffstat (limited to 'gcc/config/arm')
-rw-r--r-- | gcc/config/arm/arm.c | 128 |
1 files changed, 66 insertions, 62 deletions
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 7410517..a89229e 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -62,6 +62,7 @@ const struct attribute_spec arm_attribute_table[]; void (*arm_lang_output_object_attributes_hook)(void); /* Forward function declarations. */ +static int arm_compute_static_chain_stack_bytes (void); static arm_stack_offsets *arm_get_frame_offsets (void); static void arm_add_gc_roots (void); static int arm_gen_constant (enum rtx_code, enum machine_mode, rtx, @@ -10792,6 +10793,24 @@ arm_compute_save_reg0_reg12_mask (void) } +/* Compute the number of bytes used to store the static chain register on the + stack, above the stack frame. We need to know this accurately to get the + alignment of the rest of the stack frame correct. */ + +static int arm_compute_static_chain_stack_bytes (void) +{ + unsigned long func_type = arm_current_func_type (); + int static_chain_stack_bytes = 0; + + if (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM && + IS_NESTED (func_type) && + df_regs_ever_live_p (3) && crtl->args.pretend_args_size == 0) + static_chain_stack_bytes = 4; + + return static_chain_stack_bytes; +} + + /* Compute a bit mask of which registers need to be saved on the stack for the current function. This is used by arm_get_frame_offsets, which may add extra registers. */ @@ -10844,7 +10863,9 @@ arm_compute_save_reg_mask (void) if (TARGET_REALLY_IWMMXT && ((bit_count (save_reg_mask) - + ARM_NUM_INTS (crtl->args.pretend_args_size)) % 2) != 0) + + ARM_NUM_INTS (crtl->args.pretend_args_size + + arm_compute_static_chain_stack_bytes()) + ) % 2) != 0) { /* The total number of registers that are going to be pushed onto the stack is odd. We need to ensure that the stack @@ -10929,6 +10950,26 @@ thumb1_compute_save_reg_mask (void) mask |= 1 << reg; } + /* The 504 below is 8 bytes less than 512 because there are two possible + alignment words. We can't tell here if they will be present or not so we + have to play it safe and assume that they are. */ + if ((CALLER_INTERWORKING_SLOT_SIZE + + ROUND_UP_WORD (get_frame_size ()) + + crtl->outgoing_args_size) >= 504) + { + /* This is the same as the code in thumb1_expand_prologue() which + determines which register to use for stack decrement. */ + for (reg = LAST_ARG_REGNUM + 1; reg <= LAST_LO_REGNUM; reg++) + if (mask & (1 << reg)) + break; + + if (reg > LAST_LO_REGNUM) + { + /* Make sure we have a register available for stack decrement. */ + mask |= 1 << LAST_LO_REGNUM; + } + } + return mask; } @@ -12064,7 +12105,8 @@ arm_get_frame_offsets (void) offsets->saved_args = crtl->args.pretend_args_size; /* In Thumb mode this is incorrect, but never used. */ - offsets->frame = offsets->saved_args + (frame_pointer_needed ? 4 : 0); + offsets->frame = offsets->saved_args + (frame_pointer_needed ? 4 : 0) + + arm_compute_static_chain_stack_bytes(); if (TARGET_32BIT) { @@ -12111,7 +12153,8 @@ arm_get_frame_offsets (void) } /* Saved registers include the stack frame. */ - offsets->saved_regs = offsets->saved_args + saved; + offsets->saved_regs = offsets->saved_args + saved + + arm_compute_static_chain_stack_bytes(); 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. */ @@ -12203,14 +12246,9 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to) return offsets->soft_frame - offsets->saved_args; case ARM_HARD_FRAME_POINTER_REGNUM: - /* If there is no stack frame then the hard - frame pointer and the arg pointer coincide. */ - if (offsets->frame == offsets->saved_regs) - return 0; - /* FIXME: Not sure about this. Maybe we should always return 0 ? */ - return (frame_pointer_needed - && cfun->static_chain_decl != NULL - && ! cfun->machine->uses_anonymous_args) ? 4 : 0; + /* This is only non-zero in the case where the static chain register + is stored above the frame. */ + return offsets->frame - offsets->saved_args - 4; case STACK_POINTER_REGNUM: /* If nothing has been pushed on the stack at all @@ -12498,6 +12536,9 @@ arm_expand_prologue (void) insn = emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx); else if (args_to_push == 0) { + gcc_assert(arm_compute_static_chain_stack_bytes() == 4); + saved_regs += 4; + rtx dwarf; insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx); @@ -17008,62 +17049,25 @@ thumb1_expand_prologue (void) been pushed at the start of the prologue and so we can corrupt it now. */ for (regno = LAST_ARG_REGNUM + 1; regno <= LAST_LO_REGNUM; regno++) - if (live_regs_mask & (1 << regno) - && !(frame_pointer_needed - && (regno == THUMB_HARD_FRAME_POINTER_REGNUM))) + if (live_regs_mask & (1 << regno)) break; - if (regno > LAST_LO_REGNUM) /* Very unlikely. */ - { - rtx spare = gen_rtx_REG (SImode, IP_REGNUM); - - /* Choose an arbitrary, non-argument low register. */ - reg = gen_rtx_REG (SImode, LAST_LO_REGNUM); - - /* Save it by copying it into a high, scratch register. */ - emit_insn (gen_movsi (spare, reg)); - /* Add a USE to stop propagate_one_insn() from barfing. */ - emit_insn (gen_prologue_use (spare)); + gcc_assert(regno <= LAST_LO_REGNUM); - /* Decrement the stack. */ - emit_insn (gen_movsi (reg, GEN_INT (- amount))); - insn = emit_insn (gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, reg)); - RTX_FRAME_RELATED_P (insn) = 1; - dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx, - plus_constant (stack_pointer_rtx, - -amount)); - RTX_FRAME_RELATED_P (dwarf) = 1; - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf, - REG_NOTES (insn)); - - /* Restore the low register's original value. */ - emit_insn (gen_movsi (reg, spare)); - - /* Emit a USE of the restored scratch register, so that flow - analysis will not consider the restore redundant. The - register won't be used again in this function and isn't - restored by the epilogue. */ - emit_insn (gen_prologue_use (reg)); - } - else - { - reg = gen_rtx_REG (SImode, regno); + reg = gen_rtx_REG (SImode, regno); - emit_insn (gen_movsi (reg, GEN_INT (- amount))); + emit_insn (gen_movsi (reg, GEN_INT (- amount))); - insn = emit_insn (gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, reg)); - RTX_FRAME_RELATED_P (insn) = 1; - dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx, - plus_constant (stack_pointer_rtx, - -amount)); - RTX_FRAME_RELATED_P (dwarf) = 1; - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf, - REG_NOTES (insn)); - } + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, + stack_pointer_rtx, reg)); + RTX_FRAME_RELATED_P (insn) = 1; + dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx, + plus_constant (stack_pointer_rtx, + -amount)); + RTX_FRAME_RELATED_P (dwarf) = 1; + REG_NOTES (insn) + = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf, + REG_NOTES (insn)); } } |