Commit c9f4c451 by Richard Henderson Committed by Richard Henderson

Describe unwinding for realigned frames explicitly.

We had been relying on some extremely fragile code within
dwarf2out in order to guess what to do with aligned stack
frames, which broke when we decided to perform the stores
to the aligned stack frame via EBP instead of ESP.

Instead, emit the appropriate unwinding instructions from
the backend.  This requires adding a new reg-note in order
to describe a register save at an arbitrary address.

From-SVN: r162889
parent ec7ded37
2010-08-04 Richard Henderson <rth@redhat.com> 2010-08-04 Richard Henderson <rth@redhat.com>
* reg-notes.def (CFA_EXPRESSION): New.
* dwarf2out.c (dwarf2out_frame_debug): Handle it.
(dwarf2out_frame_debug_cfa_expression): New.
(dwarf2out_frame_debug_def_cfa): Handle simple MEMs.
* config/i386/i386.h (struct machine_frame_state): Add realigned flag.
* config/i386/i386.c (ix86_expand_prologue): Set it.
(ix86_expand_epilogue): Clear it.
(ix86_emit_save_reg_using_mov): For registers saved in a realigned
context, add REG_CFA_EXPRESSION notes.
* config/i386/i386.h (struct machine_frame_state): Rename from * config/i386/i386.h (struct machine_frame_state): Rename from
machine_cfa_state. Add members tracking SP and FP regardless machine_cfa_state. Add members tracking SP and FP regardless
of the current CFA register. of the current CFA register.
......
...@@ -8616,8 +8616,9 @@ static void ...@@ -8616,8 +8616,9 @@ static void
ix86_emit_save_reg_using_mov (enum machine_mode mode, unsigned int regno, ix86_emit_save_reg_using_mov (enum machine_mode mode, unsigned int regno,
HOST_WIDE_INT cfa_offset) HOST_WIDE_INT cfa_offset)
{ {
struct machine_function *m = cfun->machine;
rtx reg = gen_rtx_REG (mode, regno); rtx reg = gen_rtx_REG (mode, regno);
rtx mem, addr, insn; rtx mem, addr, base, insn;
addr = choose_baseaddr (cfa_offset); addr = choose_baseaddr (cfa_offset);
mem = gen_frame_mem (mode, addr); mem = gen_frame_mem (mode, addr);
...@@ -8626,20 +8627,64 @@ ix86_emit_save_reg_using_mov (enum machine_mode mode, unsigned int regno, ...@@ -8626,20 +8627,64 @@ ix86_emit_save_reg_using_mov (enum machine_mode mode, unsigned int regno,
set_mem_align (mem, GET_MODE_ALIGNMENT (mode)); set_mem_align (mem, GET_MODE_ALIGNMENT (mode));
insn = emit_move_insn (mem, reg); insn = emit_move_insn (mem, reg);
RTX_FRAME_RELATED_P (insn) = 1;
base = addr;
if (GET_CODE (base) == PLUS)
base = XEXP (base, 0);
gcc_checking_assert (REG_P (base));
/* When saving registers into a re-aligned local stack frame, avoid
any tricky guessing by dwarf2out. */
if (m->fs.realigned)
{
if (stack_realign_drap && 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
of the CFA that will last past the prologue. Install it. */
gcc_checking_assert (cfun->machine->fs.fp_valid);
addr = plus_constant (hard_frame_pointer_rtx,
cfun->machine->fs.fp_offset - cfa_offset);
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 (-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
aligned frame. Use it. */
gcc_checking_assert (cfun->machine->fs.fp_valid);
addr = plus_constant (hard_frame_pointer_rtx,
cfun->machine->fs.fp_offset - cfa_offset);
mem = gen_rtx_MEM (mode, addr);
add_reg_note (insn, REG_CFA_EXPRESSION,
gen_rtx_SET (VOIDmode, mem, reg));
}
}
/* The memory may not be relative to the current CFA register, /* The memory may not be relative to the current CFA register,
which means that we may need to generate a new pattern for which means that we may need to generate a new pattern for
use by the unwind info. */ use by the unwind info. */
if (GET_CODE (addr) == PLUS) else if (base != m->fs.cfa_reg)
addr = XEXP (addr, 0);
if (addr != cfun->machine->fs.cfa_reg)
{ {
addr = plus_constant (cfun->machine->fs.cfa_reg, addr = plus_constant (m->fs.cfa_reg, m->fs.cfa_offset - cfa_offset);
cfun->machine->fs.cfa_offset - cfa_offset);
mem = gen_rtx_MEM (mode, addr); mem = gen_rtx_MEM (mode, addr);
add_reg_note (insn, REG_CFA_OFFSET, gen_rtx_SET (VOIDmode, mem, reg)); add_reg_note (insn, REG_CFA_OFFSET, gen_rtx_SET (VOIDmode, mem, reg));
} }
RTX_FRAME_RELATED_P (insn) = 1;
} }
/* Emit code to save registers using MOV insns. /* Emit code to save registers using MOV insns.
...@@ -9511,6 +9556,7 @@ ix86_expand_prologue (void) ...@@ -9511,6 +9556,7 @@ ix86_expand_prologue (void)
/* For the purposes of frame and register save area addressing, /* For the purposes of frame and register save area addressing,
we've started over with a new frame. */ we've started over with a new frame. */
m->fs.sp_offset = INCOMING_FRAME_SP_OFFSET; m->fs.sp_offset = INCOMING_FRAME_SP_OFFSET;
m->fs.realigned = true;
} }
if (frame_pointer_needed && !m->fs.fp_valid) if (frame_pointer_needed && !m->fs.fp_valid)
...@@ -9546,8 +9592,9 @@ ix86_expand_prologue (void) ...@@ -9546,8 +9592,9 @@ ix86_expand_prologue (void)
/* ??? There's no need to place the register save area into the /* ??? There's no need to place the register save area into the
aligned local stack frame. We should do this later, after aligned local stack frame. We should do this later, after
the register saves. */ the register saves. */
m->fs.fp_valid = false;
m->fs.sp_offset = (m->fs.sp_offset + align_bytes - 1) & -align_bytes; m->fs.sp_offset = (m->fs.sp_offset + align_bytes - 1) & -align_bytes;
m->fs.fp_valid = false;
m->fs.realigned = true;
} }
allocate = frame.to_allocate + frame.nsseregs * 16 + frame.padding0; allocate = frame.to_allocate + frame.nsseregs * 16 + frame.padding0;
...@@ -10070,6 +10117,7 @@ ix86_expand_epilogue (int style) ...@@ -10070,6 +10117,7 @@ ix86_expand_epilogue (int style)
frame. Thus the FP is suddenly valid and the SP isn't. */ frame. Thus the FP is suddenly valid and the SP isn't. */
m->fs.fp_valid = true; m->fs.fp_valid = true;
m->fs.sp_valid = false; m->fs.sp_valid = false;
m->fs.realigned = false;
} }
/* Leave results in shorter dependency chains on CPUs that are /* Leave results in shorter dependency chains on CPUs that are
...@@ -10122,6 +10170,7 @@ ix86_expand_epilogue (int style) ...@@ -10122,6 +10170,7 @@ ix86_expand_epilogue (int style)
frame. Thus the FP is suddenly valid and the SP isn't. */ frame. Thus the FP is suddenly valid and the SP isn't. */
m->fs.fp_valid = true; m->fs.fp_valid = true;
m->fs.sp_valid = false; m->fs.sp_valid = false;
m->fs.realigned = false;
} }
/* Leave results in shorter dependency chains on CPUs that are /* Leave results in shorter dependency chains on CPUs that are
...@@ -10162,6 +10211,7 @@ ix86_expand_epilogue (int style) ...@@ -10162,6 +10211,7 @@ ix86_expand_epilogue (int style)
m->fs.cfa_reg = stack_pointer_rtx; m->fs.cfa_reg = stack_pointer_rtx;
m->fs.cfa_offset = param_ptr_offset; m->fs.cfa_offset = param_ptr_offset;
m->fs.sp_offset = param_ptr_offset; m->fs.sp_offset = param_ptr_offset;
m->fs.realigned = false;
add_reg_note (insn, REG_CFA_DEF_CFA, add_reg_note (insn, REG_CFA_DEF_CFA,
gen_rtx_PLUS (Pmode, stack_pointer_rtx, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
...@@ -10196,6 +10246,7 @@ ix86_expand_epilogue (int style) ...@@ -10196,6 +10246,7 @@ ix86_expand_epilogue (int style)
gcc_assert (m->fs.sp_offset == UNITS_PER_WORD); gcc_assert (m->fs.sp_offset == UNITS_PER_WORD);
gcc_assert (m->fs.sp_valid); gcc_assert (m->fs.sp_valid);
gcc_assert (!m->fs.fp_valid); gcc_assert (!m->fs.fp_valid);
gcc_assert (!m->fs.realigned);
/* Sibcall epilogues don't want a return instruction. */ /* Sibcall epilogues don't want a return instruction. */
if (style == 0) if (style == 0)
......
...@@ -2323,6 +2323,11 @@ struct GTY(()) machine_frame_state ...@@ -2323,6 +2323,11 @@ struct GTY(()) machine_frame_state
BOOL_BITFIELD sp_valid : 1; BOOL_BITFIELD sp_valid : 1;
BOOL_BITFIELD fp_valid : 1; BOOL_BITFIELD fp_valid : 1;
BOOL_BITFIELD drap_valid : 1; BOOL_BITFIELD drap_valid : 1;
/* Indicate whether the local stack frame has been re-aligned. When
set, the SP/FP offsets above are relative to the aligned frame
and not the CFA. */
BOOL_BITFIELD realigned : 1;
}; };
struct GTY(()) machine_function { struct GTY(()) machine_function {
......
...@@ -479,6 +479,8 @@ static struct dw_loc_descr_struct *build_cfa_loc ...@@ -479,6 +479,8 @@ static struct dw_loc_descr_struct *build_cfa_loc
static struct dw_loc_descr_struct *build_cfa_aligned_loc static struct dw_loc_descr_struct *build_cfa_aligned_loc
(HOST_WIDE_INT, HOST_WIDE_INT); (HOST_WIDE_INT, HOST_WIDE_INT);
static void def_cfa_1 (const char *, dw_cfa_location *); static void def_cfa_1 (const char *, dw_cfa_location *);
static struct dw_loc_descr_struct *mem_loc_descriptor
(rtx, enum machine_mode mode, enum var_init_status);
/* How to start an assembler comment. */ /* How to start an assembler comment. */
#ifndef ASM_COMMENT_START #ifndef ASM_COMMENT_START
...@@ -1833,6 +1835,17 @@ dwarf2out_frame_debug_def_cfa (rtx pat, const char *label) ...@@ -1833,6 +1835,17 @@ dwarf2out_frame_debug_def_cfa (rtx pat, const char *label)
cfa.reg = REGNO (pat); cfa.reg = REGNO (pat);
break; break;
case MEM:
cfa.indirect = 1;
pat = XEXP (pat, 0);
if (GET_CODE (pat) == PLUS)
{
cfa.base_offset = INTVAL (XEXP (pat, 1));
pat = XEXP (pat, 0);
}
cfa.reg = REGNO (pat);
break;
default: default:
/* Recurse and define an expression. */ /* Recurse and define an expression. */
gcc_unreachable (); gcc_unreachable ();
...@@ -1951,6 +1964,34 @@ dwarf2out_frame_debug_cfa_register (rtx set, const char *label) ...@@ -1951,6 +1964,34 @@ dwarf2out_frame_debug_cfa_register (rtx set, const char *label)
reg_save (label, sregno, dregno, 0); reg_save (label, sregno, dregno, 0);
} }
/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_EXPRESSION note. */
static void
dwarf2out_frame_debug_cfa_expression (rtx set, const char *label)
{
rtx src, dest, span;
dw_cfi_ref cfi = new_cfi ();
dest = SET_DEST (set);
src = SET_SRC (set);
gcc_assert (REG_P (src));
gcc_assert (MEM_P (dest));
span = targetm.dwarf_register_span (src);
gcc_assert (!span);
cfi->dw_cfi_opc = DW_CFA_expression;
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = DWARF_FRAME_REGNUM (REGNO (src));
cfi->dw_cfi_oprnd2.dw_cfi_loc
= mem_loc_descriptor (XEXP (dest, 0), GET_MODE (dest),
VAR_INIT_STATUS_INITIALIZED);
/* ??? We'd like to use queue_reg_save, were the interface different,
and, as above, we could manage flushing for epilogues. */
add_fde_cfi (label, cfi);
}
/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_RESTORE note. */ /* A subroutine of dwarf2out_frame_debug, process a REG_CFA_RESTORE note. */
static void static void
...@@ -2740,6 +2781,14 @@ dwarf2out_frame_debug (rtx insn, bool after_p) ...@@ -2740,6 +2781,14 @@ dwarf2out_frame_debug (rtx insn, bool after_p)
handled_one = true; handled_one = true;
break; break;
case REG_CFA_EXPRESSION:
n = XEXP (note, 0);
if (n == NULL)
n = single_set (insn);
dwarf2out_frame_debug_cfa_expression (n, label);
handled_one = true;
break;
case REG_CFA_RESTORE: case REG_CFA_RESTORE:
n = XEXP (note, 0); n = XEXP (note, 0);
if (n == NULL) if (n == NULL)
...@@ -6181,8 +6230,6 @@ static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT, ...@@ -6181,8 +6230,6 @@ static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT,
enum var_init_status); enum var_init_status);
static int is_based_loc (const_rtx); static int is_based_loc (const_rtx);
static int resolve_one_addr (rtx *, void *); static int resolve_one_addr (rtx *, void *);
static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode,
enum var_init_status);
static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx, static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx,
enum var_init_status); enum var_init_status);
static dw_loc_descr_ref loc_descriptor (rtx, enum machine_mode mode, static dw_loc_descr_ref loc_descriptor (rtx, enum machine_mode mode,
......
...@@ -148,6 +148,12 @@ REG_NOTE (CFA_OFFSET) ...@@ -148,6 +148,12 @@ REG_NOTE (CFA_OFFSET)
or the pattern should be simple reg-reg move. */ or the pattern should be simple reg-reg move. */
REG_NOTE (CFA_REGISTER) REG_NOTE (CFA_REGISTER)
/* Attached to insns that are RTX_FRAME_RELATED_P, but are too complex
for FRAME_RELATED_EXPR intuition. This is a save to memory, i.e. will
result in a DW_CFA_expression. The pattern or the insn should be a
store of a register to an arbitrary (non-validated) memory address. */
REG_NOTE (CFA_EXPRESSION)
/* Attached to insns that are RTX_FRAME_RELATED_P, with the information /* Attached to insns that are RTX_FRAME_RELATED_P, with the information
that this is a restore operation, i.e. will result in DW_CFA_restore that this is a restore operation, i.e. will result in DW_CFA_restore
or the like. Either the attached rtx, or the destination of the insn's or the like. Either the attached rtx, or the destination of the insn's
......
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