On 03/31/2011 11:28 PM, Richard Henderson wrote: >> Rather than use a CFG, I've tried to do something similar to >> compute_barrier_args_size, using JUMP_LABELs etc. > > A reasonable solution for now, I suppose.
Ok, sounds like you haven't discovered a fatal flaw; I'll keep hacking on it. >> Summary of the patches: >> 001 - just create a dwarf2out_frame_debug_init function. > > Ok. > >> 003 - Store dw_cfi_refs in VECs rather than linked lists. Looks >> larger than it is due to reindentation > > Like 001, this one looks like it's totally independent of and of > the other changes, and a good cleanup. Please go ahead and test > and commit this one independently. Will do. >> 002 - Make it walk the function in a first pass and record CFIs to >> be output later > > Do I correctly understand that NOTE_INSN_CFI isn't actually being > used in this patch? No, it's used - but it looks like I forgot to quilt refresh and the final.c changes weren't included. New patch below. After this patch, the whole function is processed before final, and rather than emitting cfi directives immediately, we create these notes which cause the directives to be emitted during final. This probably shouldn't be committed separately when these changes go in, as (I think) it breaks -freorder-blocks-and-partition as well as the code in i386.c; it's split out simply to show an intermediate stage. >> 004 - Change the function walk introduced in 002 so that it records >> and restores state when reaching jumps/barriers > > I'm not too fond of vec_is_prefix_of. The Problem is that you're > not applying any understanding of the actual data, just doing a > string comparison (effectively). Yes, this falls under "inefficient CFI insns". I wanted to post a preliminary proof-of-concept patch set now which generates correct(-looking) output, but not necessarily optimized output. Not quite sure yet how to tackle this but I'll think of something. 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 <http://www.gnu.org/licenses/>. */ +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/final.c =================================================================== --- gcc.orig/final.c +++ gcc/final.c @@ -1899,16 +1899,15 @@ final_scan_insn (rtx insn, FILE *file, i break; case NOTE_INSN_EPILOGUE_BEG: -#if defined (HAVE_epilogue) - if (dwarf2out_do_frame ()) - dwarf2out_cfi_begin_epilogue (insn); -#endif (*debug_hooks->begin_epilogue) (last_linenum, last_filename); targetm.asm_out.function_begin_epilogue (file); break; case NOTE_INSN_CFA_RESTORE_STATE: - dwarf2out_frame_debug_restore_state (); + break; + + case NOTE_INSN_CFI: + dwarf2out_emit_cfi (NOTE_CFI (insn)); break; case NOTE_INSN_FUNCTION_BEG: @@ -2018,8 +2017,6 @@ final_scan_insn (rtx insn, FILE *file, i break; case BARRIER: - if (dwarf2out_do_frame ()) - dwarf2out_frame_debug (insn, false); break; case CODE_LABEL: @@ -2285,12 +2282,6 @@ final_scan_insn (rtx insn, FILE *file, i final_sequence = body; - /* Record the delay slots' frame information before the branch. - This is needed for delayed calls: see execute_cfa_program(). */ - if (dwarf2out_do_frame ()) - for (i = 1; i < XVECLEN (body, 0); i++) - dwarf2out_frame_debug (XVECEXP (body, 0, i), false); - /* The first insn in this SEQUENCE might be a JUMP_INSN that will force the restoration of a comparison that was previously thought unnecessary. If that happens, cancel this sequence @@ -2604,9 +2595,6 @@ final_scan_insn (rtx insn, FILE *file, i current_output_insn = debug_insn = insn; - if (CALL_P (insn) && dwarf2out_do_frame ()) - dwarf2out_frame_debug (insn, false); - /* Find the proper template for this insn. */ templ = get_insn_template (insn_code_number, insn); @@ -2686,16 +2674,6 @@ final_scan_insn (rtx insn, FILE *file, i targetm.asm_out.final_postscan_insn (file, insn, recog_data.operand, recog_data.n_operands); - /* If necessary, report the effect that the instruction has on - the unwind info. We've already done this for delay slots - and call instructions. */ - if (final_sequence == 0 -#if !defined (HAVE_prologue) - && !ACCUMULATE_OUTGOING_ARGS -#endif - && dwarf2out_do_frame ()) - dwarf2out_frame_debug (insn, true); - if (!targetm.asm_out.unwind_emit_before_insn && targetm.asm_out.unwind_emit) targetm.asm_out.unwind_emit (asm_out_file, insn);