aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2010-08-04 16:58:26 -0700
committerRichard Henderson <rth@gcc.gnu.org>2010-08-04 16:58:26 -0700
commitc9f4c45115dfba1d84958c1a971a333763976b7f (patch)
treea39862b72529e6b9992873c95bf737f8aca806dd /gcc
parentec7ded37e7550ed1e9f133b959fe92ff6fdf791d (diff)
downloadgcc-c9f4c45115dfba1d84958c1a971a333763976b7f.zip
gcc-c9f4c45115dfba1d84958c1a971a333763976b7f.tar.gz
gcc-c9f4c45115dfba1d84958c1a971a333763976b7f.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/config/i386/i386.c67
-rw-r--r--gcc/config/i386/i386.h5
-rw-r--r--gcc/dwarf2out.c51
-rw-r--r--gcc/reg-notes.def6
5 files changed, 130 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index cc867ff..9866d8e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,16 @@
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
machine_cfa_state. Add members tracking SP and FP regardless
of the current CFA register.
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 77dbef3..96897be 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -8616,8 +8616,9 @@ static void
ix86_emit_save_reg_using_mov (enum machine_mode mode, unsigned int regno,
HOST_WIDE_INT cfa_offset)
{
+ struct machine_function *m = cfun->machine;
rtx reg = gen_rtx_REG (mode, regno);
- rtx mem, addr, insn;
+ rtx mem, addr, base, insn;
addr = choose_baseaddr (cfa_offset);
mem = gen_frame_mem (mode, addr);
@@ -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));
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,
which means that we may need to generate a new pattern for
use by the unwind info. */
- if (GET_CODE (addr) == PLUS)
- addr = XEXP (addr, 0);
- if (addr != cfun->machine->fs.cfa_reg)
+ else if (base != m->fs.cfa_reg)
{
- addr = plus_constant (cfun->machine->fs.cfa_reg,
- cfun->machine->fs.cfa_offset - cfa_offset);
+ addr = plus_constant (m->fs.cfa_reg, m->fs.cfa_offset - cfa_offset);
mem = gen_rtx_MEM (mode, addr);
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.
@@ -9511,6 +9556,7 @@ ix86_expand_prologue (void)
/* For the purposes of frame and register save area addressing,
we've started over with a new frame. */
m->fs.sp_offset = INCOMING_FRAME_SP_OFFSET;
+ m->fs.realigned = true;
}
if (frame_pointer_needed && !m->fs.fp_valid)
@@ -9546,8 +9592,9 @@ ix86_expand_prologue (void)
/* ??? 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.fp_valid = false;
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;
@@ -10070,6 +10117,7 @@ ix86_expand_epilogue (int style)
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;
}
/* Leave results in shorter dependency chains on CPUs that are
@@ -10122,6 +10170,7 @@ ix86_expand_epilogue (int style)
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;
}
/* Leave results in shorter dependency chains on CPUs that are
@@ -10162,6 +10211,7 @@ ix86_expand_epilogue (int style)
m->fs.cfa_reg = stack_pointer_rtx;
m->fs.cfa_offset = param_ptr_offset;
m->fs.sp_offset = param_ptr_offset;
+ m->fs.realigned = false;
add_reg_note (insn, REG_CFA_DEF_CFA,
gen_rtx_PLUS (Pmode, stack_pointer_rtx,
@@ -10196,6 +10246,7 @@ ix86_expand_epilogue (int style)
gcc_assert (m->fs.sp_offset == UNITS_PER_WORD);
gcc_assert (m->fs.sp_valid);
gcc_assert (!m->fs.fp_valid);
+ gcc_assert (!m->fs.realigned);
/* Sibcall epilogues don't want a return instruction. */
if (style == 0)
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 300f22e..a2acc71 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -2323,6 +2323,11 @@ struct GTY(()) machine_frame_state
BOOL_BITFIELD sp_valid : 1;
BOOL_BITFIELD fp_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 {
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 54585e9..2c79c69 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -479,6 +479,8 @@ static struct dw_loc_descr_struct *build_cfa_loc
static struct dw_loc_descr_struct *build_cfa_aligned_loc
(HOST_WIDE_INT, HOST_WIDE_INT);
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. */
#ifndef ASM_COMMENT_START
@@ -1833,6 +1835,17 @@ dwarf2out_frame_debug_def_cfa (rtx pat, const char *label)
cfa.reg = REGNO (pat);
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:
/* Recurse and define an expression. */
gcc_unreachable ();
@@ -1951,6 +1964,34 @@ dwarf2out_frame_debug_cfa_register (rtx set, const char *label)
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. */
static void
@@ -2740,6 +2781,14 @@ dwarf2out_frame_debug (rtx insn, bool after_p)
handled_one = true;
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:
n = XEXP (note, 0);
if (n == NULL)
@@ -6181,8 +6230,6 @@ static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT,
enum var_init_status);
static int is_based_loc (const_rtx);
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,
enum var_init_status);
static dw_loc_descr_ref loc_descriptor (rtx, enum machine_mode mode,
diff --git a/gcc/reg-notes.def b/gcc/reg-notes.def
index aa2daea..f82e7b7 100644
--- a/gcc/reg-notes.def
+++ b/gcc/reg-notes.def
@@ -148,6 +148,12 @@ REG_NOTE (CFA_OFFSET)
or the pattern should be simple reg-reg move. */
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
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