diff options
author | Jan Hubicka <jh@suse.cz> | 2000-01-20 01:05:32 +0100 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2000-01-20 00:05:32 +0000 |
commit | 0903fcab883e00dd589e7fec4f26dca9b61b4a29 (patch) | |
tree | 1ce8978bec4ca26b9c70b20e0ed5b0ec02d3bde3 /gcc | |
parent | e774613011781485fcb8cebacd4296792f5572fe (diff) | |
download | gcc-0903fcab883e00dd589e7fec4f26dca9b61b4a29.zip gcc-0903fcab883e00dd589e7fec4f26dca9b61b4a29.tar.gz gcc-0903fcab883e00dd589e7fec4f26dca9b61b4a29.tar.bz2 |
i386-protos.h (ix86_compute_frame_size): Remove prototype.
* i386-protos.h (ix86_compute_frame_size): Remove prototype.
(ix86_initial_elimination_offset): Declare.
* i386.c (ix86_nsaved_regs): Break out from ...
(ix86_can_use_return_insn_p): ... here.
(ix86_emit_save_regs): Break out from ...
(ix86_expand_prologue): ... here.
(ix86_emit_epilogue_esp_adjustment, ix86_emit_restore_regs): Break
out from ...
(ix86_expand_epilogue): ... here.
(ix86_compute_frame_size): Make static, add prototype.
(ix86_initial_elimination_offset): Break out from ...
* i386.h (INITIAL_ELIMINATION_OFFSET): ... here.
From-SVN: r31529
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 15 | ||||
-rw-r--r-- | gcc/config/i386/i386-protos.h | 2 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 231 | ||||
-rw-r--r-- | gcc/config/i386/i386.h | 25 |
4 files changed, 173 insertions, 100 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b5604e0..6118c7b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +Thu Jan 20 01:01:23 MET 2000 Jan Hubicka <jh@suse.cz> + + * i386-protos.h (ix86_compute_frame_size): Remove prototype. + (ix86_initial_elimination_offset): Declare. + * i386.c (ix86_nsaved_regs): Break out from ... + (ix86_can_use_return_insn_p): ... here. + (ix86_emit_save_regs): Break out from ... + (ix86_expand_prologue): ... here. + (ix86_emit_epilogue_esp_adjustment, ix86_emit_restore_regs): Break + out from ... + (ix86_expand_epilogue): ... here. + (ix86_compute_frame_size): Make static, add prototype. + (ix86_initial_elimination_offset): Break out from ... + * i386.h (INITIAL_ELIMINATION_OFFSET): ... here. + 2000-01-19 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> * recog.h (OUT_FCN): Delete. diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 0207955..02ef4d0 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -27,7 +27,7 @@ extern int ix86_can_use_return_insn_p PARAMS ((void)); extern void asm_output_function_prefix PARAMS ((FILE *, char *)); extern void load_pic_register PARAMS ((void)); -extern HOST_WIDE_INT ix86_compute_frame_size PARAMS ((HOST_WIDE_INT, int *)); +extern HOST_WIDE_INT ix86_initial_elimination_offset PARAMS((int, int)); extern void ix86_expand_prologue PARAMS ((void)); extern void ix86_expand_epilogue PARAMS ((void)); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 5897608..ccb439f 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -325,6 +325,11 @@ static void ix86_init_machine_status PARAMS ((struct function *)); static void ix86_mark_machine_status PARAMS ((struct function *)); static void ix86_split_to_parts PARAMS ((rtx, rtx *, enum machine_mode)); static int ix86_safe_length_prefix PARAMS ((rtx)); +static HOST_WIDE_INT ix86_compute_frame_size PARAMS((HOST_WIDE_INT, int *)); +static int ix86_nsaved_regs PARAMS((void)); +static void ix86_emit_save_regs PARAMS((void)); +static void ix86_emit_restore_regs PARAMS((void)); +static void ix86_emit_epilogue_esp_adjustment PARAMS((int)); struct ix86_address { @@ -1434,13 +1439,6 @@ symbolic_reference_mentioned_p (op) int ix86_can_use_return_insn_p () { - int regno; - int nregs = 0; - int reglimit = (frame_pointer_needed - ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); - int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table - || current_function_uses_const_pool); - #ifdef NON_SAVING_SETJMP if (NON_SAVING_SETJMP && current_function_calls_setjmp) return 0; @@ -1449,12 +1447,7 @@ ix86_can_use_return_insn_p () if (! reload_completed) return 0; - for (regno = reglimit - 1; regno >= 0; regno--) - if ((regs_ever_live[regno] && ! call_used_regs[regno]) - || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) - nregs++; - - return nregs == 0 || ! frame_pointer_needed; + return ix86_nsaved_regs () == 0 || ! frame_pointer_needed; } static char *pic_label_name; @@ -1547,6 +1540,61 @@ gen_push (arg) arg); } +/* Return number of registers to be saved on the stack. */ + +static int +ix86_nsaved_regs () +{ + int nregs = 0; + 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); + int regno; + + for (regno = limit - 1; regno >= 0; regno--) + if ((regs_ever_live[regno] && ! call_used_regs[regno]) + || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) + { + nregs ++; + } + return nregs; +} + +/* Return the offset between two registers, one to be eliminated, and the other + its replacement, at the start of a routine. */ + +HOST_WIDE_INT +ix86_initial_elimination_offset (from, to) + int from; + int to; +{ + if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM) + return 8; /* Skip saved PC and previous frame pointer */ + else + { + int nregs; + int poffset; + int offset; + int preferred_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT; + HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), + &nregs); + + offset = (tsize + nregs * UNITS_PER_WORD); + + poffset = 4; + if (frame_pointer_needed) + poffset += UNITS_PER_WORD; + + if (from == ARG_POINTER_REGNUM) + offset += poffset; + else + offset -= ((poffset + preferred_alignment - 1) + & -preferred_alignment) - poffset; + return offset; + } +} + /* Compute the size of local storage taking into consideration the desired stack alignment which is to be maintained. Also determine the number of registers saved below the local storage. */ @@ -1608,13 +1656,33 @@ ix86_compute_frame_size (size, nregs_on_stack) return size + padding; } +/* Emit code to save registers in the prologue. */ + +static void +ix86_emit_save_regs () +{ + register int regno; + int limit; + rtx insn; + int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table + || current_function_uses_const_pool); + limit = (frame_pointer_needed + ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); + + for (regno = limit - 1; regno >= 0; regno--) + if ((regs_ever_live[regno] && !call_used_regs[regno]) + || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) + { + insn = emit_insn (gen_push (gen_rtx_REG (SImode, regno))); + RTX_FRAME_RELATED_P (insn) = 1; + } +} + /* Expand the prologue into a bunch of separate insns. */ void ix86_expand_prologue () { - register int regno; - int limit; int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table || current_function_uses_const_pool); HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), (int *)0); @@ -1664,15 +1732,7 @@ ix86_expand_prologue () CALL_INSN_FUNCTION_USAGE (insn)); } - limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); - for (regno = limit - 1; regno >= 0; regno--) - if ((regs_ever_live[regno] && ! call_used_regs[regno]) - || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) - { - insn = emit_insn (gen_push (gen_rtx_REG (SImode, regno))); - RTX_FRAME_RELATED_P (insn) = 1; - } - + ix86_emit_save_regs (); #ifdef SUBTARGET_PROLOGUE SUBTARGET_PROLOGUE; #endif @@ -1687,14 +1747,80 @@ ix86_expand_prologue () emit_insn (gen_blockage ()); } +/* Emit code to pop all registers from stack. */ + +static void +ix86_emit_restore_regs () +{ + int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table + || current_function_uses_const_pool); + int limit = (frame_pointer_needed + ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); + int regno; + + for (regno = 0; regno < limit; regno++) + if ((regs_ever_live[regno] && !call_used_regs[regno]) + || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) + { + emit_insn (gen_popsi1 (gen_rtx_REG (SImode, regno))); + } +} + +/* Emit code to add TSIZE to esp value. Use POP instruction when + profitable. */ + +static void +ix86_emit_epilogue_esp_adjustment (tsize) + int tsize; +{ + /* Intel's docs say that for 4 or 8 bytes of stack frame one should + use `pop' and not `add'. */ + int use_pop = tsize == 4; + rtx edx = 0, ecx; + + /* Use two pops only for the Pentium processors. */ + if (tsize == 8 && !TARGET_386 && !TARGET_486) + { + rtx retval = current_function_return_rtx; + + edx = gen_rtx_REG (SImode, 1); + + /* This case is a bit more complex. Since we cannot pop into + %ecx twice we need a second register. But this is only + available if the return value is not of DImode in which + case the %edx register is not available. */ + use_pop = (retval == NULL + || !reg_overlap_mentioned_p (edx, retval)); + } + + if (use_pop) + { + ecx = gen_rtx_REG (SImode, 2); + + /* We have to prevent the two pops here from being scheduled. + GCC otherwise would try in some situation to put other + instructions in between them which has a bad effect. */ + emit_insn (gen_blockage ()); + emit_insn (gen_popsi1 (ecx)); + if (tsize == 8) + emit_insn (gen_popsi1 (edx)); + } + else + { + /* If there is no frame pointer, we must still release the frame. */ + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (tsize))); + } +} + /* Restore function stack, frame, and registers. */ void ix86_expand_epilogue () { - register int regno; - register int limit; + int regno; int nregs; + int limit; int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table || current_function_uses_const_pool); int sp_valid = !frame_pointer_needed || current_function_sp_is_unchanging; @@ -1710,9 +1836,6 @@ ix86_expand_epilogue () less work than reloading sp and popping the register. Otherwise, restore sp (if necessary) and pop the registers. */ - limit = (frame_pointer_needed - ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); - if (nregs > 1 || sp_valid) { if ( !sp_valid ) @@ -1724,15 +1847,12 @@ ix86_expand_epilogue () emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx, addr_offset)); } - for (regno = 0; regno < limit; regno++) - if ((regs_ever_live[regno] && ! call_used_regs[regno]) - || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) - { - emit_insn (gen_popsi1 (gen_rtx_REG (SImode, regno))); - } + ix86_emit_restore_regs (); } else { + limit = (frame_pointer_needed + ? 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)) @@ -1756,46 +1876,7 @@ ix86_expand_epilogue () } } else if (tsize) - { - /* Intel's docs say that for 4 or 8 bytes of stack frame one should - use `pop' and not `add'. */ - int use_pop = tsize == 4; - rtx edx = 0, ecx; - - /* Use two pops only for the Pentium processors. */ - if (tsize == 8 && !TARGET_386 && !TARGET_486) - { - rtx retval = current_function_return_rtx; - - edx = gen_rtx_REG (SImode, 1); - - /* This case is a bit more complex. Since we cannot pop into - %ecx twice we need a second register. But this is only - available if the return value is not of DImode in which - case the %edx register is not available. */ - use_pop = (retval == NULL - || ! reg_overlap_mentioned_p (edx, retval)); - } - - if (use_pop) - { - ecx = gen_rtx_REG (SImode, 2); - - /* We have to prevent the two pops here from being scheduled. - GCC otherwise would try in some situation to put other - instructions in between them which has a bad effect. */ - emit_insn (gen_blockage ()); - emit_insn (gen_popsi1 (ecx)); - if (tsize == 8) - emit_insn (gen_popsi1 (edx)); - } - else - { - /* If there is no frame pointer, we must still release the frame. */ - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (tsize))); - } - } + ix86_emit_epilogue_esp_adjustment (tsize); #ifdef FUNCTION_BLOCK_PROFILER_EXIT if (profile_block_flag == 2) diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 9e45815..f7d08bb 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1419,30 +1419,7 @@ do { \ its replacement, at the start of a routine. */ #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ -{ \ - if ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM) \ - (OFFSET) = 8; /* Skip saved PC and previous frame pointer */ \ - else \ - { \ - int nregs; \ - int offset; \ - int preferred_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT; \ - HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), \ - &nregs); \ - \ - (OFFSET) = (tsize + nregs * UNITS_PER_WORD); \ - \ - offset = 4; \ - if (frame_pointer_needed) \ - offset += UNITS_PER_WORD; \ - \ - if ((FROM) == ARG_POINTER_REGNUM) \ - (OFFSET) += offset; \ - else \ - (OFFSET) -= ((offset + preferred_alignment - 1) \ - & -preferred_alignment) - offset; \ - } \ -} + (OFFSET) = ix86_initial_elimination_offset (FROM, TO) /* Addressing modes, and classification of registers for them. */ |