#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;
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));
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 *));
\f
/* Sometimes certain combinations of command options do not make
sense on a particular target machine. You can define a macro
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)
&& 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.
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;
}
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
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. */
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;
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. */
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
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"));
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;
}
}
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)
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
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 ());
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. */