From patchwork Thu Mar 31 19:59:02 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bernd Schmidt X-Patchwork-Id: 89125 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 14845B6EDF for ; Fri, 1 Apr 2011 07:02:08 +1100 (EST) Received: (qmail 9188 invoked by alias); 31 Mar 2011 20:02:05 -0000 Received: (qmail 9145 invoked by uid 22791); 31 Mar 2011 20:01:57 -0000 X-SWARE-Spam-Status: No, hits=-0.4 required=5.0 tests=AWL, BAYES_50, TW_CF, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 31 Mar 2011 20:01:44 +0000 Received: (qmail 31407 invoked from network); 31 Mar 2011 20:01:42 -0000 Received: from unknown (HELO ?84.152.157.219?) (bernds@127.0.0.2) by mail.codesourcery.com with ESMTPA; 31 Mar 2011 20:01:42 -0000 Message-ID: <4D94DD06.9030507@codesourcery.com> Date: Thu, 31 Mar 2011 21:59:02 +0200 From: Bernd Schmidt User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.15) Gecko/20110325 Lightning/1.0b3pre Thunderbird/3.1.9 MIME-Version: 1.0 To: Richard Henderson CC: GCC Patches Subject: Re: [PATCH 3/6] Allow jumps in epilogues References: <4D8A0703.9090306@codesourcery.com> <4D8A089D.7020507@codesourcery.com> <4D8A23E8.4090802@redhat.com> <4D8A245A.20701@codesourcery.com> <4D8A2B86.4080402@redhat.com> <4D8CD227.5090205@codesourcery.com> <4D8D5CCC.10705@redhat.com> In-Reply-To: <4D8D5CCC.10705@redhat.com> 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 On 03/26/2011 04:26 AM, Richard Henderson wrote: > I think the ideal thing would be a pass while the cfg is still extant that > captures the unwind info into notes; these can be recorded at basic block > boundaries, so that they persist until the end of compilation. > > So long as late late compilation passes continue to not move frame-related > insns across basic block boundaries, we should be fine. I'm nervous about this as the reorg pass can do arbitrary transformations. On Blackfin for example, we can reorder basic blocks for the sake of loop optimizations; sched-ebb can create new blocks, etc. I think it would be best if we can somehow make it work during final, without a CFG. > I'm willing to work with you on the problem of cfg-aware unwind info. We > have needed this for a really long time; there are existing bugs related > to exception handling and !ACCUMULATE_OUTGOING_ARGS that would be fixed by > this. I'm appending a series of draft patches. It tries to compute CFIs for stretches of straight-line code and records state for potential jump targets, iterating until everything is covered. Then, a pass through all insns from start to finish reassembles the pieces into a coherent string of CFI insns. Rather than use a CFG, I've tried to do something similar to compute_barrier_args_size, using JUMP_LABELs etc. Summary of the patches: 001 - just create a dwarf2out_frame_debug_init function. 002 - Make it walk the function in a first pass and record CFIs to be output later 003 - Store dw_cfi_refs in VECs rather than linked lists. Looks larger than it is due to reindentation 004 - Change the function walk introduced in 002 so that it records and restores state when reaching jumps/barriers For now I'd just like some input on whether this looks remotely viable. There are a number of known problems with it: * The generated CFIs are inefficient (poor use of remember/restore) * -freorder-blocks-and-partition is broken * i386.c uses dwarf2out_frame_debug directly in some cases and is unconverted * I haven't tested whether my attempt to use get_eh_landing_pad_from_rtx in the absence of a CFG actually works * Computed jumps and nonlocal gotos aren't handled. I think this could be done by recording the state at NOTE_INSN_PROLOGUE_END and using that for all labels we can't otherwise reach. Bernd * cfgcleanup.c (flow_find_head_matching_sequence): Ignore epilogue notes. * df-problems.c (can_move_insns_across): Don't stop at epilogue notes. * dwarf2out.c (dwarf2out_cfi_begin_epilogue): Also allow a simplejump to end the block. Index: gcc/dwarf2out.c =================================================================== --- gcc.orig/dwarf2out.c +++ gcc/dwarf2out.c @@ -471,6 +471,8 @@ static void output_call_frame_info (int) static void dwarf2out_note_section_used (void); static bool clobbers_queued_reg_save (const_rtx); static void dwarf2out_frame_debug_expr (rtx, const char *); +static void dwarf2out_cfi_begin_epilogue (rtx); +static void dwarf2out_frame_debug_restore_state (void); /* Support for complex CFA locations. */ static void output_cfa_loc (dw_cfi_ref, int); @@ -879,6 +881,9 @@ dwarf2out_cfi_label (bool force) return label; } +/* The insn after which a new CFI note should be emitted. */ +static rtx cfi_insn; + /* True if remember_state should be emitted before following CFI directive. */ static bool emit_cfa_remember; @@ -961,7 +966,8 @@ add_fde_cfi (const char *label, dw_cfi_r } } - output_cfi_directive (cfi); + cfi_insn = emit_note_after (NOTE_INSN_CFI, cfi_insn); + NOTE_CFI (cfi_insn) = cfi; list_head = &fde->dw_fde_cfi; any_cfis_emitted = true; @@ -2790,6 +2796,11 @@ dwarf2out_frame_debug (rtx insn, bool af rtx note, n; bool handled_one = false; + if (after_p) + cfi_insn = insn; + else + cfi_insn = PREV_INSN (insn); + if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn)) dwarf2out_flush_queued_reg_saves (); @@ -2911,6 +2922,7 @@ void dwarf2out_frame_debug_init (void) { size_t i; + rtx insn; /* Flush any queued register saves. */ dwarf2out_flush_queued_reg_saves (); @@ -2937,12 +2949,64 @@ dwarf2out_frame_debug_init (void) XDELETEVEC (barrier_args_size); barrier_args_size = NULL; } + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + rtx pat; + if (BARRIER_P (insn)) + { + dwarf2out_frame_debug (insn, false); + continue; + } + else if (NOTE_P (insn)) + { + switch (NOTE_KIND (insn)) + { + case NOTE_INSN_EPILOGUE_BEG: +#if defined (HAVE_epilogue) + dwarf2out_cfi_begin_epilogue (insn); +#endif + break; + case NOTE_INSN_CFA_RESTORE_STATE: + cfi_insn = insn; + dwarf2out_frame_debug_restore_state (); + break; + } + continue; + } + if (!NONDEBUG_INSN_P (insn)) + continue; + pat = PATTERN (insn); + if (asm_noperands (pat) >= 0) + continue; + if (GET_CODE (pat) == SEQUENCE) + { + int j; + for (j = 1; j < XVECLEN (pat, 0); j++) + dwarf2out_frame_debug (XVECEXP (pat, 0, j), false); + insn = XVECEXP (pat, 0, 0); + } + + if (CALL_P (insn) && dwarf2out_do_frame ()) + dwarf2out_frame_debug (insn, false); + if (dwarf2out_do_frame () +#if !defined (HAVE_prologue) + && !ACCUMULATE_OUTGOING_ARGS +#endif + ) + dwarf2out_frame_debug (insn, true); + } +} + +void +dwarf2out_emit_cfi (dw_cfi_ref cfi) +{ + output_cfi_directive (cfi); } -/* Determine if we need to save and restore CFI information around this - epilogue. If SIBCALL is true, then this is a sibcall epilogue. If - we do need to save/restore, then emit the save now, and insert a - NOTE_INSN_CFA_RESTORE_STATE at the appropriate place in the stream. */ +/* Determine if we need to save and restore CFI information around + this epilogue. If we do need to save/restore, then emit the save + now, and insert a NOTE_INSN_CFA_RESTORE_STATE at the appropriate + place in the stream. */ void dwarf2out_cfi_begin_epilogue (rtx insn) @@ -2957,8 +3021,10 @@ dwarf2out_cfi_begin_epilogue (rtx insn) if (!INSN_P (i)) continue; - /* Look for both regular and sibcalls to end the block. */ - if (returnjump_p (i)) + /* Look for both regular and sibcalls to end the block. Various + optimization passes may cause us to jump to a common epilogue + tail, so we also accept simplejumps. */ + if (returnjump_p (i) || simplejump_p (i)) break; if (CALL_P (i) && SIBLING_CALL_P (i)) break; Index: gcc/dwarf2out.h =================================================================== --- gcc.orig/dwarf2out.h +++ gcc/dwarf2out.h @@ -18,11 +18,11 @@ You should have received a copy of the G along with GCC; see the file COPYING3. If not see . */ +struct dw_cfi_struct; extern void dwarf2out_decl (tree); extern void dwarf2out_frame_debug (rtx, bool); extern void dwarf2out_frame_debug_init (void); -extern void dwarf2out_cfi_begin_epilogue (rtx); -extern void dwarf2out_frame_debug_restore_state (void); +extern void dwarf2out_emit_cfi (struct dw_cfi_struct *); extern void dwarf2out_flush_queued_reg_saves (void); extern void debug_dwarf (void); Index: gcc/insn-notes.def =================================================================== --- gcc.orig/insn-notes.def +++ gcc/insn-notes.def @@ -77,4 +77,8 @@ INSN_NOTE (SWITCH_TEXT_SECTIONS) when an epilogue appears in the middle of a function. */ INSN_NOTE (CFA_RESTORE_STATE) +/* When emitting dwarf2 frame information, contains a directive that + should be emitted. */ +INSN_NOTE (CFI) + #undef INSN_NOTE Index: gcc/rtl.h =================================================================== --- gcc.orig/rtl.h +++ gcc/rtl.h @@ -180,6 +180,7 @@ union rtunion_def mem_attrs *rt_mem; reg_attrs *rt_reg; struct constant_descriptor_rtx *rt_constant; + struct dw_cfi_struct *rt_cfi; }; typedef union rtunion_def rtunion; @@ -708,6 +709,7 @@ extern void rtl_check_failed_flag (const #define XTREE(RTX, N) (RTL_CHECK1 (RTX, N, 't').rt_tree) #define XBBDEF(RTX, N) (RTL_CHECK1 (RTX, N, 'B').rt_bb) #define XTMPL(RTX, N) (RTL_CHECK1 (RTX, N, 'T').rt_str) +#define XCFI(RTX, N) (RTL_CHECK1 (RTX, N, 'C').rt_cfi) #define XVECEXP(RTX, N, M) RTVEC_ELT (XVEC (RTX, N), M) #define XVECLEN(RTX, N) GET_NUM_ELEM (XVEC (RTX, N)) @@ -740,6 +742,7 @@ extern void rtl_check_failed_flag (const #define XCMODE(RTX, N, C) (RTL_CHECKC1 (RTX, N, C).rt_type) #define XCTREE(RTX, N, C) (RTL_CHECKC1 (RTX, N, C).rt_tree) #define XCBBDEF(RTX, N, C) (RTL_CHECKC1 (RTX, N, C).rt_bb) +#define XCCFI(RTX, N, C) (RTL_CHECKC1 (RTX, N, C).rt_cfi) #define XCCSELIB(RTX, N, C) (RTL_CHECKC1 (RTX, N, C).rt_cselib) #define XCVECEXP(RTX, N, M, C) RTVEC_ELT (XCVEC (RTX, N, C), M) @@ -882,6 +885,7 @@ extern const char * const reg_note_name[ #define NOTE_BLOCK(INSN) XCTREE (INSN, 4, NOTE) #define NOTE_EH_HANDLER(INSN) XCINT (INSN, 4, NOTE) #define NOTE_BASIC_BLOCK(INSN) XCBBDEF (INSN, 4, NOTE) +#define NOTE_CFI(INSN) XCCFI (INSN, 4, NOTE) #define NOTE_VAR_LOCATION(INSN) XCEXP (INSN, 4, NOTE) /* In a NOTE that is a line number, this is the line number. Index: gcc/dwarf2out.c =================================================================== --- gcc.orig/dwarf2out.c +++ gcc/dwarf2out.c @@ -267,7 +267,6 @@ typedef union GTY(()) dw_cfi_oprnd_struc dw_cfi_oprnd; typedef struct GTY(()) dw_cfi_struct { - dw_cfi_ref dw_cfi_next; enum dwarf_call_frame_info dw_cfi_opc; dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd1_desc (%1.dw_cfi_opc)"))) dw_cfi_oprnd1; @@ -276,6 +275,12 @@ typedef struct GTY(()) dw_cfi_struct { } dw_cfi_node; +DEF_VEC_P (dw_cfi_ref); +DEF_VEC_ALLOC_P (dw_cfi_ref, heap); +DEF_VEC_ALLOC_P (dw_cfi_ref, gc); + +typedef VEC(dw_cfi_ref, gc) *cfi_vec; + /* This is how we define the location of the CFA. We use to handle it as REG + OFFSET all the time, but now it can be more complex. It can now be either REG + CFA_OFFSET or *(REG + BASE_OFFSET) + CFA_OFFSET. @@ -306,8 +311,8 @@ typedef struct GTY(()) dw_fde_struct { const char *dw_fde_hot_section_end_label; const char *dw_fde_unlikely_section_label; const char *dw_fde_unlikely_section_end_label; - dw_cfi_ref dw_fde_cfi; - dw_cfi_ref dw_fde_switch_cfi; /* Last CFI before switching sections. */ + cfi_vec dw_fde_cfi; + int dw_fde_switch_cfi_index; /* Last CFI before switching sections. */ HOST_WIDE_INT stack_realignment; unsigned funcdef_number; /* Dynamic realign argument pointer register. */ @@ -416,8 +421,8 @@ current_fde (void) return fde_table_in_use ? &fde_table[fde_table_in_use - 1] : NULL; } -/* A list of call frame insns for the CIE. */ -static GTY(()) dw_cfi_ref cie_cfi_head; +/* A vector of call frame insns for the CIE. */ +static GTY(()) cfi_vec cie_cfi_vec; /* Some DWARF extensions (e.g., MIPS/SGI) implement a subprogram attribute that accelerates the lookup of the FDE associated @@ -457,7 +462,7 @@ static GTY(()) section *cold_text_sectio static char *stripattributes (const char *); static const char *dwarf_cfi_name (unsigned); static dw_cfi_ref new_cfi (void); -static void add_cfi (dw_cfi_ref *, dw_cfi_ref); +static void add_cfi (cfi_vec *, dw_cfi_ref); static void add_fde_cfi (const char *, dw_cfi_ref); static void lookup_cfa_1 (dw_cfi_ref, dw_cfa_location *, dw_cfa_location *); static void lookup_cfa (dw_cfa_location *); @@ -815,7 +820,6 @@ new_cfi (void) { dw_cfi_ref cfi = ggc_alloc_dw_cfi_node (); - cfi->dw_cfi_next = NULL; cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0; cfi->dw_cfi_oprnd2.dw_cfi_reg_num = 0; @@ -825,9 +829,8 @@ new_cfi (void) /* Add a Call Frame Instruction to list of instructions. */ static inline void -add_cfi (dw_cfi_ref *list_head, dw_cfi_ref cfi) +add_cfi (cfi_vec *vec, dw_cfi_ref cfi) { - dw_cfi_ref *p; dw_fde_ref fde = current_fde (); /* When DRAP is used, CFA is defined with an expression. Redefine @@ -849,11 +852,7 @@ add_cfi (dw_cfi_ref *list_head, dw_cfi_r break; } - /* Find the end of the chain. */ - for (p = list_head; (*p) != NULL; p = &(*p)->dw_cfi_next) - ; - - *p = cfi; + VEC_safe_push (dw_cfi_ref, gc, *vec, cfi); } /* Generate a new label for the CFI info to refer to. FORCE is true @@ -896,7 +895,12 @@ static bool any_cfis_emitted; static void add_fde_cfi (const char *label, dw_cfi_ref cfi) { - dw_cfi_ref *list_head; + cfi_vec *vec; + + if (cie_cfi_vec == NULL) + cie_cfi_vec = VEC_alloc (dw_cfi_ref, gc, 20); + + vec = &cie_cfi_vec; if (emit_cfa_remember) { @@ -909,8 +913,6 @@ add_fde_cfi (const char *label, dw_cfi_r add_fde_cfi (label, cfi_remember); } - list_head = &cie_cfi_head; - if (dwarf2out_do_cfi_asm ()) { if (label) @@ -969,7 +971,7 @@ add_fde_cfi (const char *label, dw_cfi_r cfi_insn = emit_note_after (NOTE_INSN_CFI, cfi_insn); NOTE_CFI (cfi_insn) = cfi; - list_head = &fde->dw_fde_cfi; + vec = &fde->dw_fde_cfi; any_cfis_emitted = true; } /* ??? If this is a CFI for the CIE, we don't emit. This @@ -1007,11 +1009,11 @@ add_fde_cfi (const char *label, dw_cfi_r fde->dw_fde_current_label = label; } - list_head = &fde->dw_fde_cfi; + vec = &fde->dw_fde_cfi; any_cfis_emitted = true; } - add_cfi (list_head, cfi); + add_cfi (vec, cfi); } /* Subroutine of lookup_cfa. */ @@ -1058,6 +1060,7 @@ lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_loc static void lookup_cfa (dw_cfa_location *loc) { + int ix; dw_cfi_ref cfi; dw_fde_ref fde; dw_cfa_location remember; @@ -1066,12 +1069,12 @@ lookup_cfa (dw_cfa_location *loc) loc->reg = INVALID_REGNUM; remember = *loc; - for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next) + FOR_EACH_VEC_ELT (dw_cfi_ref, cie_cfi_vec, ix, cfi) lookup_cfa_1 (cfi, loc, &remember); fde = current_fde (); if (fde) - for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next) + FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi) lookup_cfa_1 (cfi, loc, &remember); } @@ -3496,169 +3499,181 @@ output_cfi_directive (dw_cfi_ref cfi) } } -DEF_VEC_P (dw_cfi_ref); -DEF_VEC_ALLOC_P (dw_cfi_ref, heap); - -/* Output CFIs to bring current FDE to the same state as after executing - CFIs in CFI chain. DO_CFI_ASM is true if .cfi_* directives shall - be emitted, false otherwise. If it is false, FDE and FOR_EH are the - other arguments to pass to output_cfi. */ +/* Output CFIs from VEC, up to index UPTO, to bring current FDE to the + same state as after executing CFIs in CFI chain. DO_CFI_ASM is + true if .cfi_* directives shall be emitted, false otherwise. If it + is false, FDE and FOR_EH are the other arguments to pass to + output_cfi. */ static void -output_cfis (dw_cfi_ref cfi, bool do_cfi_asm, dw_fde_ref fde, bool for_eh) +output_cfis (cfi_vec vec, int upto, bool do_cfi_asm, + dw_fde_ref fde, bool for_eh) { + int ix; struct dw_cfi_struct cfi_buf; dw_cfi_ref cfi2; dw_cfi_ref cfi_args_size = NULL, cfi_cfa = NULL, cfi_cfa_offset = NULL; - VEC (dw_cfi_ref, heap) *regs = VEC_alloc (dw_cfi_ref, heap, 32); + VEC(dw_cfi_ref, heap) *regs = VEC_alloc (dw_cfi_ref, heap, 32); unsigned int len, idx; - for (;; cfi = cfi->dw_cfi_next) - switch (cfi ? cfi->dw_cfi_opc : DW_CFA_nop) - { - case DW_CFA_advance_loc: - case DW_CFA_advance_loc1: - case DW_CFA_advance_loc2: - case DW_CFA_advance_loc4: - case DW_CFA_MIPS_advance_loc8: - case DW_CFA_set_loc: - /* All advances should be ignored. */ - break; - case DW_CFA_remember_state: + for (ix = 0; ix < upto + 1; ix++) + { + dw_cfi_ref cfi = ix < upto ? VEC_index (dw_cfi_ref, vec, ix) : NULL; + switch (cfi ? cfi->dw_cfi_opc : DW_CFA_nop) { - dw_cfi_ref args_size = cfi_args_size; - - /* Skip everything between .cfi_remember_state and - .cfi_restore_state. */ - for (cfi2 = cfi->dw_cfi_next; cfi2; cfi2 = cfi2->dw_cfi_next) - if (cfi2->dw_cfi_opc == DW_CFA_restore_state) - break; - else if (cfi2->dw_cfi_opc == DW_CFA_GNU_args_size) - args_size = cfi2; - else - gcc_assert (cfi2->dw_cfi_opc != DW_CFA_remember_state); - - if (cfi2 == NULL) - goto flush_all; - else - { - cfi = cfi2; - cfi_args_size = args_size; - } + case DW_CFA_advance_loc: + case DW_CFA_advance_loc1: + case DW_CFA_advance_loc2: + case DW_CFA_advance_loc4: + case DW_CFA_MIPS_advance_loc8: + case DW_CFA_set_loc: + /* All advances should be ignored. */ break; - } - case DW_CFA_GNU_args_size: - cfi_args_size = cfi; - break; - case DW_CFA_GNU_window_save: - goto flush_all; - case DW_CFA_offset: - case DW_CFA_offset_extended: - case DW_CFA_offset_extended_sf: - case DW_CFA_restore: - case DW_CFA_restore_extended: - case DW_CFA_undefined: - case DW_CFA_same_value: - case DW_CFA_register: - case DW_CFA_val_offset: - case DW_CFA_val_offset_sf: - case DW_CFA_expression: - case DW_CFA_val_expression: - case DW_CFA_GNU_negative_offset_extended: - if (VEC_length (dw_cfi_ref, regs) <= cfi->dw_cfi_oprnd1.dw_cfi_reg_num) - VEC_safe_grow_cleared (dw_cfi_ref, heap, regs, - cfi->dw_cfi_oprnd1.dw_cfi_reg_num + 1); - VEC_replace (dw_cfi_ref, regs, cfi->dw_cfi_oprnd1.dw_cfi_reg_num, cfi); - break; - case DW_CFA_def_cfa: - case DW_CFA_def_cfa_sf: - case DW_CFA_def_cfa_expression: - cfi_cfa = cfi; - cfi_cfa_offset = cfi; - break; - case DW_CFA_def_cfa_register: - cfi_cfa = cfi; - break; - case DW_CFA_def_cfa_offset: - case DW_CFA_def_cfa_offset_sf: - cfi_cfa_offset = cfi; - break; - case DW_CFA_nop: - gcc_assert (cfi == NULL); - flush_all: - len = VEC_length (dw_cfi_ref, regs); - for (idx = 0; idx < len; idx++) + case DW_CFA_remember_state: { - cfi2 = VEC_replace (dw_cfi_ref, regs, idx, NULL); - if (cfi2 != NULL - && cfi2->dw_cfi_opc != DW_CFA_restore - && cfi2->dw_cfi_opc != DW_CFA_restore_extended) + dw_cfi_ref args_size = cfi_args_size; + + /* Skip everything between .cfi_remember_state and + .cfi_restore_state. */ + for (; ix < upto; ix++) { - if (do_cfi_asm) - output_cfi_directive (cfi2); + cfi2 = VEC_index (dw_cfi_ref, vec, ix); + if (cfi2->dw_cfi_opc == DW_CFA_restore_state) + break; + else if (cfi2->dw_cfi_opc == DW_CFA_GNU_args_size) + args_size = cfi2; else - output_cfi (cfi2, fde, for_eh); + gcc_assert (cfi2->dw_cfi_opc != DW_CFA_remember_state); } + + if (cfi2 == NULL) + goto flush_all; + cfi_args_size = args_size; + break; } - if (cfi_cfa && cfi_cfa_offset && cfi_cfa_offset != cfi_cfa) - { - gcc_assert (cfi_cfa->dw_cfi_opc != DW_CFA_def_cfa_expression); - cfi_buf = *cfi_cfa; - switch (cfi_cfa_offset->dw_cfi_opc) - { - case DW_CFA_def_cfa_offset: - cfi_buf.dw_cfi_opc = DW_CFA_def_cfa; - cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd1; - break; - case DW_CFA_def_cfa_offset_sf: - cfi_buf.dw_cfi_opc = DW_CFA_def_cfa_sf; - cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd1; - break; - case DW_CFA_def_cfa: - case DW_CFA_def_cfa_sf: - cfi_buf.dw_cfi_opc = cfi_cfa_offset->dw_cfi_opc; - cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd2; - break; - default: - gcc_unreachable (); - } - cfi_cfa = &cfi_buf; - } - else if (cfi_cfa_offset) - cfi_cfa = cfi_cfa_offset; - if (cfi_cfa) - { - if (do_cfi_asm) - output_cfi_directive (cfi_cfa); - else - output_cfi (cfi_cfa, fde, for_eh); - } - cfi_cfa = NULL; - cfi_cfa_offset = NULL; - if (cfi_args_size - && cfi_args_size->dw_cfi_oprnd1.dw_cfi_offset) - { - if (do_cfi_asm) - output_cfi_directive (cfi_args_size); - else - output_cfi (cfi_args_size, fde, for_eh); - } - cfi_args_size = NULL; - if (cfi == NULL) - { - VEC_free (dw_cfi_ref, heap, regs); - return; - } - else if (do_cfi_asm) - output_cfi_directive (cfi); - else - output_cfi (cfi, fde, for_eh); - break; - default: - gcc_unreachable (); + case DW_CFA_GNU_args_size: + cfi_args_size = cfi; + break; + case DW_CFA_GNU_window_save: + goto flush_all; + case DW_CFA_offset: + case DW_CFA_offset_extended: + case DW_CFA_offset_extended_sf: + case DW_CFA_restore: + case DW_CFA_restore_extended: + case DW_CFA_undefined: + case DW_CFA_same_value: + case DW_CFA_register: + case DW_CFA_val_offset: + case DW_CFA_val_offset_sf: + case DW_CFA_expression: + case DW_CFA_val_expression: + case DW_CFA_GNU_negative_offset_extended: + if (VEC_length (dw_cfi_ref, regs) + <= cfi->dw_cfi_oprnd1.dw_cfi_reg_num) + VEC_safe_grow_cleared (dw_cfi_ref, heap, regs, + cfi->dw_cfi_oprnd1.dw_cfi_reg_num + 1); + VEC_replace (dw_cfi_ref, regs, cfi->dw_cfi_oprnd1.dw_cfi_reg_num, + cfi); + break; + case DW_CFA_def_cfa: + case DW_CFA_def_cfa_sf: + case DW_CFA_def_cfa_expression: + cfi_cfa = cfi; + cfi_cfa_offset = cfi; + break; + case DW_CFA_def_cfa_register: + cfi_cfa = cfi; + break; + case DW_CFA_def_cfa_offset: + case DW_CFA_def_cfa_offset_sf: + cfi_cfa_offset = cfi; + break; + case DW_CFA_nop: + gcc_assert (cfi == NULL); + flush_all: + len = VEC_length (dw_cfi_ref, regs); + for (idx = 0; idx < len; idx++) + { + cfi2 = VEC_replace (dw_cfi_ref, regs, idx, NULL); + if (cfi2 != NULL + && cfi2->dw_cfi_opc != DW_CFA_restore + && cfi2->dw_cfi_opc != DW_CFA_restore_extended) + { + if (do_cfi_asm) + output_cfi_directive (cfi2); + else + output_cfi (cfi2, fde, for_eh); + } + } + if (cfi_cfa && cfi_cfa_offset && cfi_cfa_offset != cfi_cfa) + { + gcc_assert (cfi_cfa->dw_cfi_opc != DW_CFA_def_cfa_expression); + cfi_buf = *cfi_cfa; + switch (cfi_cfa_offset->dw_cfi_opc) + { + case DW_CFA_def_cfa_offset: + cfi_buf.dw_cfi_opc = DW_CFA_def_cfa; + cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd1; + break; + case DW_CFA_def_cfa_offset_sf: + cfi_buf.dw_cfi_opc = DW_CFA_def_cfa_sf; + cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd1; + break; + case DW_CFA_def_cfa: + case DW_CFA_def_cfa_sf: + cfi_buf.dw_cfi_opc = cfi_cfa_offset->dw_cfi_opc; + cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd2; + break; + default: + gcc_unreachable (); + } + cfi_cfa = &cfi_buf; + } + else if (cfi_cfa_offset) + cfi_cfa = cfi_cfa_offset; + if (cfi_cfa) + { + if (do_cfi_asm) + output_cfi_directive (cfi_cfa); + else + output_cfi (cfi_cfa, fde, for_eh); + } + cfi_cfa = NULL; + cfi_cfa_offset = NULL; + if (cfi_args_size + && cfi_args_size->dw_cfi_oprnd1.dw_cfi_offset) + { + if (do_cfi_asm) + output_cfi_directive (cfi_args_size); + else + output_cfi (cfi_args_size, fde, for_eh); + } + cfi_args_size = NULL; + if (cfi == NULL) + { + VEC_free (dw_cfi_ref, heap, regs); + return; + } + else if (do_cfi_asm) + output_cfi_directive (cfi); + else + output_cfi (cfi, fde, for_eh); + break; + default: + gcc_unreachable (); + } } } +/* Like output_cfis, but emit all CFIs in the vector. */ +static void +output_all_cfis (cfi_vec vec, bool do_cfi_asm, + dw_fde_ref fde, bool for_eh) +{ + output_cfis (vec, VEC_length (dw_cfi_ref, vec), do_cfi_asm, fde, for_eh); +} + /* Output one FDE. */ static void @@ -3666,6 +3681,7 @@ output_fde (dw_fde_ref fde, bool for_eh, char *section_start_label, int fde_encoding, char *augmentation, bool any_lsda_needed, int lsda_encoding) { + int ix; const char *begin, *end; static unsigned int j; char l1[20], l2[20]; @@ -3773,31 +3789,31 @@ output_fde (dw_fde_ref fde, bool for_eh, this FDE. */ fde->dw_fde_current_label = begin; if (!fde->dw_fde_switched_sections) - for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next) + FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi) output_cfi (cfi, fde, for_eh); else if (!second) { - if (fde->dw_fde_switch_cfi) - for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next) + if (fde->dw_fde_switch_cfi_index) + FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi) { output_cfi (cfi, fde, for_eh); - if (cfi == fde->dw_fde_switch_cfi) + if (ix == fde->dw_fde_switch_cfi_index) break; } } else { - dw_cfi_ref cfi_next = fde->dw_fde_cfi; + int i, from = 0; + int until = VEC_length (dw_cfi_ref, fde->dw_fde_cfi); - if (fde->dw_fde_switch_cfi) + if (fde->dw_fde_switch_cfi_index > 0) { - cfi_next = fde->dw_fde_switch_cfi->dw_cfi_next; - fde->dw_fde_switch_cfi->dw_cfi_next = NULL; - output_cfis (fde->dw_fde_cfi, false, fde, for_eh); - fde->dw_fde_switch_cfi->dw_cfi_next = cfi_next; + from = fde->dw_fde_switch_cfi_index; + output_cfis (fde->dw_fde_cfi, from, false, fde, for_eh); } - for (cfi = cfi_next; cfi != NULL; cfi = cfi->dw_cfi_next) - output_cfi (cfi, fde, for_eh); + for (i = from; i < until; i++) + output_cfi (VEC_index (dw_cfi_ref, fde->dw_fde_cfi, i), + fde, for_eh); } /* If we are to emit a ref/link from function bodies to their frame tables, @@ -4033,7 +4049,7 @@ output_call_frame_info (int for_eh) eh_data_format_name (fde_encoding)); } - for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next) + FOR_EACH_VEC_ELT (dw_cfi_ref, cie_cfi_vec, i, cfi) output_cfi (cfi, NULL, for_eh); /* Pad the CIE out to an address sized boundary. */ @@ -4179,8 +4195,8 @@ dwarf2out_begin_prologue (unsigned int l fde->dw_fde_end = NULL; fde->dw_fde_vms_end_prologue = NULL; fde->dw_fde_vms_begin_epilogue = NULL; - fde->dw_fde_cfi = NULL; - fde->dw_fde_switch_cfi = NULL; + fde->dw_fde_cfi = VEC_alloc (dw_cfi_ref, gc, 20); + fde->dw_fde_switch_cfi_index = 0; fde->funcdef_number = current_function_funcdef_no; fde->all_throwers_are_sibcalls = crtl->all_throwers_are_sibcalls; fde->uses_eh_lsda = crtl->uses_eh_lsda; @@ -4385,18 +4401,10 @@ dwarf2out_switch_text_section (void) dwarf2out_do_cfi_startproc (true); /* As this is a different FDE, insert all current CFI instructions again. */ - output_cfis (fde->dw_fde_cfi, true, fde, true); + output_all_cfis (fde->dw_fde_cfi, true, fde, true); } else - { - dw_cfi_ref cfi = fde->dw_fde_cfi; - - cfi = fde->dw_fde_cfi; - if (cfi) - while (cfi->dw_cfi_next != NULL) - cfi = cfi->dw_cfi_next; - fde->dw_fde_switch_cfi = cfi; - } + fde->dw_fde_switch_cfi_index = VEC_length (dw_cfi_ref, fde->dw_fde_cfi); } /* And now, the subset of the debugging information support code necessary @@ -17258,6 +17266,7 @@ tree_add_const_value_attribute_for_decl static dw_loc_list_ref convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) { + int ix; dw_fde_ref fde; dw_loc_list_ref list, *list_tail; dw_cfi_ref cfi; @@ -17280,13 +17289,13 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_IN /* ??? Bald assumption that the CIE opcode list does not contain advance opcodes. */ - for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next) + FOR_EACH_VEC_ELT (dw_cfi_ref, cie_cfi_vec, ix, cfi) lookup_cfa_1 (cfi, &next_cfa, &remember); last_cfa = next_cfa; last_label = start_label; - for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next) + FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi) switch (cfi->dw_cfi_opc) { case DW_CFA_set_loc: Index: gcc/dwarf2out.c =================================================================== --- gcc.orig/dwarf2out.c +++ gcc/dwarf2out.c @@ -471,13 +471,14 @@ static void initial_return_save (rtx); static HOST_WIDE_INT stack_adjust_offset (const_rtx, HOST_WIDE_INT, HOST_WIDE_INT); static void output_cfi (dw_cfi_ref, dw_fde_ref, int); -static void output_cfi_directive (dw_cfi_ref); +static void output_cfi_directive (FILE *, dw_cfi_ref); static void output_call_frame_info (int); static void dwarf2out_note_section_used (void); static bool clobbers_queued_reg_save (const_rtx); static void dwarf2out_frame_debug_expr (rtx, const char *); -static void dwarf2out_cfi_begin_epilogue (rtx); -static void dwarf2out_frame_debug_restore_state (void); + +extern void dwarf2out_cfi_begin_epilogue (rtx); +extern void dwarf2out_frame_debug_restore_state (const char *); /* Support for complex CFA locations. */ static void output_cfa_loc (dw_cfi_ref, int); @@ -889,6 +890,17 @@ static bool emit_cfa_remember; /* True if any CFI directives were emitted at the current insn. */ static bool any_cfis_emitted; +static void +add_cfa_remember (const char *label) +{ + dw_cfi_ref cfi_remember; + + /* Emit the state save. */ + cfi_remember = new_cfi (); + cfi_remember->dw_cfi_opc = DW_CFA_remember_state; + add_fde_cfi (label, cfi_remember); +} + /* Add CFI to the current fde at the PC value indicated by LABEL if specified, or to the CIE if LABEL is NULL. */ @@ -904,13 +916,8 @@ add_fde_cfi (const char *label, dw_cfi_r if (emit_cfa_remember) { - dw_cfi_ref cfi_remember; - - /* Emit the state save. */ emit_cfa_remember = false; - cfi_remember = new_cfi (); - cfi_remember->dw_cfi_opc = DW_CFA_remember_state; - add_fde_cfi (label, cfi_remember); + add_cfa_remember (label); } if (dwarf2out_do_cfi_asm ()) @@ -1436,7 +1443,7 @@ stack_adjust_offset (const_rtx pattern, return offset; } - +#if 0 /* Precomputed args_size for CODE_LABELs and BARRIERs preceeding them, indexed by INSN_UID. */ @@ -1541,7 +1548,11 @@ compute_barrier_args_size (void) cur_args_size = barrier_args_size[INSN_UID (insn)]; prev = prev_nonnote_insn (insn); if (prev && BARRIER_P (prev)) - barrier_args_size[INSN_UID (prev)] = cur_args_size; + { + gcc_assert (LABEL_P (insn)); + barrier_args_size[INSN_UID (prev)] = cur_args_size; + barrier_args_size[INSN_UID (insn)] = cur_args_size; + } for (; insn; insn = NEXT_INSN (insn)) { @@ -1609,6 +1620,7 @@ compute_barrier_args_size (void) VEC_free (rtx, heap, worklist); VEC_free (rtx, heap, next); } +#endif /* Add a CFI to update the running total of the size of arguments pushed onto the stack. */ @@ -1707,25 +1719,7 @@ dwarf2out_notice_stack_adjust (rtx insn, return; } else if (BARRIER_P (insn)) - { - /* Don't call compute_barrier_args_size () if the only - BARRIER is at the end of function. */ - if (barrier_args_size == NULL && next_nonnote_insn (insn)) - compute_barrier_args_size (); - if (barrier_args_size == NULL) - offset = 0; - else - { - offset = barrier_args_size[INSN_UID (insn)]; - if (offset < 0) - offset = 0; - } - - offset -= args_size; -#ifndef STACK_GROWS_DOWNWARD - offset = -offset; -#endif - } + return; else if (GET_CODE (PATTERN (insn)) == SET) offset = stack_adjust_offset (PATTERN (insn), args_size, 0); else if (GET_CODE (PATTERN (insn)) == PARALLEL @@ -2921,11 +2915,102 @@ dwarf2out_frame_debug (rtx insn, bool af dwarf2out_flush_queued_reg_saves (); } +typedef struct +{ + cfi_vec cfis; + dw_cfa_location cfa, cfa_store; + bool visited; + bool used_as_start; + int args_size; +} jump_target_info; + +static void +maybe_record_jump_target (rtx label, VEC (rtx, heap) **worklist, + int *uid_luid, jump_target_info *info) +{ + dw_fde_ref fde = current_fde (); + int uid; + + if (GET_CODE (label) == LABEL_REF) + label = XEXP (label, 0); + gcc_assert (LABEL_P (label)); + uid = INSN_UID (label); + info += uid_luid[uid]; + if (info->visited || info->cfis) + return; + + if (dump_file) + fprintf (dump_file, "recording label %d as possible jump target\n", uid); + + VEC_safe_push (rtx, heap, *worklist, label); + info->cfis = VEC_copy (dw_cfi_ref, gc, fde->dw_fde_cfi); + info->args_size = args_size; + info->cfa = cfa; + info->cfa_store = cfa_store; +} + +static bool +vec_is_prefix_of (cfi_vec vec1, cfi_vec vec2) +{ + int i; + int len1 = VEC_length (dw_cfi_ref, vec1); + int len2 = VEC_length (dw_cfi_ref, vec2); + if (len1 > len2) + return false; + for (i = 0; i < len1; i++) + if (VEC_index (dw_cfi_ref, vec1, i) != VEC_index (dw_cfi_ref, vec1, i)) + return false; + return true; +} + +static void +append_extra_cfis (dw_fde_ref fde, cfi_vec prefix, cfi_vec full, const char *label) +{ + int i; + int len = VEC_length (dw_cfi_ref, full); + int prefix_len = VEC_length (dw_cfi_ref, prefix); + for (i = 0; i < len; i++) + { + dw_cfi_ref elt = VEC_index (dw_cfi_ref, full, i); + if (i < prefix_len) + gcc_assert (elt == VEC_index (dw_cfi_ref, prefix, i)); + else + { + if (label) + { + dw_cfi_ref cfi2 = new_cfi (); + *cfi2 = *elt; + add_fde_cfi (label, cfi2); + } + else + VEC_safe_push (dw_cfi_ref, gc, fde->dw_fde_cfi, elt); + } + } +} + +extern void debug_cfi_vec (FILE *, cfi_vec v); +void debug_cfi_vec (FILE *f, cfi_vec v) +{ + int ix; + dw_cfi_ref cfi; + + FOR_EACH_VEC_ELT (dw_cfi_ref, v, ix, cfi) + output_cfi_directive (f, cfi); +} + void dwarf2out_frame_debug_init (void) { - size_t i; + int max_uid = get_max_uid (); + size_t j; + int i; rtx insn; + VEC (rtx, heap) *worklist; + cfi_vec incoming_cfis; + int n_points; + int *uid_luid; + jump_target_info *point_info; + dw_fde_ref fde = current_fde (); /* Flush any queued register saves. */ dwarf2out_flush_queued_reg_saves (); @@ -2940,70 +3025,249 @@ dwarf2out_frame_debug_init (void) cfa_temp.reg = -1; cfa_temp.offset = 0; - for (i = 0; i < num_regs_saved_in_regs; i++) + for (j = 0; j < num_regs_saved_in_regs; j++) { - regs_saved_in_regs[i].orig_reg = NULL_RTX; - regs_saved_in_regs[i].saved_in_reg = NULL_RTX; + regs_saved_in_regs[j].orig_reg = NULL_RTX; + regs_saved_in_regs[j].saved_in_reg = NULL_RTX; } num_regs_saved_in_regs = 0; - +#if 0 if (barrier_args_size) { XDELETEVEC (barrier_args_size); barrier_args_size = NULL; } - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) +#endif + + n_points = 0; + for (insn = get_insns (); insn != NULL_RTX; insn = NEXT_INSN (insn)) + if (LABEL_P (insn) || BARRIER_P (insn)) + n_points++; + uid_luid = XCNEWVEC (int, max_uid); + n_points = 0; + for (insn = get_insns (); insn != NULL_RTX; insn = NEXT_INSN (insn)) + if (LABEL_P (insn) || BARRIER_P (insn)) + uid_luid[INSN_UID (insn)] = n_points++; + + point_info = XCNEWVEC (jump_target_info, n_points); + for (i = 0; i < n_points; i++) + point_info[i].args_size = -1; + + worklist = VEC_alloc (rtx, heap, 20); + insn = get_insns (); + incoming_cfis = VEC_copy (dw_cfi_ref, gc, fde->dw_fde_cfi); + + args_size = old_args_size = 0; + + for (;;) { - rtx pat; - if (BARRIER_P (insn)) - { - dwarf2out_frame_debug (insn, false); - continue; - } - else if (NOTE_P (insn)) - { - switch (NOTE_KIND (insn)) + HOST_WIDE_INT offset; + rtx new_insn, best, next; + bool best_has_barrier; + jump_target_info *restart_info; + + for (; insn != NULL_RTX; insn = next) + { + int uid = INSN_UID (insn); + rtx pat, note; + + next = NEXT_INSN (insn); + if (LABEL_P (insn) || BARRIER_P (insn)) + { + int luid = uid_luid[uid]; + jump_target_info *info = point_info + luid; + if (info->used_as_start) + { + if (dump_file) + fprintf (dump_file, + "Stopping scan at insn %d; previously reached\n", + uid); + break; + } + info->visited = true; + if (BARRIER_P (insn)) + { + dwarf2out_frame_debug (insn, false); + gcc_assert (info->cfis == NULL); + info->cfis = fde->dw_fde_cfi; + if (dump_file) + { + fprintf (dump_file, "Stopping scan at barrier %d\n", uid); + if (dump_flags & TDF_DETAILS) + debug_cfi_vec (dump_file, fde->dw_fde_cfi); + } + break; + } + } + if (!NONDEBUG_INSN_P (insn)) + continue; + pat = PATTERN (insn); + if (asm_noperands (pat) >= 0) + continue; + if (GET_CODE (pat) == SEQUENCE) { - case NOTE_INSN_EPILOGUE_BEG: -#if defined (HAVE_epilogue) - dwarf2out_cfi_begin_epilogue (insn); + for (i = 1; i < XVECLEN (pat, 0); i++) + dwarf2out_frame_debug (XVECEXP (pat, 0, i), false); + insn = XVECEXP (pat, 0, 0); + } + + if (CALL_P (insn) && dwarf2out_do_frame ()) + dwarf2out_frame_debug (insn, false); + if (dwarf2out_do_frame () +#if !defined (HAVE_prologue) + && !ACCUMULATE_OUTGOING_ARGS #endif - break; - case NOTE_INSN_CFA_RESTORE_STATE: - cfi_insn = insn; - dwarf2out_frame_debug_restore_state (); - break; + ) + dwarf2out_frame_debug (insn, true); + if (JUMP_P (insn)) + { + rtx label = JUMP_LABEL (insn); + if (label) + { + rtx next = next_real_insn (label); + if (next && JUMP_P (next) + && (GET_CODE (PATTERN (next)) == ADDR_VEC + || GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC)) + { + rtx pat = PATTERN (next); + int eltnum = GET_CODE (pat) == ADDR_DIFF_VEC ? 1 : 0; + + for (i = 0; i < XVECLEN (pat, eltnum); i++) + maybe_record_jump_target (XVECEXP (pat, eltnum, i), + &worklist, uid_luid, + point_info); + } + else + maybe_record_jump_target (label, &worklist, uid_luid, + point_info); + } + } + note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); + if (note) + { + eh_landing_pad lp; + + lp = get_eh_landing_pad_from_rtx (insn); + if (lp) + maybe_record_jump_target (lp->landing_pad, &worklist, + uid_luid, point_info); } - continue; } - if (!NONDEBUG_INSN_P (insn)) - continue; - pat = PATTERN (insn); - if (asm_noperands (pat) >= 0) - continue; - if (GET_CODE (pat) == SEQUENCE) + best = NULL_RTX; + best_has_barrier = false; + FOR_EACH_VEC_ELT (rtx, worklist, i, new_insn) { - int j; - for (j = 1; j < XVECLEN (pat, 0); j++) - dwarf2out_frame_debug (XVECEXP (pat, 0, j), false); - insn = XVECEXP (pat, 0, 0); + rtx prev; + bool this_has_barrier; + restart_info = point_info + uid_luid[INSN_UID (new_insn)]; + if (restart_info->visited) + continue; + prev = prev_nonnote_nondebug_insn (new_insn); + this_has_barrier = prev && BARRIER_P (prev); + if (best == NULL_RTX + || prev == insn + || (!best_has_barrier && this_has_barrier)) + { + best = new_insn; + best_has_barrier = this_has_barrier; + } } + if (best == NULL_RTX) + break; + if (dump_file) + fprintf (dump_file, "restarting scan at label %d", INSN_UID (best)); + restart_info = point_info + uid_luid[INSN_UID (best)]; + restart_info->used_as_start = true; + insn = best; + gcc_assert (LABEL_P (insn)); + fde->dw_fde_cfi = VEC_copy (dw_cfi_ref, gc, restart_info->cfis); + cfa = restart_info->cfa; + cfa_store = restart_info->cfa_store; + offset = restart_info->args_size; + if (offset >= 0) + { + const char *label; + + if (dump_file && offset != args_size) + fprintf (dump_file, ", args_size " HOST_WIDE_INT_PRINT_DEC + " -> " HOST_WIDE_INT_PRINT_DEC, + args_size, offset); - if (CALL_P (insn) && dwarf2out_do_frame ()) - dwarf2out_frame_debug (insn, false); - if (dwarf2out_do_frame () -#if !defined (HAVE_prologue) - && !ACCUMULATE_OUTGOING_ARGS + offset -= args_size; +#ifndef STACK_GROWS_DOWNWARD + offset = -offset; #endif - ) - dwarf2out_frame_debug (insn, true); + label = dwarf2out_cfi_label (false); + cfi_insn = prev_nonnote_nondebug_insn (insn); + dwarf2out_stack_adjust (offset, label); + } + if (dump_file) + { + fprintf (dump_file, "\n"); + if (dump_flags & TDF_DETAILS) + debug_cfi_vec (dump_file, fde->dw_fde_cfi); + } + + restart_info->visited = true; + insn = NEXT_INSN (insn); + } + + /* Now splice the various CFI fragments together into a coherent whole. */ + fde->dw_fde_cfi = VEC_alloc (dw_cfi_ref, gc, 20); + insn = get_insns (); + while (!NOTE_P (insn) && NOTE_KIND (insn) != NOTE_INSN_FUNCTION_BEG) + insn = NEXT_INSN (insn); + cfi_insn = insn; + add_cfa_remember (dwarf2out_cfi_label (false)); + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (BARRIER_P (insn)) + { + cfi_vec new_cfi_vec; + jump_target_info *info = point_info + uid_luid[INSN_UID (insn)]; + cfi_vec barrier_cfi = info->cfis; + const char *label = dwarf2out_cfi_label (false); + + append_extra_cfis (fde, incoming_cfis, barrier_cfi, NULL); + + /* Find the start of the next sequence we processed. */ + do + { + if (LABEL_P (insn)) + { + info = point_info + uid_luid[INSN_UID (insn)]; + if (info->used_as_start) + break; + } + insn = NEXT_INSN (insn); + } + while (insn != NULL_RTX); + if (insn == NULL_RTX) + break; + + /* Emit extra CFIs as necessary to achieve the correct state. */ + gcc_assert (LABEL_P (insn)); + new_cfi_vec = info->cfis; + cfi_insn = insn; + if (vec_is_prefix_of (barrier_cfi, new_cfi_vec)) + append_extra_cfis (fde, barrier_cfi, new_cfi_vec, label); + else + { + dwarf2out_frame_debug_restore_state (label); + add_cfa_remember (label); + + append_extra_cfis (fde, NULL, new_cfi_vec, label); + } + incoming_cfis = new_cfi_vec; + } } } void dwarf2out_emit_cfi (dw_cfi_ref cfi) { - output_cfi_directive (cfi); + output_cfi_directive (asm_out_file, cfi); } /* Determine if we need to save and restore CFI information around @@ -3091,17 +3355,12 @@ dwarf2out_cfi_begin_epilogue (rtx insn) required. */ void -dwarf2out_frame_debug_restore_state (void) +dwarf2out_frame_debug_restore_state (const char *label) { dw_cfi_ref cfi = new_cfi (); - const char *label = dwarf2out_cfi_label (false); cfi->dw_cfi_opc = DW_CFA_restore_state; add_fde_cfi (label, cfi); - - gcc_assert (cfa_remember.in_use); - cfa = cfa_remember; - cfa_remember.in_use = 0; } /* Describe for the GTY machinery what parts of dw_cfi_oprnd1 are used. */ @@ -3401,7 +3660,7 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref f /* Similar, but do it via assembler directives instead. */ static void -output_cfi_directive (dw_cfi_ref cfi) +output_cfi_directive (FILE *f, dw_cfi_ref cfi) { unsigned long r, r2; @@ -3422,76 +3681,76 @@ output_cfi_directive (dw_cfi_ref cfi) case DW_CFA_offset_extended: case DW_CFA_offset_extended_sf: r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); - fprintf (asm_out_file, "\t.cfi_offset %lu, "HOST_WIDE_INT_PRINT_DEC"\n", + fprintf (f, "\t.cfi_offset %lu, "HOST_WIDE_INT_PRINT_DEC"\n", r, cfi->dw_cfi_oprnd2.dw_cfi_offset); break; case DW_CFA_restore: case DW_CFA_restore_extended: r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); - fprintf (asm_out_file, "\t.cfi_restore %lu\n", r); + fprintf (f, "\t.cfi_restore %lu\n", r); break; case DW_CFA_undefined: r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); - fprintf (asm_out_file, "\t.cfi_undefined %lu\n", r); + fprintf (f, "\t.cfi_undefined %lu\n", r); break; case DW_CFA_same_value: r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); - fprintf (asm_out_file, "\t.cfi_same_value %lu\n", r); + fprintf (f, "\t.cfi_same_value %lu\n", r); break; case DW_CFA_def_cfa: case DW_CFA_def_cfa_sf: r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); - fprintf (asm_out_file, "\t.cfi_def_cfa %lu, "HOST_WIDE_INT_PRINT_DEC"\n", + fprintf (f, "\t.cfi_def_cfa %lu, "HOST_WIDE_INT_PRINT_DEC"\n", r, cfi->dw_cfi_oprnd2.dw_cfi_offset); break; case DW_CFA_def_cfa_register: r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); - fprintf (asm_out_file, "\t.cfi_def_cfa_register %lu\n", r); + fprintf (f, "\t.cfi_def_cfa_register %lu\n", r); break; case DW_CFA_register: r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); r2 = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd2.dw_cfi_reg_num, 1); - fprintf (asm_out_file, "\t.cfi_register %lu, %lu\n", r, r2); + fprintf (f, "\t.cfi_register %lu, %lu\n", r, r2); break; case DW_CFA_def_cfa_offset: case DW_CFA_def_cfa_offset_sf: - fprintf (asm_out_file, "\t.cfi_def_cfa_offset " + fprintf (f, "\t.cfi_def_cfa_offset " HOST_WIDE_INT_PRINT_DEC"\n", cfi->dw_cfi_oprnd1.dw_cfi_offset); break; case DW_CFA_remember_state: - fprintf (asm_out_file, "\t.cfi_remember_state\n"); + fprintf (f, "\t.cfi_remember_state\n"); break; case DW_CFA_restore_state: - fprintf (asm_out_file, "\t.cfi_restore_state\n"); + fprintf (f, "\t.cfi_restore_state\n"); break; case DW_CFA_GNU_args_size: - fprintf (asm_out_file, "\t.cfi_escape %#x,", DW_CFA_GNU_args_size); + fprintf (f, "\t.cfi_escape %#x,", DW_CFA_GNU_args_size); dw2_asm_output_data_uleb128_raw (cfi->dw_cfi_oprnd1.dw_cfi_offset); if (flag_debug_asm) - fprintf (asm_out_file, "\t%s args_size "HOST_WIDE_INT_PRINT_DEC, + fprintf (f, "\t%s args_size "HOST_WIDE_INT_PRINT_DEC, ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset); - fputc ('\n', asm_out_file); + fputc ('\n', f); break; case DW_CFA_GNU_window_save: - fprintf (asm_out_file, "\t.cfi_window_save\n"); + fprintf (f, "\t.cfi_window_save\n"); break; case DW_CFA_def_cfa_expression: case DW_CFA_expression: - fprintf (asm_out_file, "\t.cfi_escape %#x,", cfi->dw_cfi_opc); + fprintf (f, "\t.cfi_escape %#x,", cfi->dw_cfi_opc); output_cfa_loc_raw (cfi); - fputc ('\n', asm_out_file); + fputc ('\n', f); break; default: @@ -3601,7 +3860,7 @@ output_cfis (cfi_vec vec, int upto, bool && cfi2->dw_cfi_opc != DW_CFA_restore_extended) { if (do_cfi_asm) - output_cfi_directive (cfi2); + output_cfi_directive (asm_out_file, cfi2); else output_cfi (cfi2, fde, for_eh); } @@ -3635,7 +3894,7 @@ output_cfis (cfi_vec vec, int upto, bool if (cfi_cfa) { if (do_cfi_asm) - output_cfi_directive (cfi_cfa); + output_cfi_directive (asm_out_file, cfi_cfa); else output_cfi (cfi_cfa, fde, for_eh); } @@ -3645,7 +3904,7 @@ output_cfis (cfi_vec vec, int upto, bool && cfi_args_size->dw_cfi_oprnd1.dw_cfi_offset) { if (do_cfi_asm) - output_cfi_directive (cfi_args_size); + output_cfi_directive (asm_out_file, cfi_args_size); else output_cfi (cfi_args_size, fde, for_eh); } @@ -3656,7 +3915,7 @@ output_cfis (cfi_vec vec, int upto, bool return; } else if (do_cfi_asm) - output_cfi_directive (cfi); + output_cfi_directive (asm_out_file, cfi); else output_cfi (cfi, fde, for_eh); break; Index: gcc/dwarf2out.c =================================================================== --- gcc.orig/dwarf2out.c +++ gcc/dwarf2out.c @@ -2790,38 +2790,6 @@ dwarf2out_frame_debug (rtx insn, bool af rtx note, n; bool handled_one = false; - if (insn == NULL_RTX) - { - size_t i; - - /* Flush any queued register saves. */ - dwarf2out_flush_queued_reg_saves (); - - /* Set up state for generating call frame debug info. */ - lookup_cfa (&cfa); - gcc_assert (cfa.reg - == (unsigned long)DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM)); - - cfa.reg = STACK_POINTER_REGNUM; - cfa_store = cfa; - cfa_temp.reg = -1; - cfa_temp.offset = 0; - - for (i = 0; i < num_regs_saved_in_regs; i++) - { - regs_saved_in_regs[i].orig_reg = NULL_RTX; - regs_saved_in_regs[i].saved_in_reg = NULL_RTX; - } - num_regs_saved_in_regs = 0; - - if (barrier_args_size) - { - XDELETEVEC (barrier_args_size); - barrier_args_size = NULL; - } - return; - } - if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn)) dwarf2out_flush_queued_reg_saves (); @@ -2939,6 +2907,38 @@ dwarf2out_frame_debug (rtx insn, bool af dwarf2out_flush_queued_reg_saves (); } +void +dwarf2out_frame_debug_init (void) +{ + size_t i; + + /* Flush any queued register saves. */ + dwarf2out_flush_queued_reg_saves (); + + /* Set up state for generating call frame debug info. */ + lookup_cfa (&cfa); + gcc_assert (cfa.reg + == (unsigned long)DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM)); + + cfa.reg = STACK_POINTER_REGNUM; + cfa_store = cfa; + cfa_temp.reg = -1; + cfa_temp.offset = 0; + + for (i = 0; i < num_regs_saved_in_regs; i++) + { + regs_saved_in_regs[i].orig_reg = NULL_RTX; + regs_saved_in_regs[i].saved_in_reg = NULL_RTX; + } + num_regs_saved_in_regs = 0; + + if (barrier_args_size) + { + XDELETEVEC (barrier_args_size); + barrier_args_size = NULL; + } +} + /* Determine if we need to save and restore CFI information around this epilogue. If SIBCALL is true, then this is a sibcall epilogue. If we do need to save/restore, then emit the save now, and insert a Index: gcc/dwarf2out.h =================================================================== --- gcc.orig/dwarf2out.h +++ gcc/dwarf2out.h @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. extern void dwarf2out_decl (tree); extern void dwarf2out_frame_debug (rtx, bool); +extern void dwarf2out_frame_debug_init (void); extern void dwarf2out_cfi_begin_epilogue (rtx); extern void dwarf2out_frame_debug_restore_state (void); extern void dwarf2out_flush_queued_reg_saves (void); Index: gcc/final.c =================================================================== --- gcc.orig/final.c +++ gcc/final.c @@ -1561,7 +1561,7 @@ final_start_function (rtx first ATTRIBUT #if defined (HAVE_prologue) if (dwarf2out_do_frame ()) - dwarf2out_frame_debug (NULL_RTX, false); + dwarf2out_frame_debug_init (); #endif /* If debugging, assign block numbers to all of the blocks in this