@@ -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;
@@ -10064,6 +10111,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
@@ -10116,6 +10164,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
@@ -10156,6 +10205,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,
@@ -10190,6 +10240,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)
@@ -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 {
@@ -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,
@@ -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