i386.c (ix86_compute_frame_layout): Re-align stack after saving registers.

* config/i386/i386.c (ix86_compute_frame_layout): Re-align stack
	after saving registers.  Assert that SSE registers are only saved
	with a sufficiently aligned frame.
	(ix86_emit_save_reg_using_mov): Assert realigned only with DRAP;
	remove stack_realign_fp handling.
	(ix86_expand_prologue): Save int registers before stack_realign_fp,
	and do not mark the stack alignment as frame related.
	(ix86_expand_epilogue): SP is now invalid with stack_realign_fp.

	* dwarf2out.c (dwarf2out_frame_debug_expr): Flush queued register
	saves when re-aligning the stack.

From-SVN: r163068
This commit is contained in:
Richard Henderson 2010-08-10 07:50:34 -07:00 committed by Richard Henderson
parent 67536dcb63
commit 35b15a461e
3 changed files with 84 additions and 71 deletions

View File

@ -1,3 +1,17 @@
2010-08-10 Richard Henderson <rth@redhat.com>
* config/i386/i386.c (ix86_compute_frame_layout): Re-align stack
after saving registers. Assert that SSE registers are only saved
with a sufficiently aligned frame.
(ix86_emit_save_reg_using_mov): Assert realigned only with DRAP;
remove stack_realign_fp handling.
(ix86_expand_prologue): Save int registers before stack_realign_fp,
and do not mark the stack alignment as frame related.
(ix86_expand_epilogue): SP is now invalid with stack_realign_fp.
* dwarf2out.c (dwarf2out_frame_debug_expr): Flush queued register
saves when re-aligning the stack.
2010-08-10 Nathan Froyd <froydnj@codesourcery.com>
* basic-block.h (alloc_aux_for_block, alloc_aux_for_edge): Delete.

View File

@ -8404,10 +8404,6 @@ ix86_compute_frame_layout (struct ix86_frame *frame)
frame->hard_frame_pointer_offset = offset;
/* Set offset to aligned because the realigned frame starts from here. */
if (stack_realign_fp)
offset = (offset + stack_alignment_needed -1) & -stack_alignment_needed;
/* Register save area */
offset += frame->nregs * UNITS_PER_WORD;
frame->reg_save_offset = offset;
@ -8415,11 +8411,22 @@ ix86_compute_frame_layout (struct ix86_frame *frame)
/* Align and set SSE register save area. */
if (frame->nsseregs)
{
/* The only ABI that has saved SSE registers (Win64) also has a
16-byte aligned default stack, and thus we don't need to be
within the re-aligned local stack frame to save them. */
gcc_assert (INCOMING_STACK_BOUNDARY >= 128);
offset = (offset + 16 - 1) & -16;
offset += frame->nsseregs * 16;
}
frame->sse_reg_save_offset = offset;
/* The re-aligned stack starts here. Values before this point are not
directly comparable with values below this point. In order to make
sure that no value happens to be the same before and after, force
the alignment computation below to add a non-zero value. */
if (stack_realign_fp)
offset = (offset + stack_alignment_needed) & -stack_alignment_needed;
/* Va-arg area */
frame->va_arg_size = ix86_varargs_gpr_size + ix86_varargs_fpr_size;
offset += frame->va_arg_size;
@ -8621,7 +8628,9 @@ ix86_emit_save_reg_using_mov (enum machine_mode mode, unsigned int regno,
any tricky guessing by dwarf2out. */
if (m->fs.realigned)
{
if (stack_realign_drap && regno == REGNO (crtl->drap_reg))
gcc_checking_assert (stack_realign_drap);
if (regno == REGNO (crtl->drap_reg))
{
/* A bit of a hack. We force the DRAP register to be saved in
the re-aligned stack frame, which provides us with a copy
@ -8632,21 +8641,6 @@ ix86_emit_save_reg_using_mov (enum machine_mode mode, unsigned int regno,
mem = gen_rtx_MEM (mode, addr);
add_reg_note (insn, REG_CFA_DEF_CFA, mem);
}
else if (stack_realign_fp)
{
/* The stack pointer may or may not be varying within the
function. If it is, then we can't use it as a stable
reference to the locations within the frame. Instead,
simply compute the location of the aligned frame from
the frame pointer. */
addr = GEN_INT (-(HOST_WIDE_INT)crtl->stack_alignment_needed
/ BITS_PER_UNIT);
addr = gen_rtx_AND (Pmode, hard_frame_pointer_rtx, addr);
addr = plus_constant (addr, -cfa_offset);
mem = gen_rtx_MEM (mode, addr);
add_reg_note (insn, REG_CFA_EXPRESSION,
gen_rtx_SET (VOIDmode, mem, reg));
}
else
{
/* The frame pointer is a stable reference within the
@ -9391,7 +9385,7 @@ ix86_expand_prologue (void)
bool pic_reg_used;
struct ix86_frame frame;
HOST_WIDE_INT allocate;
bool int_registers_saved = false;
bool int_registers_saved;
ix86_finalize_stack_realign_flags ();
@ -9560,33 +9554,59 @@ ix86_expand_prologue (void)
m->fs.fp_valid = true;
}
int_registers_saved = (frame.nregs == 0);
if (!int_registers_saved)
{
/* If saving registers via PUSH, do so now. */
if (!frame.save_regs_using_mov)
{
ix86_emit_save_regs ();
int_registers_saved = true;
gcc_assert (m->fs.sp_offset == frame.reg_save_offset);
}
/* When using red zone we may start register saving before allocating
the stack frame saving one cycle of the prologue. However, avoid
doing this if we have to probe the stack; at least on x86_64 the
stack probe can turn into a call that clobbers a red zone location. */
else if (ix86_using_red_zone ()
&& (! TARGET_STACK_PROBE
|| frame.stack_pointer_offset < CHECK_STACK_LIMIT))
{
ix86_emit_save_regs_using_mov (frame.reg_save_offset);
int_registers_saved = true;
}
}
if (stack_realign_fp)
{
int align_bytes = crtl->stack_alignment_needed / BITS_PER_UNIT;
gcc_assert (align_bytes > MIN_STACK_BOUNDARY / BITS_PER_UNIT);
/* The computation of the size of the re-aligned stack frame means
that we must allocate the size of the register save area before
performing the actual alignment. Otherwise we cannot guarantee
that there's enough storage above the realignment point. */
if (m->fs.sp_offset != frame.sse_reg_save_offset)
pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (m->fs.sp_offset
- frame.sse_reg_save_offset),
-1, false);
/* Align the stack. */
insn = emit_insn (ix86_gen_andsp (stack_pointer_rtx,
stack_pointer_rtx,
GEN_INT (-align_bytes)));
RTX_FRAME_RELATED_P (insn) = 1;
/* For the purposes of register save area addressing, the frame
pointer is no longer valid. */
/* ??? There's no need to place the register save area into the
aligned local stack frame. We should do this later, after
the register saves. */
m->fs.sp_offset = (m->fs.sp_offset + align_bytes - 1) & -align_bytes;
m->fs.fp_valid = false;
m->fs.realigned = true;
/* For the purposes of register save area addressing, the stack
pointer is no longer valid. As for the value of sp_offset,
see ix86_compute_frame_layout, which we need to match in order
to pass verification of stack_pointer_offset at the end. */
m->fs.sp_offset = (m->fs.sp_offset + align_bytes) & -align_bytes;
m->fs.sp_valid = false;
}
if (!frame.save_regs_using_mov)
{
ix86_emit_save_regs ();
int_registers_saved = true;
gcc_assert (m->fs.sp_offset == frame.reg_save_offset);
}
allocate = frame.stack_pointer_offset - m->fs.sp_offset;
/* The stack has already been decremented by the instruction calling us
@ -9615,21 +9635,10 @@ ix86_expand_prologue (void)
}
}
/* When using red zone we may start register saving before allocating the
stack frame saving one cycle of the prologue. However, avoid doing this
if we have to probe the stack; at least on x86_64 the stack probe can
turn into a call that clobbers a red zone location. */
if (!int_registers_saved
&& ix86_using_red_zone ()
&& (! TARGET_STACK_PROBE || allocate < CHECK_STACK_LIMIT))
{
ix86_emit_save_regs_using_mov (frame.reg_save_offset);
int_registers_saved = true;
}
if (allocate == 0)
;
else if (!ix86_target_stack_probe () || allocate < CHECK_STACK_LIMIT)
else if (!ix86_target_stack_probe ()
|| frame.stack_pointer_offset < CHECK_STACK_LIMIT)
{
pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (-allocate), -1,
@ -9918,19 +9927,14 @@ ix86_expand_epilogue (int style)
ix86_finalize_stack_realign_flags ();
ix86_compute_frame_layout (&frame);
/* When stack is realigned, SP must be valid. */
m->fs.sp_valid = (!frame_pointer_needed
|| current_function_sp_is_unchanging
|| stack_realign_fp);
|| (current_function_sp_is_unchanging
&& !stack_realign_fp));
gcc_assert (!m->fs.sp_valid
|| m->fs.sp_offset == frame.stack_pointer_offset);
/* The FP must be valid if the frame pointer is present, but not
if the register save area is in the re-aligned local frame and
the FP points to the unaligned argument frame. */
gcc_assert (frame_pointer_needed
? stack_realign_fp != m->fs.fp_valid
: !m->fs.fp_valid);
/* The FP must be valid if the frame pointer is present. */
gcc_assert (frame_pointer_needed == m->fs.fp_valid);
gcc_assert (!m->fs.fp_valid
|| m->fs.fp_offset == frame.hard_frame_pointer_offset);
@ -9955,10 +9959,10 @@ ix86_expand_epilogue (int style)
/* The red-zone begins below the return address. */
m->fs.red_zone_offset = RED_ZONE_SIZE + UNITS_PER_WORD;
/* Since the register save area is in the aligned portion of
/* When the register save area is in the aligned portion of
the stack, determine the maximum runtime displacement that
matches up with the aligned frame. */
if (crtl->stack_realign_needed)
if (stack_realign_drap)
m->fs.red_zone_offset -= (crtl->stack_alignment_needed / BITS_PER_UNIT
+ UNITS_PER_WORD);
}
@ -10030,7 +10034,7 @@ ix86_expand_epilogue (int style)
rtx insn, sa = EH_RETURN_STACKADJ_RTX;
/* Stack align doesn't work with eh_return. */
gcc_assert (!crtl->stack_realign_needed);
gcc_assert (!stack_realign_drap);
/* Neither does regparm nested functions. */
gcc_assert (!ix86_static_chain_on_stack);
@ -10109,17 +10113,8 @@ ix86_expand_epilogue (int style)
/* If we used a stack pointer and haven't already got rid of it,
then do so now. */
if (m->fs.fp_valid || stack_realign_fp)
if (m->fs.fp_valid)
{
if (stack_realign_fp)
{
/* We're re-defining what it means to be the local stack
frame. Thus the FP is suddenly valid and the SP isn't. */
m->fs.fp_valid = true;
m->fs.sp_valid = false;
m->fs.realigned = false;
}
/* If the stack pointer is valid and pointing at the frame
pointer store address, then we only need a pop. */
if (m->fs.sp_valid && m->fs.sp_offset == frame.hard_frame_pointer_offset)

View File

@ -2456,6 +2456,10 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
alignment. */
if (fde && XEXP (src, 0) == stack_pointer_rtx)
{
/* We interpret reg_save differently with stack_realign set.
Thus we must flush whatever we have queued first. */
flush_queued_reg_saves ();
gcc_assert (cfa_store.reg == REGNO (XEXP (src, 0)));
fde->stack_realign = 1;
fde->stack_realignment = INTVAL (XEXP (src, 1));