diff options
-rw-r--r-- | gcc/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 67 | ||||
-rw-r--r-- | gcc/config/i386/i386.h | 5 | ||||
-rw-r--r-- | gcc/dwarf2out.c | 51 | ||||
-rw-r--r-- | gcc/reg-notes.def | 6 |
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 |