From patchwork Tue Aug 3 23:53:14 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 60809 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 47E1FB70A8 for ; Wed, 4 Aug 2010 09:55:19 +1000 (EST) Received: (qmail 10508 invoked by alias); 3 Aug 2010 23:53:48 -0000 Received: (qmail 9994 invoked by uid 22791); 3 Aug 2010 23:53:40 -0000 X-SWARE-Spam-Status: No, hits=-1.7 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_NONE X-Spam-Check-By: sourceware.org Received: from a.mail.sonic.net (HELO a.mail.sonic.net) (64.142.16.245) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 03 Aug 2010 23:53:24 +0000 Received: from are.twiddle.net (are.twiddle.net [75.101.38.216]) by a.mail.sonic.net (8.13.8.Beta0-Sonic/8.13.7) with ESMTP id o73NrMUj006123 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 3 Aug 2010 16:53:22 -0700 Received: from are.twiddle.net (localhost [127.0.0.1]) by are.twiddle.net (8.14.4/8.14.4) with ESMTP id o73NrLCW001161; Tue, 3 Aug 2010 16:53:21 -0700 Received: (from rth@localhost) by are.twiddle.net (8.14.4/8.14.4/Submit) id o73NrLiZ001160; Tue, 3 Aug 2010 16:53:21 -0700 From: Richard Henderson To: gcc-patches@gcc.gnu.org Cc: kai.tietz@onevision.com, ubizjak@gmail.com Subject: [PATCH 7/9] Describe unwinding for realigned frames explicitly. Date: Tue, 3 Aug 2010 16:53:14 -0700 Message-Id: <1280879596-1089-8-git-send-email-rth@twiddle.net> In-Reply-To: <1280879596-1089-1-git-send-email-rth@twiddle.net> References: <1280879596-1089-1-git-send-email-rth@twiddle.net> Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org 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. --- gcc/config/i386/i386.c | 67 ++++++++++++++++++++++++++++++++++++++++++----- gcc/config/i386/i386.h | 5 +++ gcc/dwarf2out.c | 51 +++++++++++++++++++++++++++++++++++- gcc/reg-notes.def | 6 ++++ 4 files changed, 119 insertions(+), 10 deletions(-) * 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. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index f465600..b4fddfc 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; @@ -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) 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 d8d3851..1ac874b 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