From bb21ed29b7f3b2f420791d5c3beed9920da6c5bf Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 12 Mar 2008 18:58:47 +0000 Subject: [PATCH] 2008-03-12 Paul Brook gcc/ * config/arm/arm.c (use_return_insn): Use offsets->saved_regs_mask instead of {arm,thumb}_compute_save_reg_mask. (output_return_instruction): Ditto. (thumb_unexpanded_epilogue): Ditto. (thumb1_expand_prologue): Ditto. (thumb1_output_function_prologue): Ditto. (arm_set_return_address): Ditto. (thumb_set_return_address): Ditto. (arm_get_frame_offsets): Set offsets->saved_regs_mask. Push extra regs to achieve stack alignment. (thumb1_compute_save_reg_mask): Fix compiler warning. (arm_output_epilogue): Use offsets->saved_regs_mask. Adjust stack pointer by poping call clobered registers. (arm_expand_prologue): Use offsets->saved_regs_mask. Adjust stack pointer by pushing extra registers. * gcc/config/arm.h (arm_stack_offsets): Add saved_regs_mask. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@133148 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 19 ++++++++ gcc/config/arm/arm.c | 135 ++++++++++++++++++++++++++++++++++++++++++--------- gcc/config/arm/arm.h | 1 + 3 files changed, 132 insertions(+), 23 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index dfdbfc26a19..4bdbd1b7dca 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2008-03-12 Paul Brook + + * config/arm/arm.c (use_return_insn): Use offsets->saved_regs_mask + instead of {arm,thumb}_compute_save_reg_mask. + (output_return_instruction): Ditto. + (thumb_unexpanded_epilogue): Ditto. + (thumb1_expand_prologue): Ditto. + (thumb1_output_function_prologue): Ditto. + (arm_set_return_address): Ditto. + (thumb_set_return_address): Ditto. + (arm_get_frame_offsets): Set offsets->saved_regs_mask. Push extra + regs to achieve stack alignment. + (thumb1_compute_save_reg_mask): Fix compiler warning. + (arm_output_epilogue): Use offsets->saved_regs_mask. + Adjust stack pointer by poping call clobered registers. + (arm_expand_prologue): Use offsets->saved_regs_mask. + Adjust stack pointer by pushing extra registers. + * gcc/config/arm.h (arm_stack_offsets): Add saved_regs_mask. + 2008-03-12 Paolo Bonzini PR tree-opt/35422 diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 531dd1fe3eb..304b4302cc6 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -74,7 +74,6 @@ static int thumb1_base_register_rtx_p (rtx, enum machine_mode, int); inline static int thumb1_index_register_rtx_p (rtx, int); static int thumb_far_jump_used_p (void); static bool thumb_force_lr_save (void); -static unsigned long thumb1_compute_save_reg_mask (void); static int const_ok_for_op (HOST_WIDE_INT, enum rtx_code); static rtx emit_sfm (int, int); static unsigned arm_size_return_regs (void); @@ -1666,7 +1665,7 @@ use_return_insn (int iscond, rtx sibling) && stack_adjust == 4))) return 0; - saved_int_regs = arm_compute_save_reg_mask (); + saved_int_regs = offsets->saved_regs_mask; /* Unfortunately, the insn @@ -10750,7 +10749,8 @@ arm_compute_save_reg0_reg12_mask (void) /* Compute a bit mask of which registers need to be - saved on the stack for the current function. */ + saved on the stack for the current function. + This is used by arm_get_frame_offsets, which may add extra registers. */ static unsigned long arm_compute_save_reg_mask (void) @@ -10878,7 +10878,7 @@ thumb1_compute_save_reg_mask (void) reg = thumb_find_work_register (1 << LAST_LO_REGNUM); /* Make sure the register returned by thumb_find_work_register is not part of the return value. */ - if (reg * UNITS_PER_WORD <= arm_size_return_regs ()) + if (reg * UNITS_PER_WORD <= (unsigned) arm_size_return_regs ()) reg = LAST_LO_REGNUM; if (! call_used_regs[reg]) @@ -10975,7 +10975,8 @@ output_return_instruction (rtx operand, int really_return, int reverse) return_used_this_function = 1; - live_regs_mask = arm_compute_save_reg_mask (); + offsets = arm_get_frame_offsets (); + live_regs_mask = offsets->saved_regs_mask; if (live_regs_mask) { @@ -11037,7 +11038,6 @@ output_return_instruction (rtx operand, int really_return, int reverse) { unsigned HOST_WIDE_INT stack_adjust; - offsets = arm_get_frame_offsets (); stack_adjust = offsets->outgoing_args - offsets->saved_regs; gcc_assert (stack_adjust == 0 || stack_adjust == 4); @@ -11285,7 +11285,7 @@ arm_output_epilogue (rtx sibling) gcc_assert (!current_function_calls_eh_return || really_return); offsets = arm_get_frame_offsets (); - saved_regs_mask = arm_compute_save_reg_mask (); + saved_regs_mask = offsets->saved_regs_mask; if (TARGET_IWMMXT) lrm_count = bit_count (saved_regs_mask); @@ -11482,8 +11482,35 @@ arm_output_epilogue (rtx sibling) } else { + unsigned long count; operands[0] = stack_pointer_rtx; amount = offsets->outgoing_args - offsets->saved_regs; + /* pop call clobbered registers if it avoids a + separate stack adjustment. */ + count = offsets->saved_regs - offsets->saved_args; + if (optimize_size + && count != 0 + && !current_function_calls_eh_return + && bit_count(saved_regs_mask) * 4 == count + && !IS_INTERRUPT (func_type) + && !cfun->tail_call_emit) + { + unsigned long mask; + mask = (1 << (arm_size_return_regs() / 4)) - 1; + mask ^= 0xf; + mask &= ~saved_regs_mask; + reg = 0; + while (bit_count (mask) * 4 > amount) + { + while ((mask & (1 << reg)) == 0) + reg++; + mask &= ~(1 << reg); + } + if (bit_count (mask) * 4 == amount) { + amount = 0; + saved_regs_mask |= mask; + } + } } if (amount) @@ -11954,7 +11981,8 @@ thumb_force_lr_save (void) /* Calculate stack offsets. These are used to calculate register elimination - offsets and in prologue/epilogue code. */ + offsets and in prologue/epilogue code. Also calculates which registers + should be saved. */ static arm_stack_offsets * arm_get_frame_offsets (void) @@ -11963,7 +11991,9 @@ arm_get_frame_offsets (void) unsigned long func_type; int leaf; int saved; + int core_saved; HOST_WIDE_INT frame_size; + int i; offsets = &cfun->machine->stack_offsets; @@ -11996,7 +12026,9 @@ arm_get_frame_offsets (void) { unsigned int regno; - saved = bit_count (arm_compute_save_reg_mask ()) * 4; + offsets->saved_regs_mask = arm_compute_save_reg_mask (); + core_saved = bit_count (offsets->saved_regs_mask) * 4; + saved = core_saved; /* We know that SP will be doubleword aligned on entry, and we must preserve that condition at any subroutine call. We also require the @@ -12027,7 +12059,9 @@ arm_get_frame_offsets (void) } else /* TARGET_THUMB1 */ { - saved = bit_count (thumb1_compute_save_reg_mask ()) * 4; + offsets->saved_regs_mask = thumb1_compute_save_reg_mask (); + core_saved = bit_count (offsets->saved_regs_mask) * 4; + saved = core_saved; if (TARGET_BACKTRACE) saved += 16; } @@ -12047,7 +12081,39 @@ arm_get_frame_offsets (void) /* Ensure SFP has the correct alignment. */ if (ARM_DOUBLEWORD_ALIGN && (offsets->soft_frame & 7)) - offsets->soft_frame += 4; + { + offsets->soft_frame += 4; + /* Try to align stack by pushing an extra reg. Don't bother doing this + when there is a stack frame as the alignment will be rolled into + the normal stack adjustment. */ + if (frame_size + current_function_outgoing_args_size == 0) + { + int reg = -1; + + for (i = 4; i <= (TARGET_THUMB1 ? LAST_LO_REGNUM : 11); i++) + { + if ((offsets->saved_regs_mask & (1 << i)) == 0) + { + reg = i; + break; + } + } + + if (reg == -1 && arm_size_return_regs () <= 12 + && !cfun->tail_call_emit) + { + /* Push/pop an argument register (r3) if all callee saved + registers are already being pushed. */ + reg = 3; + } + + if (reg != -1) + { + offsets->saved_regs += 4; + offsets->saved_regs_mask |= (1 << reg); + } + } + } offsets->locals_base = offsets->soft_frame + frame_size; offsets->outgoing_args = (offsets->locals_base @@ -12303,7 +12369,8 @@ arm_expand_prologue (void) args_to_push = current_function_pretend_args_size; /* Compute which register we will have to save onto the stack. */ - live_regs_mask = arm_compute_save_reg_mask (); + offsets = arm_get_frame_offsets (); + live_regs_mask = offsets->saved_regs_mask; ip_rtx = gen_rtx_REG (SImode, IP_REGNUM); @@ -12456,8 +12523,28 @@ arm_expand_prologue (void) if (live_regs_mask) { - insn = emit_multi_reg_push (live_regs_mask); saved_regs += bit_count (live_regs_mask) * 4; + if (optimize_size && !frame_pointer_needed + && saved_regs == offsets->saved_regs - offsets->saved_args) + { + /* If no coprocessor registers are being pushed and we don't have + to worry about a frame pointer then push extra registers to + create the stack frame. This is done is a way that does not + alter the frame layout, so is independent of the epilogue. */ + int n; + int frame; + n = 0; + while (n < 8 && (live_regs_mask & (1 << n)) == 0) + n++; + frame = offsets->outgoing_args - (offsets->saved_args + saved_regs); + if (frame && n * 4 >= frame) + { + n = frame / 4; + live_regs_mask |= (1 << n) - 1; + saved_regs += frame; + } + } + insn = emit_multi_reg_push (live_regs_mask); RTX_FRAME_RELATED_P (insn) = 1; } @@ -12498,7 +12585,6 @@ arm_expand_prologue (void) } } - offsets = arm_get_frame_offsets (); if (offsets->outgoing_args != offsets->saved_args + saved_regs) { /* This add can produce multiple insns for a large constant, so we @@ -16494,6 +16580,7 @@ is_called_in_ARM_mode (tree func) const char * thumb_unexpanded_epilogue (void) { + arm_stack_offsets *offsets; int regno; unsigned long live_regs_mask = 0; int high_regs_pushed = 0; @@ -16506,7 +16593,8 @@ thumb_unexpanded_epilogue (void) if (IS_NAKED (arm_current_func_type ())) return ""; - live_regs_mask = thumb1_compute_save_reg_mask (); + offsets = arm_get_frame_offsets (); + live_regs_mask = offsets->saved_regs_mask; high_regs_pushed = bit_count (live_regs_mask & 0x0f00); /* If we can deduce the registers used from the function's return value. @@ -16768,7 +16856,8 @@ thumb1_expand_prologue (void) return; } - live_regs_mask = thumb1_compute_save_reg_mask (); + offsets = arm_get_frame_offsets (); + live_regs_mask = offsets->saved_regs_mask; /* Load the pic register before setting the frame pointer, so we can use r7 as a temporary work register. */ if (flag_pic && arm_pic_register != INVALID_REGNUM) @@ -16778,7 +16867,6 @@ thumb1_expand_prologue (void) emit_move_insn (gen_rtx_REG (Pmode, ARM_HARD_FRAME_POINTER_REGNUM), stack_pointer_rtx); - offsets = arm_get_frame_offsets (); amount = offsets->outgoing_args - offsets->saved_regs; if (amount) { @@ -16940,6 +17028,7 @@ thumb1_expand_epilogue (void) static void thumb1_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED) { + arm_stack_offsets *offsets; unsigned long live_regs_mask = 0; unsigned long l_mask; unsigned high_regs_pushed = 0; @@ -17024,7 +17113,8 @@ thumb1_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED) } /* Get the registers we are going to push. */ - live_regs_mask = thumb1_compute_save_reg_mask (); + offsets = arm_get_frame_offsets (); + live_regs_mask = offsets->saved_regs_mask; /* Extract a mask of the ones we can give to the Thumb's push instruction. */ l_mask = live_regs_mask & 0x40ff; /* Then count how many other high registers will need to be pushed. */ @@ -18152,7 +18242,8 @@ arm_set_return_address (rtx source, rtx scratch) rtx addr; unsigned long saved_regs; - saved_regs = arm_compute_save_reg_mask (); + offsets = arm_get_frame_offsets (); + saved_regs = offsets->saved_regs_mask; if ((saved_regs & (1 << LR_REGNUM)) == 0) emit_move_insn (gen_rtx_REG (Pmode, LR_REGNUM), source); @@ -18163,7 +18254,6 @@ arm_set_return_address (rtx source, rtx scratch) else { /* LR will be the first saved register. */ - offsets = arm_get_frame_offsets (); delta = offsets->outgoing_args - (offsets->frame + 4); @@ -18196,11 +18286,10 @@ thumb_set_return_address (rtx source, rtx scratch) emit_insn (gen_rtx_USE (VOIDmode, source)); - mask = thumb1_compute_save_reg_mask (); + offsets = arm_get_frame_offsets (); + mask = offsets->saved_regs_mask; if (mask & (1 << LR_REGNUM)) { - offsets = arm_get_frame_offsets (); - limit = 1024; /* Find the saved regs. */ if (frame_pointer_needed) diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index d93476ba77c..3901768d8d6 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -1538,6 +1538,7 @@ typedef struct arm_stack_offsets GTY(()) int soft_frame; /* FRAME_POINTER_REGNUM. */ int locals_base; /* THUMB_HARD_FRAME_POINTER_REGNUM. */ int outgoing_args; /* STACK_POINTER_REGNUM. */ + unsigned int saved_regs_mask; } arm_stack_offsets; -- 2.11.0