From patchwork Tue Sep 21 21:32:56 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 65380 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 13D10B70CB for ; Wed, 22 Sep 2010 07:34:26 +1000 (EST) Received: (qmail 25675 invoked by alias); 21 Sep 2010 21:34:22 -0000 Received: (qmail 24963 invoked by uid 22791); 21 Sep 2010 21:34:15 -0000 X-SWARE-Spam-Status: No, hits=-5.7 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 21 Sep 2010 21:34:07 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o8LLWwqQ005596 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 21 Sep 2010 17:32:58 -0400 Received: from anchor.twiddle.home (vpn-10-222.rdu.redhat.com [10.11.10.222]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o8LLWu5K017814; Tue, 21 Sep 2010 17:32:57 -0400 Message-ID: <4C992488.40804@redhat.com> Date: Tue, 21 Sep 2010 14:32:56 -0700 From: Richard Henderson User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.9) Gecko/20100907 Fedora/3.1.3-1.fc13 Thunderbird/3.1.3 MIME-Version: 1.0 To: Steve Ellcey CC: GCC Patches Subject: [ia64] Cleanup unwind info annotations X-IsSubscribed: yes 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 In the "Hookize TARGET_UNWIND_INFO" thread we found a number of problems with the generic dwarf2 interpretation of the RTX_FRAME_RELATED_P insns. While we don't actually emit dwarf2 unwind info for this target, we do convert the unwind info into location lists for pre-dwarf3 DW_AT_frame_base. This patch avoids all of the guesswork in dwarf2out_frame_debug_expr by using the very specific REG_CFA_* notes. At the same time, we get to clean up the similar guesswork in the backend which emits the ia64 unwind info. I've successfully built to stage3 with this patch (standalone, not on top of the "hookize" patch). However, I get comparison failures before and after the patch: Bootstrap comparison failure! gcc/cp/decl.o differs gcc/cp/name-lookup.o differs by which I conclude that ia64-linux isn't in great shape at the moment. I'll keep digging into this, but thought I should pass on the patch anyway. Comments appreciated. r~ diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index d02d2b8..b63303f 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -230,7 +230,6 @@ static void emit_predicate_relation_info (void); static void ia64_reorg (void); static bool ia64_in_small_data_p (const_tree); static void process_epilogue (FILE *, rtx, bool, bool); -static int process_set (FILE *, rtx, rtx, bool, bool); static bool ia64_assemble_integer (rtx, unsigned int, int); static void ia64_output_function_prologue (FILE *, HOST_WIDE_INT); @@ -318,6 +317,8 @@ static enum machine_mode ia64_promote_function_mode (const_tree, int); static void ia64_trampoline_init (rtx, tree, rtx); static void ia64_override_options_after_change (void); + +static void ia64_dwarf_handle_frame_unspec (const char *, rtx, int); /* Table of valid machine attributes. */ static const struct attribute_spec ia64_attribute_table[] = @@ -527,6 +528,8 @@ static const struct attribute_spec ia64_attribute_table[] = #undef TARGET_GIMPLIFY_VA_ARG_EXPR #define TARGET_GIMPLIFY_VA_ARG_EXPR ia64_gimplify_va_arg +#undef TARGET_DWARF_HANDLE_FRAME_UNSPEC +#define TARGET_DWARF_HANDLE_FRAME_UNSPEC ia64_dwarf_handle_frame_unspec #undef TARGET_ASM_UNWIND_EMIT #define TARGET_ASM_UNWIND_EMIT ia64_asm_unwind_emit #undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY @@ -3035,7 +3038,7 @@ do_spill (rtx (*move_fn) (rtx, rtx, rtx), rtx reg, HOST_WIDE_INT cfa_off, off = current_frame_info.total_size - cfa_off; } - add_reg_note (insn, REG_FRAME_RELATED_EXPR, + add_reg_note (insn, REG_CFA_OFFSET, gen_rtx_SET (VOIDmode, gen_rtx_MEM (GET_MODE (reg), plus_constant (base, off)), @@ -3219,6 +3222,10 @@ ia64_expand_prologue (void) { insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); RTX_FRAME_RELATED_P (insn) = 1; + + /* Force the unwind info to recognize this as defining a new CFA, + rather than some temp register setup. */ + add_reg_note (insn, REG_CFA_ADJUST_CFA, NULL_RTX); } if (current_frame_info.total_size != 0) @@ -3241,13 +3248,12 @@ ia64_expand_prologue (void) if (! frame_pointer_needed) { RTX_FRAME_RELATED_P (insn) = 1; - if (GET_CODE (offset) != CONST_INT) - add_reg_note (insn, REG_FRAME_RELATED_EXPR, - gen_rtx_SET (VOIDmode, - stack_pointer_rtx, - gen_rtx_PLUS (DImode, - stack_pointer_rtx, - frame_size_rtx))); + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (VOIDmode, + stack_pointer_rtx, + gen_rtx_PLUS (DImode, + stack_pointer_rtx, + frame_size_rtx))); } /* ??? At this point we must generate a magic insn that appears to @@ -3275,7 +3281,11 @@ ia64_expand_prologue (void) reg = gen_rtx_REG (DImode, AR_UNAT_REGNUM); insn = emit_move_insn (ar_unat_save_reg, reg); - RTX_FRAME_RELATED_P (insn) = (current_frame_info.r[reg_save_ar_unat] != 0); + if (current_frame_info.r[reg_save_ar_unat]) + { + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX); + } /* Even if we're not going to generate an epilogue, we still need to save the register so that EH works. */ @@ -3314,8 +3324,7 @@ ia64_expand_prologue (void) /* ??? Denote pr spill/fill by a DImode move that modifies all 64 hard registers. */ RTX_FRAME_RELATED_P (insn) = 1; - add_reg_note (insn, REG_FRAME_RELATED_EXPR, - gen_rtx_SET (VOIDmode, alt_reg, reg)); + add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX); /* Even if we're not going to generate an epilogue, we still need to save the register so that EH works. */ @@ -3361,6 +3370,7 @@ ia64_expand_prologue (void) reg_emitted (reg_save_ar_lc); insn = emit_move_insn (alt_reg, reg); RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX); /* Even if we're not going to generate an epilogue, we still need to save the register so that EH works. */ @@ -3387,6 +3397,7 @@ ia64_expand_prologue (void) reg_emitted (reg_save_b0); insn = emit_move_insn (alt_reg, reg); RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX); /* Even if we're not going to generate an epilogue, we still need to save the register so that EH works. */ @@ -3677,6 +3688,7 @@ ia64_expand_epilogue (int sibcall_p) { insn = emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx); RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_ADJUST_CFA, NULL); } else if (current_frame_info.total_size) { @@ -3696,13 +3708,12 @@ ia64_expand_epilogue (int sibcall_p) offset)); RTX_FRAME_RELATED_P (insn) = 1; - if (GET_CODE (offset) != CONST_INT) - add_reg_note (insn, REG_FRAME_RELATED_EXPR, - gen_rtx_SET (VOIDmode, - stack_pointer_rtx, - gen_rtx_PLUS (DImode, - stack_pointer_rtx, - frame_size_rtx))); + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (VOIDmode, + stack_pointer_rtx, + gen_rtx_PLUS (DImode, + stack_pointer_rtx, + frame_size_rtx))); } if (cfun->machine->ia64_eh_epilogue_bsp) @@ -3713,11 +3724,12 @@ ia64_expand_epilogue (int sibcall_p) else { int fp = GR_REG (2); - /* We need a throw away register here, r0 and r1 are reserved, so r2 is the - first available call clobbered register. If there was a frame_pointer - register, we may have swapped the names of r2 and HARD_FRAME_POINTER_REGNUM, - so we have to make sure we're using the string "r2" when emitting - the register name for the assembler. */ + /* We need a throw away register here, r0 and r1 are reserved, + so r2 is the first available call clobbered register. If + there was a frame_pointer register, we may have swapped the + names of r2 and HARD_FRAME_POINTER_REGNUM, so we have to make + sure we're using the string "r2" when emitting the register + name for the assembler. */ if (current_frame_info.r[reg_fp] && current_frame_info.r[reg_fp] == GR_REG (2)) fp = HARD_FRAME_POINTER_REGNUM; @@ -9590,6 +9602,17 @@ ia64_dwarf2out_def_steady_cfa (rtx insn, bool frame) + ARG_POINTER_CFA_OFFSET (current_function_decl)); } +/* All we need to do here is avoid a crash in the generic dwarf2 + processing. The real CFA definition is set up above. */ + +static void +ia64_dwarf_handle_frame_unspec (const char * ARG_UNUSED (label), + rtx ARG_UNUSED (pattern), + int index) +{ + gcc_assert (index == UNSPECV_ALLOC); +} + /* The generic dwarf2 frame debug info generator does not define a separate region for the very end of the epilogue, so refrain from doing so in the IA64-specific code as well. */ @@ -9619,53 +9642,19 @@ process_epilogue (FILE *asm_out_file, rtx insn, bool unwind, bool frame) STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET); } -/* This function processes a SET pattern looking for specific patterns - which result in emitting an assembly directive required for unwinding. */ +/* This function processes a SET pattern for REG_CFA_ADJUST_CFA. */ -static int -process_set (FILE *asm_out_file, rtx pat, rtx insn, bool unwind, bool frame) +static void +process_cfa_adjust_cfa (FILE *asm_out_file, rtx pat, rtx insn, + bool unwind, bool frame) { - rtx src = SET_SRC (pat); rtx dest = SET_DEST (pat); - int src_regno, dest_regno; - - /* Look for the ALLOC insn. */ - if (GET_CODE (src) == UNSPEC_VOLATILE - && XINT (src, 1) == UNSPECV_ALLOC - && GET_CODE (dest) == REG) - { - dest_regno = REGNO (dest); - - /* If this is the final destination for ar.pfs, then this must - be the alloc in the prologue. */ - if (dest_regno == current_frame_info.r[reg_save_ar_pfs]) - { - if (unwind) - fprintf (asm_out_file, "\t.save ar.pfs, r%d\n", - ia64_dbx_register_number (dest_regno)); - } - else - { - /* This must be an alloc before a sibcall. We must drop the - old frame info. The easiest way to drop the old frame - info is to ensure we had a ".restore sp" directive - followed by a new prologue. If the procedure doesn't - have a memory-stack frame, we'll issue a dummy ".restore - sp" now. */ - if (current_frame_info.total_size == 0 && !frame_pointer_needed) - /* if haven't done process_epilogue() yet, do it now */ - process_epilogue (asm_out_file, insn, unwind, frame); - if (unwind) - fprintf (asm_out_file, "\t.prologue\n"); - } - return 1; - } + rtx src = SET_SRC (pat); - /* Look for SP = .... */ - if (GET_CODE (dest) == REG && REGNO (dest) == STACK_POINTER_REGNUM) + if (dest == stack_pointer_rtx) { if (GET_CODE (src) == PLUS) - { + { rtx op0 = XEXP (src, 0); rtx op1 = XEXP (src, 1); @@ -9675,7 +9664,8 @@ process_set (FILE *asm_out_file, rtx pat, rtx insn, bool unwind, bool frame) { gcc_assert (!frame_pointer_needed); if (unwind) - fprintf (asm_out_file, "\t.fframe "HOST_WIDE_INT_PRINT_DEC"\n", + fprintf (asm_out_file, + "\t.fframe "HOST_WIDE_INT_PRINT_DEC"\n", -INTVAL (op1)); ia64_dwarf2out_def_steady_cfa (insn, frame); } @@ -9684,240 +9674,298 @@ process_set (FILE *asm_out_file, rtx pat, rtx insn, bool unwind, bool frame) } else { - gcc_assert (GET_CODE (src) == REG - && REGNO (src) == HARD_FRAME_POINTER_REGNUM); + gcc_assert (src == hard_frame_pointer_rtx); process_epilogue (asm_out_file, insn, unwind, frame); } + } + else if (dest == hard_frame_pointer_rtx) + { + gcc_assert (src == stack_pointer_rtx); + gcc_assert (frame_pointer_needed); - return 1; + if (unwind) + fprintf (asm_out_file, "\t.vframe r%d\n", + ia64_dbx_register_number (REGNO (dest))); + ia64_dwarf2out_def_steady_cfa (insn, frame); } + else + gcc_unreachable (); +} - /* Register move we need to look at. */ - if (GET_CODE (dest) == REG && GET_CODE (src) == REG) - { - src_regno = REGNO (src); - dest_regno = REGNO (dest); +/* This function processes a SET pattern for REG_CFA_REGISTER. */ - switch (src_regno) - { - case BR_REG (0): - /* Saving return address pointer. */ - gcc_assert (dest_regno == current_frame_info.r[reg_save_b0]); - if (unwind) - fprintf (asm_out_file, "\t.save rp, r%d\n", - ia64_dbx_register_number (dest_regno)); - return 1; +static void +process_cfa_register (FILE *asm_out_file, rtx pat, bool unwind) +{ + rtx dest = SET_DEST (pat); + rtx src = SET_SRC (pat); - case PR_REG (0): - gcc_assert (dest_regno == current_frame_info.r[reg_save_pr]); - if (unwind) - fprintf (asm_out_file, "\t.save pr, r%d\n", - ia64_dbx_register_number (dest_regno)); - return 1; + int dest_regno = REGNO (dest); + int src_regno = REGNO (src); - case AR_UNAT_REGNUM: - gcc_assert (dest_regno == current_frame_info.r[reg_save_ar_unat]); - if (unwind) - fprintf (asm_out_file, "\t.save ar.unat, r%d\n", - ia64_dbx_register_number (dest_regno)); - return 1; + switch (src_regno) + { + case BR_REG (0): + /* Saving return address pointer. */ + gcc_assert (dest_regno == current_frame_info.r[reg_save_b0]); + if (unwind) + fprintf (asm_out_file, "\t.save rp, r%d\n", + ia64_dbx_register_number (dest_regno)); + break; - case AR_LC_REGNUM: - gcc_assert (dest_regno == current_frame_info.r[reg_save_ar_lc]); - if (unwind) - fprintf (asm_out_file, "\t.save ar.lc, r%d\n", - ia64_dbx_register_number (dest_regno)); - return 1; + case PR_REG (0): + gcc_assert (dest_regno == current_frame_info.r[reg_save_pr]); + if (unwind) + fprintf (asm_out_file, "\t.save pr, r%d\n", + ia64_dbx_register_number (dest_regno)); + break; - case STACK_POINTER_REGNUM: - gcc_assert (dest_regno == HARD_FRAME_POINTER_REGNUM - && frame_pointer_needed); - if (unwind) - fprintf (asm_out_file, "\t.vframe r%d\n", - ia64_dbx_register_number (dest_regno)); - ia64_dwarf2out_def_steady_cfa (insn, frame); - return 1; + case AR_UNAT_REGNUM: + gcc_assert (dest_regno == current_frame_info.r[reg_save_ar_unat]); + if (unwind) + fprintf (asm_out_file, "\t.save ar.unat, r%d\n", + ia64_dbx_register_number (dest_regno)); + break; - default: - /* Everything else should indicate being stored to memory. */ - gcc_unreachable (); - } + case AR_LC_REGNUM: + gcc_assert (dest_regno == current_frame_info.r[reg_save_ar_lc]); + if (unwind) + fprintf (asm_out_file, "\t.save ar.lc, r%d\n", + ia64_dbx_register_number (dest_regno)); + break; + + default: + /* Everything else should indicate being stored to memory. */ + gcc_unreachable (); } +} - /* Memory store we need to look at. */ - if (GET_CODE (dest) == MEM && GET_CODE (src) == REG) - { - long off; - rtx base; - const char *saveop; +/* This function processes a SET pattern for REG_CFA_OFFSET. */ - if (GET_CODE (XEXP (dest, 0)) == REG) - { - base = XEXP (dest, 0); - off = 0; - } - else - { - gcc_assert (GET_CODE (XEXP (dest, 0)) == PLUS - && GET_CODE (XEXP (XEXP (dest, 0), 1)) == CONST_INT); - base = XEXP (XEXP (dest, 0), 0); - off = INTVAL (XEXP (XEXP (dest, 0), 1)); - } +static void +process_cfa_offset (FILE *asm_out_file, rtx pat, bool unwind) +{ + rtx dest = SET_DEST (pat); + rtx src = SET_SRC (pat); + int src_regno = REGNO (src); + const char *saveop; + HOST_WIDE_INT off; + rtx base; - if (base == hard_frame_pointer_rtx) - { - saveop = ".savepsp"; - off = - off; - } - else - { - gcc_assert (base == stack_pointer_rtx); - saveop = ".savesp"; - } + gcc_assert (MEM_P (dest)); + if (GET_CODE (XEXP (dest, 0)) == REG) + { + base = XEXP (dest, 0); + off = 0; + } + else + { + gcc_assert (GET_CODE (XEXP (dest, 0)) == PLUS + && GET_CODE (XEXP (XEXP (dest, 0), 1)) == CONST_INT); + base = XEXP (XEXP (dest, 0), 0); + off = INTVAL (XEXP (XEXP (dest, 0), 1)); + } - src_regno = REGNO (src); - switch (src_regno) - { - case BR_REG (0): - gcc_assert (!current_frame_info.r[reg_save_b0]); - if (unwind) - fprintf (asm_out_file, "\t%s rp, %ld\n", saveop, off); - return 1; + if (base == hard_frame_pointer_rtx) + { + saveop = ".savepsp"; + off = - off; + } + else + { + gcc_assert (base == stack_pointer_rtx); + saveop = ".savesp"; + } - case PR_REG (0): - gcc_assert (!current_frame_info.r[reg_save_pr]); - if (unwind) - fprintf (asm_out_file, "\t%s pr, %ld\n", saveop, off); - return 1; + src_regno = REGNO (src); + switch (src_regno) + { + case BR_REG (0): + gcc_assert (!current_frame_info.r[reg_save_b0]); + if (unwind) + fprintf (asm_out_file, "\t%s rp, %ld\n", saveop, off); + break; - case AR_LC_REGNUM: - gcc_assert (!current_frame_info.r[reg_save_ar_lc]); - if (unwind) - fprintf (asm_out_file, "\t%s ar.lc, %ld\n", saveop, off); - return 1; + case PR_REG (0): + gcc_assert (!current_frame_info.r[reg_save_pr]); + if (unwind) + fprintf (asm_out_file, "\t%s pr, %ld\n", saveop, off); + break; - case AR_PFS_REGNUM: - gcc_assert (!current_frame_info.r[reg_save_ar_pfs]); - if (unwind) - fprintf (asm_out_file, "\t%s ar.pfs, %ld\n", saveop, off); - return 1; + case AR_LC_REGNUM: + gcc_assert (!current_frame_info.r[reg_save_ar_lc]); + if (unwind) + fprintf (asm_out_file, "\t%s ar.lc, %ld\n", saveop, off); + break; - case AR_UNAT_REGNUM: - gcc_assert (!current_frame_info.r[reg_save_ar_unat]); - if (unwind) - fprintf (asm_out_file, "\t%s ar.unat, %ld\n", saveop, off); - return 1; + case AR_PFS_REGNUM: + gcc_assert (!current_frame_info.r[reg_save_ar_pfs]); + if (unwind) + fprintf (asm_out_file, "\t%s ar.pfs, %ld\n", saveop, off); + break; - case GR_REG (4): - case GR_REG (5): - case GR_REG (6): - case GR_REG (7): - if (unwind) - fprintf (asm_out_file, "\t.save.g 0x%x\n", - 1 << (src_regno - GR_REG (4))); - return 1; + case AR_UNAT_REGNUM: + gcc_assert (!current_frame_info.r[reg_save_ar_unat]); + if (unwind) + fprintf (asm_out_file, "\t%s ar.unat, %ld\n", saveop, off); + break; - case BR_REG (1): - case BR_REG (2): - case BR_REG (3): - case BR_REG (4): - case BR_REG (5): - if (unwind) - fprintf (asm_out_file, "\t.save.b 0x%x\n", - 1 << (src_regno - BR_REG (1))); - return 1; + case GR_REG (4): + case GR_REG (5): + case GR_REG (6): + case GR_REG (7): + if (unwind) + fprintf (asm_out_file, "\t.save.g 0x%x\n", + 1 << (src_regno - GR_REG (4))); + break; - case FR_REG (2): - case FR_REG (3): - case FR_REG (4): - case FR_REG (5): - if (unwind) - fprintf (asm_out_file, "\t.save.f 0x%x\n", - 1 << (src_regno - FR_REG (2))); - return 1; + case BR_REG (1): + case BR_REG (2): + case BR_REG (3): + case BR_REG (4): + case BR_REG (5): + if (unwind) + fprintf (asm_out_file, "\t.save.b 0x%x\n", + 1 << (src_regno - BR_REG (1))); + break; - case FR_REG (16): case FR_REG (17): case FR_REG (18): case FR_REG (19): - case FR_REG (20): case FR_REG (21): case FR_REG (22): case FR_REG (23): - case FR_REG (24): case FR_REG (25): case FR_REG (26): case FR_REG (27): - case FR_REG (28): case FR_REG (29): case FR_REG (30): case FR_REG (31): - if (unwind) - fprintf (asm_out_file, "\t.save.gf 0x0, 0x%x\n", - 1 << (src_regno - FR_REG (12))); - return 1; + case FR_REG (2): + case FR_REG (3): + case FR_REG (4): + case FR_REG (5): + if (unwind) + fprintf (asm_out_file, "\t.save.f 0x%x\n", + 1 << (src_regno - FR_REG (2))); + break; - default: - return 0; - } - } + case FR_REG (16): case FR_REG (17): case FR_REG (18): case FR_REG (19): + case FR_REG (20): case FR_REG (21): case FR_REG (22): case FR_REG (23): + case FR_REG (24): case FR_REG (25): case FR_REG (26): case FR_REG (27): + case FR_REG (28): case FR_REG (29): case FR_REG (30): case FR_REG (31): + if (unwind) + fprintf (asm_out_file, "\t.save.gf 0x0, 0x%x\n", + 1 << (src_regno - FR_REG (12))); + break; - return 0; + default: + /* ??? For some reason we mark other general registers, even those + we can't represent in the unwind info. Ignore them. */ + break; + } } - /* This function looks at a single insn and emits any directives required to unwind this insn. */ + static void ia64_asm_unwind_emit (FILE *asm_out_file, rtx insn) { bool unwind = (flag_unwind_tables || (flag_exceptions && !USING_SJLJ_EXCEPTIONS)); bool frame = dwarf2out_do_frame (); + rtx note, pat; + bool handled_one; + + if (!unwind && !frame) + return; - if (unwind || frame) + if (NOTE_INSN_BASIC_BLOCK_P (insn)) { - rtx pat; + last_block = NOTE_BASIC_BLOCK (insn)->next_bb == EXIT_BLOCK_PTR; - if (NOTE_INSN_BASIC_BLOCK_P (insn)) + /* Restore unwind state from immediately before the epilogue. */ + if (need_copy_state) { - last_block = NOTE_BASIC_BLOCK (insn)->next_bb == EXIT_BLOCK_PTR; - - /* Restore unwind state from immediately before the epilogue. */ - if (need_copy_state) + if (unwind) { - if (unwind) - { - fprintf (asm_out_file, "\t.body\n"); - fprintf (asm_out_file, "\t.copy_state %d\n", - cfun->machine->state_num); - } - if (IA64_CHANGE_CFA_IN_EPILOGUE) - ia64_dwarf2out_def_steady_cfa (insn, frame); - need_copy_state = false; + fprintf (asm_out_file, "\t.body\n"); + fprintf (asm_out_file, "\t.copy_state %d\n", + cfun->machine->state_num); } + if (IA64_CHANGE_CFA_IN_EPILOGUE) + ia64_dwarf2out_def_steady_cfa (insn, frame); + need_copy_state = false; } + } - if (GET_CODE (insn) == NOTE || ! RTX_FRAME_RELATED_P (insn)) - return; + if (GET_CODE (insn) == NOTE || ! RTX_FRAME_RELATED_P (insn)) + return; + + /* Look for the ALLOC insn. */ + if (INSN_CODE (insn) == CODE_FOR_alloc) + { + rtx dest = SET_DEST (XVECEXP (PATTERN (insn), 0, 0)); + int dest_regno = REGNO (dest); - pat = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX); - if (pat) - pat = XEXP (pat, 0); + /* If this is the final destination for ar.pfs, then this must + be the alloc in the prologue. */ + if (dest_regno == current_frame_info.r[reg_save_ar_pfs]) + { + if (unwind) + fprintf (asm_out_file, "\t.save ar.pfs, r%d\n", + ia64_dbx_register_number (dest_regno)); + } else - pat = PATTERN (insn); + { + /* This must be an alloc before a sibcall. We must drop the + old frame info. The easiest way to drop the old frame + info is to ensure we had a ".restore sp" directive + followed by a new prologue. If the procedure doesn't + have a memory-stack frame, we'll issue a dummy ".restore + sp" now. */ + if (current_frame_info.total_size == 0 && !frame_pointer_needed) + /* if haven't done process_epilogue() yet, do it now */ + process_epilogue (asm_out_file, insn, unwind, frame); + if (unwind) + fprintf (asm_out_file, "\t.prologue\n"); + } + return; + } - switch (GET_CODE (pat)) - { - case SET: - process_set (asm_out_file, pat, insn, unwind, frame); - break; + handled_one = false; + for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) + switch (REG_NOTE_KIND (note)) + { + case REG_CFA_ADJUST_CFA: + pat = XEXP (note, 0); + if (pat == NULL) + pat = PATTERN (insn); + process_cfa_adjust_cfa (asm_out_file, pat, insn, unwind, frame); + handled_one = true; + break; - case PARALLEL: - { - int par_index; - int limit = XVECLEN (pat, 0); - for (par_index = 0; par_index < limit; par_index++) - { - rtx x = XVECEXP (pat, 0, par_index); - if (GET_CODE (x) == SET) - process_set (asm_out_file, x, insn, unwind, frame); - } - break; - } + case REG_CFA_OFFSET: + pat = XEXP (note, 0); + if (pat == NULL) + pat = PATTERN (insn); + process_cfa_offset (asm_out_file, pat, unwind); + handled_one = true; + break; - default: - gcc_unreachable (); - } - } + case REG_CFA_REGISTER: + pat = XEXP (note, 0); + if (pat == NULL) + pat = PATTERN (insn); + process_cfa_register (asm_out_file, pat, unwind); + handled_one = true; + break; + + case REG_FRAME_RELATED_EXPR: + case REG_CFA_DEF_CFA: + case REG_CFA_EXPRESSION: + case REG_CFA_RESTORE: + case REG_CFA_SET_VDRAP: + /* Not used in the ia64 port. */ + gcc_unreachable (); + + default: + /* Not a frame-related note. */ + break; + } + + /* All REG_FRAME_RELATED_P insns, besides ALLOC, are marked with the + explicit action to take. No guessing required. */ + gcc_assert (handled_one); } /* Implement TARGET_ASM_EMIT_EXCEPT_PERSONALITY. */