Index: arm.c =================================================================== --- arm.c (revision 135576) +++ arm.c (working copy) @@ -62,6 +62,7 @@ const struct attribute_spec arm_attribut 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, @@ -10781,6 +10782,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. */ @@ -10833,7 +10852,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 @@ -10918,6 +10939,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; } @@ -12053,7 +12094,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) { @@ -12100,7 +12142,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. */ @@ -12192,14 +12235,9 @@ arm_compute_initial_elimination_offset ( 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 @@ -12485,6 +12523,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); @@ -16928,62 +16969,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); + gcc_assert(regno <= LAST_LO_REGNUM); - /* Choose an arbitrary, non-argument low register. */ - reg = gen_rtx_REG (SImode, LAST_LO_REGNUM); + reg = gen_rtx_REG (SImode, regno); - /* 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)); + emit_insn (gen_movsi (reg, GEN_INT (- amount))); - /* 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); - - 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)); } }