diff options
author | Jan Hubicka <jh@suse.cz> | 2000-02-12 01:49:11 +0100 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2000-02-12 00:49:11 +0000 |
commit | da2d1d3a8f3121eb1d3ae502b0367291577919ab (patch) | |
tree | 519d4188849c4d4b69b57aec887adde1c91819ff | |
parent | 28ec5077d7f533713104cdfa21817917098c8111 (diff) | |
download | gcc-da2d1d3a8f3121eb1d3ae502b0367291577919ab.zip gcc-da2d1d3a8f3121eb1d3ae502b0367291577919ab.tar.gz gcc-da2d1d3a8f3121eb1d3ae502b0367291577919ab.tar.bz2 |
i386.c (ix86_emit_restore_regs_using_mov): Break out from ...
* i386.c (ix86_emit_restore_regs_using_mov): Break out from ...
(ix86_expand_epilogue): ... here. Use mov instead of add to restore
stack pointer in functions w/o saved registers, output LEAVE more often
on TARGET_USE_LEAVE machines.
From-SVN: r31941
-rw-r--r-- | gcc/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 67 |
2 files changed, 59 insertions, 15 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8799dba..e7698d5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +Sat Feb 12 01:44:26 MET 2000 Jan Hubicka <jh@suse.cz> + + * i386.c (ix86_emit_restore_regs_using_mov): Break out from ... + (ix86_expand_epilogue): ... here. Use mov instead of add to restore + stack pointer in functions w/o saved registers, output LEAVE more often + on TARGET_USE_LEAVE machines. + 2000-02-07 Dmitri Makarov <dim@wrs.com> & Bernd Schmidt <bernds@redhat.com> * config/arm/arm.c (arm_init_cumulative_args); New function: diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 730594a..18128b7 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -401,6 +401,7 @@ static HOST_WIDE_INT ix86_compute_frame_size PARAMS((HOST_WIDE_INT, int *, int *, int *)); static int ix86_nsaved_regs PARAMS((void)); static void ix86_emit_save_regs PARAMS((void)); +static void ix86_emit_restore_regs_using_mov PARAMS ((rtx, int)); static void ix86_emit_epilogue_esp_adjustment PARAMS((int)); static void ix86_sched_reorder_pentium PARAMS((rtx *, rtx *)); static void ix86_sched_reorder_ppro PARAMS((rtx *, rtx *)); @@ -1963,6 +1964,31 @@ ix86_emit_epilogue_esp_adjustment (tsize) } } +/* Emit code to restore saved registers using MOV insns. First register + is restored from POINTER + OFFSET. */ +static void +ix86_emit_restore_regs_using_mov (pointer, offset) + rtx pointer; + int offset; +{ + int regno; + int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table + || current_function_uses_const_pool); + int limit = (frame_pointer_needed + ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); + + for (regno = 0; regno < limit; regno++) + if ((regs_ever_live[regno] && !call_used_regs[regno]) + || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) + { + emit_move_insn (gen_rtx_REG (SImode, regno), + adj_offsettable_operand (gen_rtx_MEM (SImode, + pointer), + offset)); + offset += 4; + } +} + /* Restore function stack, frame, and registers. */ void @@ -1991,23 +2017,34 @@ ix86_expand_epilogue () /* If we're only restoring one register and sp is not valid then using a move instruction to restore the register since it's - less work than reloading sp and popping the register. */ - if (!sp_valid && nregs <= 1) - { - if (!frame_pointer_needed) - abort(); - - for (regno = 0; regno < HARD_FRAME_POINTER_REGNUM; regno++) - if ((regs_ever_live[regno] && ! call_used_regs[regno]) - || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) - { - emit_move_insn (gen_rtx_REG (SImode, regno), - adj_offsettable_operand (AT_BP (Pmode), offset)); - offset += 4; - } + less work than reloading sp and popping the register. + + The default code result in stack adjustment using add/lea instruction, + while this code results in LEAVE instruction (or discrete equivalent), + so it is profitable in some other cases as well. Especially when there + are no registers to restore. We also use this code when TARGET_USE_LEAVE + and there is exactly one register to pop. This heruistic may need some + tuning in future. */ + if ((!sp_valid && nregs <= 1) + || (frame_pointer_needed && !nregs && tsize) + || (frame_pointer_needed && TARGET_USE_LEAVE && !optimize_size + && nregs == 1)) + { + /* Restore registers. We can use ebp or esp to address the memory + locations. If both are available, default to ebp, since offsets + are known to be small. Only exception is esp pointing directly to the + end of block of saved registers, where we may simplify addressing + mode. */ + + if (!frame_pointer_needed || (sp_valid && !tsize)) + ix86_emit_restore_regs_using_mov (stack_pointer_rtx, tsize); + else + ix86_emit_restore_regs_using_mov (hard_frame_pointer_rtx, offset); + if (!frame_pointer_needed) + ix86_emit_epilogue_esp_adjustment (tsize + nregs * UNITS_PER_WORD); /* If not an i386, mov & pop is faster than "leave". */ - if (TARGET_USE_LEAVE || optimize_size) + else if (TARGET_USE_LEAVE || optimize_size) emit_insn (gen_leave ()); else { |