saved frame pointer if frame_pointer_needed
<- HARD_FRAME_POINTER
+ [-msave-args]
+
+ [padding0]
+
[saved regs]
[padding1] \
*/
struct ix86_frame
{
+ int nmsave_args;
+ int padding0;
int nregs;
int padding1;
int va_arg_size;
static tree ix86_stack_protect_fail (void);
static rtx ix86_internal_arg_pointer (void);
static void ix86_dwarf_handle_frame_unspec (const char *, rtx, int);
+static void pro_epilogue_adjust_stack (rtx, rtx, rtx, int);
/* This function is only used on Solaris. */
static void i386_solaris_elf_named_section (const char *, unsigned int, tree)
}
else
{
+ if (TARGET_SAVE_ARGS)
+ error ("-msave-args makes no sense in the 32-bit mode");
/* i386 ABI does not specify red zone. It still makes sense to use it
when programmer takes care to stack from being destroyed. */
if (!(target_flags_explicit & MASK_NO_RED_ZONE))
return 0;
ix86_compute_frame_layout (&frame);
- return frame.to_allocate == 0 && frame.nregs == 0;
+ return frame.to_allocate == 0 && frame.nmsave_args == 0 && frame.nregs == 0;
}
\f
/* Value should be nonzero if functions must have frame pointers.
if (SUBTARGET_FRAME_POINTER_REQUIRED)
return 1;
+ if (TARGET_SAVE_ARGS)
+ return 1;
+
/* In override_options, TARGET_OMIT_LEAF_FRAME_POINTER turns off
the frame pointer by default. Turn it back on now if we've not
got a leaf function. */
return nregs;
}
+/* Return number of arguments to be saved on the stack with
+ -msave-args. */
+
+static int
+ix86_nsaved_args (void)
+{
+ if (TARGET_SAVE_ARGS)
+ return current_function_args_info.regno - current_function_returns_struct;
+ else
+ return 0;
+}
+
/* Return the offset between two registers, one to be eliminated, and the other
its replacement, at the start of a routine. */
frame->local_size = size;
frame->nregs = ix86_nsaved_regs ();
+ frame->nmsave_args = ix86_nsaved_args ();
total_size = size;
stack_alignment_needed = cfun->stack_alignment_needed / BITS_PER_UNIT;
else
frame->save_regs_using_mov = false;
+ if (TARGET_SAVE_ARGS)
+ {
+ cfun->machine->use_fast_prologue_epilogue = true;
+ frame->save_regs_using_mov = true;
+ }
/* Skip return address and saved base pointer. */
offset = frame_pointer_needed ? UNITS_PER_WORD * 2 : UNITS_PER_WORD;
if (stack_alignment_needed < STACK_BOUNDARY / BITS_PER_UNIT)
stack_alignment_needed = STACK_BOUNDARY / BITS_PER_UNIT;
+ /* Argument save area */
+ if (TARGET_SAVE_ARGS)
+ {
+ offset += frame->nmsave_args * UNITS_PER_WORD;
+ frame->padding0 = (frame->nmsave_args % 2) * UNITS_PER_WORD;
+ offset += frame->padding0;
+ }
+ else
+ frame->padding0 = 0;
+
/* Register save area */
offset += frame->nregs * UNITS_PER_WORD;
(size + frame->padding1 + frame->padding2
+ frame->outgoing_arguments_size + frame->va_arg_size);
- if ((!frame->to_allocate && frame->nregs <= 1)
- || (TARGET_64BIT && frame->to_allocate >= (HOST_WIDE_INT) 0x80000000))
+ if (!TARGET_SAVE_ARGS
+ && ((!frame->to_allocate && frame->nregs <= 1)
+ || (TARGET_64BIT
+ && frame->to_allocate >= (HOST_WIDE_INT) 0x80000000)))
frame->save_regs_using_mov = false;
if (TARGET_RED_ZONE && current_function_sp_is_unchanging
{
frame->red_zone_size = frame->to_allocate;
if (frame->save_regs_using_mov)
- frame->red_zone_size += frame->nregs * UNITS_PER_WORD;
+ {
+ frame->red_zone_size
+ += (frame->nregs + frame->nmsave_args) * UNITS_PER_WORD;
+ frame->red_zone_size += frame->padding0;
+ }
if (frame->red_zone_size > RED_ZONE_SIZE - RED_ZONE_RESERVE)
frame->red_zone_size = RED_ZONE_SIZE - RED_ZONE_RESERVE;
}
frame->to_allocate -= frame->red_zone_size;
frame->stack_pointer_offset -= frame->red_zone_size;
#if 0
+ fprintf (stderr, "nmsave_args: %i\n", frame->nmsave_args);
+ fprintf (stderr, "padding0: %i\n", frame->padding0);
fprintf (stderr, "nregs: %i\n", frame->nregs);
fprintf (stderr, "size: %i\n", size);
fprintf (stderr, "alignment1: %i\n", stack_alignment_needed);
unsigned int regno;
rtx insn;
+ if (TARGET_SAVE_ARGS)
+ {
+ int i;
+ int nsaved = ix86_nsaved_args ();
+ int start = cfun->returns_struct;
+ for (i = start; i < start + nsaved; i++)
+ {
+ regno = x86_64_int_parameter_registers[i];
+ insn = emit_insn (gen_push (gen_rtx_REG (Pmode, regno)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ if (nsaved % 2 != 0)
+ pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (-UNITS_PER_WORD), -1);
+ }
+
for (regno = FIRST_PSEUDO_REGISTER; regno-- > 0; )
if (ix86_save_reg (regno, true))
{
RTX_FRAME_RELATED_P (insn) = 1;
offset += UNITS_PER_WORD;
}
+
+ if (TARGET_SAVE_ARGS)
+ {
+ int i;
+ int nsaved = ix86_nsaved_args ();
+ int start = cfun->returns_struct;
+ if (nsaved % 2 != 0)
+ offset += UNITS_PER_WORD;
+ for (i = start + nsaved - 1; i >= start; i--)
+ {
+ regno = x86_64_int_parameter_registers[i];
+ insn = emit_move_insn (adjust_address (gen_rtx_MEM (Pmode, pointer),
+ Pmode, offset),
+ gen_rtx_REG (Pmode, regno));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ offset += UNITS_PER_WORD;
+ }
+ }
+
}
/* Expand prologue or epilogue stack adjustment.
if (!frame.save_regs_using_mov)
ix86_emit_save_regs ();
else
- allocate += frame.nregs * UNITS_PER_WORD;
+ allocate += (frame.nregs + frame.nmsave_args) * UNITS_PER_WORD
+ + frame.padding0;
/* When using red zone we may start register saving before allocating
the stack frame saving one cycle of the prologue. */
if (TARGET_RED_ZONE && frame.save_regs_using_mov)
ix86_emit_save_regs_using_mov (frame_pointer_needed ? hard_frame_pointer_rtx
: stack_pointer_rtx,
- -frame.nregs * UNITS_PER_WORD);
+ -(frame.nregs + frame.nmsave_args)
+ * UNITS_PER_WORD - frame.padding0);
if (allocate == 0)
;
t = plus_constant (hard_frame_pointer_rtx,
allocate
- frame.to_allocate
- - frame.nregs * UNITS_PER_WORD);
+ - (frame.nregs + frame.nmsave_args)
+ * UNITS_PER_WORD - frame.padding0);
else
t = plus_constant (stack_pointer_rtx, allocate);
emit_move_insn (eax, gen_rtx_MEM (SImode, t));
if (frame.save_regs_using_mov && !TARGET_RED_ZONE)
{
- if (!frame_pointer_needed || !frame.to_allocate)
+ if (!TARGET_SAVE_ARGS &&
+ (!frame_pointer_needed || !frame.to_allocate))
ix86_emit_save_regs_using_mov (stack_pointer_rtx, frame.to_allocate);
else
ix86_emit_save_regs_using_mov (hard_frame_pointer_rtx,
- -frame.nregs * UNITS_PER_WORD);
+ -(frame.nregs + frame.nmsave_args)
+ * UNITS_PER_WORD - frame.padding0);
}
pic_reg_used = false;
must be taken for the normal return case of a function using
eh_return: the eax and edx registers are marked as saved, but not
restored along this path. */
- offset = frame.nregs;
+ offset = frame.nregs + frame.nmsave_args;
if (current_function_calls_eh_return && style != 2)
offset -= 2;
offset *= -UNITS_PER_WORD;
+ offset -= frame.padding0;
/* If we're only restoring one register and sp is not valid then
using a move instruction to restore the register since it's
{
tmp = gen_rtx_PLUS (Pmode, stack_pointer_rtx, sa);
tmp = plus_constant (tmp, (frame.to_allocate
- + frame.nregs * UNITS_PER_WORD));
+ + (frame.nregs + frame.nmsave_args)
+ * UNITS_PER_WORD + frame.padding0));
emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx, tmp));
}
}
else if (!frame_pointer_needed)
pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (frame.to_allocate
- + frame.nregs * UNITS_PER_WORD),
+ + (frame.nregs + frame.nmsave_args)
+ * UNITS_PER_WORD + frame.padding0),
style);
/* If not an i386, mov & pop is faster than "leave". */
else if (TARGET_USE_LEAVE || optimize_size
else
emit_insn (gen_popsi1 (gen_rtx_REG (Pmode, regno)));
}
+ if (frame.nmsave_args)
+ pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (frame.nmsave_args * UNITS_PER_WORD
+ + frame.padding0), style);
if (frame_pointer_needed)
{
/* Leave results in shorter dependency chains on CPUs that are