aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2000-01-20 01:05:32 +0100
committerJan Hubicka <hubicka@gcc.gnu.org>2000-01-20 00:05:32 +0000
commit0903fcab883e00dd589e7fec4f26dca9b61b4a29 (patch)
tree1ce8978bec4ca26b9c70b20e0ed5b0ec02d3bde3 /gcc
parente774613011781485fcb8cebacd4296792f5572fe (diff)
downloadgcc-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/ChangeLog15
-rw-r--r--gcc/config/i386/i386-protos.h2
-rw-r--r--gcc/config/i386/i386.c231
-rw-r--r--gcc/config/i386/i386.h25
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. */