aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2001-02-24 03:34:05 +0100
committerJan Hubicka <hubicka@gcc.gnu.org>2001-02-24 02:34:05 +0000
commit4dd2ac2c3546edfcfb2bcba303378dd59c51e70a (patch)
tree87ca093f4e992a9915e4888a24355f9d55928c71
parenta686dbf86a80b697e84a8ea9a8fa94b281796557 (diff)
downloadgcc-4dd2ac2c3546edfcfb2bcba303378dd59c51e70a.zip
gcc-4dd2ac2c3546edfcfb2bcba303378dd59c51e70a.tar.gz
gcc-4dd2ac2c3546edfcfb2bcba303378dd59c51e70a.tar.bz2
i386.c (ix86_frame): New structure.
* i386.c (ix86_frame): New structure. (ix86_compute_frame_size): Kill. (ix86_compute_frame_layout): New. (ix86_save_reg): New. (ix86_can_use_return_insn_p): Use frame layout stuff. (ix86_expand_prologue): Likewise. (ix86_expand_epilogue): Likewise. (ix86_initial_elimination_offset): Likewise. (ix86_nsaved_regs): Use ix86_save_reg. (ix86_emit_save_regs): Likewise. From-SVN: r40022
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/config/i386/i386.c281
2 files changed, 161 insertions, 133 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d3f1da5..5699d93 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,16 @@
+Sat Feb 24 03:32:50 CET 2001 Jan Hubicka <jh@suse.cz>
+
+ * i386.c (ix86_frame): New structure.
+ (ix86_compute_frame_size): Kill.
+ (ix86_compute_frame_layout): New.
+ (ix86_save_reg): New.
+ (ix86_can_use_return_insn_p): Use frame layout stuff.
+ (ix86_expand_prologue): Likewise.
+ (ix86_expand_epilogue): Likewise.
+ (ix86_initial_elimination_offset): Likewise.
+ (ix86_nsaved_regs): Use ix86_save_reg.
+ (ix86_emit_save_regs): Likewise.
+
Sat Feb 24 03:30:38 CET 2001 Jan Hubicka <jh@suse.cz>
* flow.c (find_sub_basic_blocks): New function.
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 7456519..e90cc0d 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -402,6 +402,40 @@ struct machine_function
#define ix86_stack_locals (cfun->machine->stack_locals)
+/* Structure describing stack frame layout.
+ Stack grows downward:
+
+ [arguments]
+ <- ARG_POINTER
+ saved pc
+
+ saved frame pointer if frame_pointer_needed
+ <- HARD_FRAME_POINTER
+ [saved regs]
+
+ [padding1] \
+ )
+ [va_arg registers] (
+ > to_allocate <- FRAME_POINTER
+ [frame] (
+ )
+ [padding2] /
+ */
+struct ix86_frame
+{
+ int nregs;
+ int padding1;
+ HOST_WIDE_INT frame;
+ int padding2;
+ int outgoing_arguments_size;
+
+ HOST_WIDE_INT to_allocate;
+ /* The offsets relative to ARG_POINTER. */
+ HOST_WIDE_INT frame_pointer_offset;
+ HOST_WIDE_INT hard_frame_pointer_offset;
+ HOST_WIDE_INT stack_pointer_offset;
+};
+
/* which cpu are we scheduling for */
enum processor_type ix86_cpu;
@@ -469,8 +503,6 @@ static void ix86_mark_machine_status PARAMS ((struct function *));
static void ix86_free_machine_status PARAMS ((struct function *));
static int 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 *, 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));
@@ -508,6 +540,8 @@ static int ix86_fp_comparison_arithmetics_cost PARAMS ((enum rtx_code code));
static int ix86_fp_comparison_fcomi_cost PARAMS ((enum rtx_code code));
static int ix86_fp_comparison_sahf_cost PARAMS ((enum rtx_code code));
static int ix86_fp_comparison_cost PARAMS ((enum rtx_code code));
+static int ix86_save_reg PARAMS ((int));
+static void ix86_compute_frame_layout PARAMS ((struct ix86_frame *));
/* Sometimes certain combinations of command options do not make
sense on a particular target machine. You can define a macro
@@ -1667,8 +1701,7 @@ symbolic_reference_mentioned_p (op)
int
ix86_can_use_return_insn_p ()
{
- HOST_WIDE_INT tsize;
- int nregs;
+ struct ix86_frame frame;
#ifdef NON_SAVING_SETJMP
if (NON_SAVING_SETJMP && current_function_calls_setjmp)
@@ -1688,8 +1721,8 @@ ix86_can_use_return_insn_p ()
&& current_function_args_size >= 32768)
return 0;
- tsize = ix86_compute_frame_size (get_frame_size (), &nregs, NULL, NULL);
- return tsize == 0 && nregs == 0;
+ ix86_compute_frame_layout (&frame);
+ return frame.to_allocate == 0 && frame.nregs == 0;
}
/* Value should be nonzero if functions must have frame pointers.
@@ -1817,24 +1850,31 @@ gen_push (arg)
arg);
}
+/* Return 1 if we need to save REGNO. */
+static int
+ix86_save_reg (regno)
+ int regno;
+{
+ int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
+ || current_function_uses_const_pool);
+ return ((regs_ever_live[regno] && !call_used_regs[regno]
+ && !fixed_regs[regno]
+ && (regno != HARD_FRAME_POINTER_REGNUM || !frame_pointer_needed))
+ || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used));
+
+}
+
/* 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 ++;
- }
+ for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
+ if (ix86_save_reg (regno))
+ nregs++;
return nregs;
}
@@ -1846,82 +1886,46 @@ ix86_initial_elimination_offset (from, to)
int from;
int to;
{
- int padding1;
- int nregs;
-
- /* Stack grows downward:
-
- [arguments]
- <- ARG_POINTER
- saved pc
-
- saved frame pointer if frame_pointer_needed
- <- HARD_FRAME_POINTER
- [saved regs]
-
- [padding1] \
- | <- FRAME_POINTER
- [frame] > tsize
- |
- [padding2] /
- */
+ struct ix86_frame frame;
+ ix86_compute_frame_layout (&frame);
if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
- /* Skip saved PC and previous frame pointer.
- Executed only when frame_pointer_needed. */
- return 8;
+ return frame.hard_frame_pointer_offset;
else if (from == FRAME_POINTER_REGNUM
&& to == HARD_FRAME_POINTER_REGNUM)
- {
- ix86_compute_frame_size (get_frame_size (), &nregs, &padding1, (int *) 0);
- padding1 += nregs * UNITS_PER_WORD;
- return -padding1;
- }
+ return frame.hard_frame_pointer_offset - frame.frame_pointer_offset;
else
{
- /* ARG_POINTER or FRAME_POINTER to STACK_POINTER elimination. */
- int frame_size = frame_pointer_needed ? 8 : 4;
- HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (),
- &nregs, &padding1, (int *) 0);
-
if (to != STACK_POINTER_REGNUM)
abort ();
else if (from == ARG_POINTER_REGNUM)
- return tsize + nregs * UNITS_PER_WORD + frame_size;
+ return frame.stack_pointer_offset;
else if (from != FRAME_POINTER_REGNUM)
abort ();
else
- return tsize - padding1;
+ return frame.stack_pointer_offset - frame.frame_pointer_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.
+/* Fill structure ix86_frame about frame of currently computed function. */
- PADDING1 returns padding before stack frame and PADDING2 returns
- padding after stack frame;
- */
-
-static HOST_WIDE_INT
-ix86_compute_frame_size (size, nregs_on_stack, rpadding1, rpadding2)
- HOST_WIDE_INT size;
- int *nregs_on_stack;
- int *rpadding1;
- int *rpadding2;
+static void
+ix86_compute_frame_layout (frame)
+ struct ix86_frame *frame;
{
- int nregs;
- int padding1 = 0;
- int padding2 = 0;
HOST_WIDE_INT total_size;
int stack_alignment_needed = cfun->stack_alignment_needed / BITS_PER_UNIT;
int offset;
int preferred_alignment = cfun->preferred_stack_boundary / BITS_PER_UNIT;
+ HOST_WIDE_INT size = get_frame_size ();
- nregs = ix86_nsaved_regs ();
+ frame->nregs = ix86_nsaved_regs ();
total_size = size;
- offset = frame_pointer_needed ? 8 : 4;
+ /* Skip return value and save base pointer. */
+ offset = frame_pointer_needed ? UNITS_PER_WORD * 2 : UNITS_PER_WORD;
+
+ frame->hard_frame_pointer_offset = offset;
/* Do some sanity checking of stack_alignment_needed and
preferred_alignment, since i386 port is the only using those features
@@ -1936,36 +1940,58 @@ ix86_compute_frame_size (size, nregs_on_stack, rpadding1, rpadding2)
if (stack_alignment_needed > PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)
abort ();
- if (stack_alignment_needed < 4)
- stack_alignment_needed = 4;
+ if (stack_alignment_needed < STACK_BOUNDARY / BITS_PER_UNIT)
+ stack_alignment_needed = STACK_BOUNDARY / BITS_PER_UNIT;
- offset += nregs * UNITS_PER_WORD;
+ /* Register save area */
+ offset += frame->nregs * UNITS_PER_WORD;
- if (ACCUMULATE_OUTGOING_ARGS)
- total_size += current_function_outgoing_args_size;
+ /* Align start of frame for local function. */
+ frame->padding1 = ((offset + stack_alignment_needed - 1)
+ & -stack_alignment_needed) - offset;
- total_size += offset;
+ offset += frame->padding1;
- /* Align start of frame for local function. */
- padding1 = ((offset + stack_alignment_needed - 1)
- & -stack_alignment_needed) - offset;
- total_size += padding1;
+ /* Frame pointer points here. */
+ frame->frame_pointer_offset = offset;
- /* Align stack boundary. */
- padding2 = ((total_size + preferred_alignment - 1)
- & -preferred_alignment) - total_size;
+ offset += size;
+ /* Add outgoing arguments area. */
if (ACCUMULATE_OUTGOING_ARGS)
- padding2 += current_function_outgoing_args_size;
-
- if (nregs_on_stack)
- *nregs_on_stack = nregs;
- if (rpadding1)
- *rpadding1 = padding1;
- if (rpadding2)
- *rpadding2 = padding2;
+ {
+ offset += current_function_outgoing_args_size;
+ frame->outgoing_arguments_size = current_function_outgoing_args_size;
+ }
+ else
+ frame->outgoing_arguments_size = 0;
- return size + padding1 + padding2;
+ /* Align stack boundary. */
+ frame->padding2 = ((offset + preferred_alignment - 1)
+ & -preferred_alignment) - offset;
+
+ offset += frame->padding2;
+
+ /* We've reached end of stack frame. */
+ frame->stack_pointer_offset = offset;
+
+ /* Size prologue needs to allocate. */
+ frame->to_allocate =
+ (size + frame->padding1 + frame->padding2
+ + frame->outgoing_arguments_size);
+
+#if 0
+ fprintf (stderr, "nregs: %i\n", frame->nregs);
+ fprintf (stderr, "size: %i\n", size);
+ fprintf (stderr, "alignment1: %i\n", stack_alignment_needed);
+ fprintf (stderr, "padding1: %i\n", frame->padding1);
+ fprintf (stderr, "padding2: %i\n", frame->padding2);
+ fprintf (stderr, "to_allocate: %i\n", frame->to_allocate);
+ fprintf (stderr, "frame_pointer_offset: %i\n", frame->frame_pointer_offset);
+ fprintf (stderr, "hard_frame_pointer_offset: %i\n",
+ frame->hard_frame_pointer_offset);
+ fprintf (stderr, "stack_pointer_offset: %i\n", frame->stack_pointer_offset);
+#endif
}
/* Emit code to save registers in the prologue. */
@@ -1974,16 +2000,10 @@ 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
- ? HARD_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))
+ for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
+ if (ix86_save_reg (regno))
{
insn = emit_insn (gen_push (gen_rtx_REG (SImode, regno)));
RTX_FRAME_RELATED_P (insn) = 1;
@@ -1995,11 +2015,12 @@ ix86_emit_save_regs ()
void
ix86_expand_prologue ()
{
- HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), (int *) 0,
- (int *) 0, (int *) 0);
rtx insn;
int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
|| current_function_uses_const_pool);
+ struct ix86_frame frame;
+
+ ix86_compute_frame_layout (&frame);
/* Note: AT&T enter does NOT have reversed args. Enter is probably
slower on all targets. Also sdb doesn't like it. */
@@ -2015,17 +2036,17 @@ ix86_expand_prologue ()
ix86_emit_save_regs ();
- if (tsize == 0)
+ if (frame.to_allocate == 0)
;
- else if (! TARGET_STACK_PROBE || tsize < CHECK_STACK_LIMIT)
+ else if (! TARGET_STACK_PROBE || frame.to_allocate < CHECK_STACK_LIMIT)
{
if (frame_pointer_needed)
insn = emit_insn (gen_pro_epilogue_adjust_stack
(stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (-tsize), hard_frame_pointer_rtx));
+ GEN_INT (-frame.to_allocate), hard_frame_pointer_rtx));
else
insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (-tsize)));
+ GEN_INT (-frame.to_allocate)));
RTX_FRAME_RELATED_P (insn) = 1;
}
else
@@ -2035,7 +2056,7 @@ ix86_expand_prologue ()
rtx arg0, sym;
arg0 = gen_rtx_REG (SImode, 0);
- emit_move_insn (arg0, GEN_INT (tsize));
+ emit_move_insn (arg0, GEN_INT (frame.to_allocate));
sym = gen_rtx_MEM (FUNCTION_MODE,
gen_rtx_SYMBOL_REF (Pmode, "_alloca"));
@@ -2087,20 +2108,15 @@ ix86_emit_restore_regs_using_mov (pointer, offset)
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))
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ if (ix86_save_reg (regno))
{
- emit_move_insn (gen_rtx_REG (SImode, regno),
- adj_offsettable_operand (gen_rtx_MEM (SImode,
+ emit_move_insn (gen_rtx_REG (Pmode, regno),
+ adj_offsettable_operand (gen_rtx_MEM (Pmode,
pointer),
offset));
- offset += 4;
+ offset += UNITS_PER_WORD;
}
}
@@ -2110,18 +2126,15 @@ void
ix86_expand_epilogue (emit_return)
int emit_return;
{
- int nregs;
int regno;
-
- 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;
+ struct ix86_frame frame;
HOST_WIDE_INT offset;
- HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), &nregs,
- (int *) 0, (int *) 0);
+
+ ix86_compute_frame_layout (&frame);
/* Calculate start of saved registers relative to ebp. */
- offset = -nregs * UNITS_PER_WORD;
+ offset = -frame.nregs * UNITS_PER_WORD;
#ifdef FUNCTION_BLOCK_PROFILER_EXIT
if (profile_block_flag == 2)
@@ -2140,10 +2153,10 @@ ix86_expand_epilogue (emit_return)
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)
+ if ((!sp_valid && frame.nregs <= 1)
+ || (frame_pointer_needed && !frame.nregs && frame.to_allocate)
|| (frame_pointer_needed && TARGET_USE_LEAVE && !optimize_size
- && nregs == 1))
+ && frame.nregs == 1))
{
/* Restore registers. We can use ebp or esp to address the memory
locations. If both are available, default to ebp, since offsets
@@ -2151,13 +2164,14 @@ ix86_expand_epilogue (emit_return)
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);
+ if (!frame_pointer_needed || (sp_valid && !frame.to_allocate))
+ ix86_emit_restore_regs_using_mov (stack_pointer_rtx, frame.to_allocate);
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);
+ ix86_emit_epilogue_esp_adjustment (frame.to_allocate
+ + frame.nregs * UNITS_PER_WORD);
/* If not an i386, mov & pop is faster than "leave". */
else if (TARGET_USE_LEAVE || optimize_size)
emit_insn (gen_leave ());
@@ -2183,13 +2197,14 @@ ix86_expand_epilogue (emit_return)
GEN_INT (offset),
hard_frame_pointer_rtx));
}
- else if (tsize)
- ix86_emit_epilogue_esp_adjustment (tsize);
+ else if (frame.to_allocate)
+ ix86_emit_epilogue_esp_adjustment (frame.to_allocate);
- for (regno = 0; regno < STACK_POINTER_REGNUM; regno++)
- if ((regs_ever_live[regno] && !call_used_regs[regno])
- || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ if (ix86_save_reg (regno))
emit_insn (gen_popsi1 (gen_rtx_REG (SImode, regno)));
+ if (frame_pointer_needed)
+ emit_insn (gen_popsi1 (hard_frame_pointer_rtx));
}
/* Sibcall epilogues don't want a return instruction. */