Commit 4dd2ac2c by Jan Hubicka Committed by Jan Hubicka

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
parent a686dbf8
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.
......
......@@ -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. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment