From: Richard Henderson Date: Fri, 5 Aug 2011 16:17:46 +0000 (-0700) Subject: re PR rtl-optimization/49977 (CFI notes are missed for delayed slot) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=eebc8f373b5c761dd9d92ff01cb4b6132dbb9081;p=gcc.git re PR rtl-optimization/49977 (CFI notes are missed for delayed slot) PR rtl-opt/49977 * dwarf2cfi.c (scan_insn_after): Split out of ... (scan_trace): ... here. Correctly place notes wrt sequences. From-SVN: r177466 --- diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c index f6ab38d4b2c..80cce3209fc 100644 --- a/gcc/dwarf2cfi.c +++ b/gcc/dwarf2cfi.c @@ -2355,13 +2355,23 @@ create_trace_edges (rtx insn) } } +/* A subroutine of scan_trace. Do what needs to be done "after" INSN. */ + +static void +scan_insn_after (rtx insn) +{ + if (RTX_FRAME_RELATED_P (insn)) + dwarf2out_frame_debug (insn); + notice_args_size (insn); +} + /* Scan the trace beginning at INSN and create the CFI notes for the instructions therein. */ static void scan_trace (dw_trace_info *trace) { - rtx insn = trace->head; + rtx prev, insn = trace->head; dw_cfa_location this_cfa; if (dump_file) @@ -2378,10 +2388,14 @@ scan_trace (dw_trace_info *trace) this_cfa = cur_row->cfa; cur_cfa = &this_cfa; - for (insn = NEXT_INSN (insn); insn ; insn = NEXT_INSN (insn)) + for (prev = insn, insn = NEXT_INSN (insn); + insn; + prev = insn, insn = NEXT_INSN (insn)) { + rtx control; + /* Do everything that happens "before" the insn. */ - add_cfi_insn = PREV_INSN (insn); + add_cfi_insn = prev; /* Notice the end of a trace. */ if (BARRIER_P (insn)) @@ -2401,34 +2415,25 @@ scan_trace (dw_trace_info *trace) if (DEBUG_INSN_P (insn) || !inside_basic_block_p (insn)) continue; - /* Flush data before calls and jumps, and of course if necessary. */ - if (can_throw_internal (insn)) - { - dwarf2out_flush_queued_reg_saves (); - notice_eh_throw (insn); - } - else if (!NONJUMP_INSN_P (insn) - || clobbers_queued_reg_save (insn) - || find_reg_note (insn, REG_CFA_FLUSH_QUEUE, NULL)) - dwarf2out_flush_queued_reg_saves (); - - /* Do everything that happens "after" the insn. */ - add_cfi_insn = insn; - - /* Handle changes to the row state. */ - if (RTX_FRAME_RELATED_P (insn)) - dwarf2out_frame_debug (insn); - - /* Look for REG_ARGS_SIZE, and handle it. */ + /* Handle all changes to the row state. Sequences require special + handling for the positioning of the notes. */ if (GET_CODE (PATTERN (insn)) == SEQUENCE) { rtx elt, pat = PATTERN (insn); int i, n = XVECLEN (pat, 0); - if (INSN_ANNULLED_BRANCH_P (XVECEXP (pat, 0, 0))) + control = XVECEXP (pat, 0, 0); + if (can_throw_internal (control)) + notice_eh_throw (control); + dwarf2out_flush_queued_reg_saves (); + + if (INSN_ANNULLED_BRANCH_P (control)) { /* ??? Hopefully multiple delay slots are not annulled. */ gcc_assert (n == 2); + gcc_assert (!RTX_FRAME_RELATED_P (control)); + gcc_assert (!find_reg_note (control, REG_ARGS_SIZE, NULL)); + elt = XVECEXP (pat, 0, 1); /* If ELT is an instruction from target of an annulled branch, @@ -2438,11 +2443,16 @@ scan_trace (dw_trace_info *trace) { HOST_WIDE_INT restore_args_size; + add_cfi_insn = NULL; restore_args_size = cur_trace->end_true_args_size; cur_cfa = &cur_row->cfa; - notice_args_size (elt); - create_trace_edges (insn); + scan_insn_after (elt); + + /* ??? Should we instead save the entire row state? */ + gcc_assert (!VEC_length (queued_reg_save, queued_reg_saves)); + + create_trace_edges (control); cur_trace->end_true_args_size = restore_args_size; cur_row->cfa = this_cfa; @@ -2451,14 +2461,48 @@ scan_trace (dw_trace_info *trace) } } + /* The insns in the delay slot should all be considered to happen + "before" a call insn. Consider a call with a stack pointer + adjustment in the delay slot. The backtrace from the callee + should include the sp adjustment. Unfortunately, that leaves + us with an unavoidable unwinding error exactly at the call insn + itself. For jump insns we'd prefer to avoid this error by + placing the notes after the sequence. */ + if (JUMP_P (control)) + add_cfi_insn = insn; + for (i = 1; i < n; ++i) { elt = XVECEXP (pat, 0, i); - notice_args_size (elt); + scan_insn_after (elt); } + + /* Make sure any register saves are visible at the jump target. */ + dwarf2out_flush_queued_reg_saves (); + + /* However, if there is some adjustment on the call itself, e.g. + a call_pop, that action should be considered to happen after + the call returns. */ + add_cfi_insn = insn; + scan_insn_after (control); } else - notice_args_size (insn); + { + /* Flush data before calls and jumps, and of course if necessary. */ + if (can_throw_internal (insn)) + { + notice_eh_throw (insn); + dwarf2out_flush_queued_reg_saves (); + } + else if (!NONJUMP_INSN_P (insn) + || clobbers_queued_reg_save (insn) + || find_reg_note (insn, REG_CFA_FLUSH_QUEUE, NULL)) + dwarf2out_flush_queued_reg_saves (); + + add_cfi_insn = insn; + scan_insn_after (insn); + control = insn; + } /* Between frame-related-p and args_size we might have otherwise emitted two cfa adjustments. Do it now. */ @@ -2468,7 +2512,7 @@ scan_trace (dw_trace_info *trace) same tests as are done to actually create the edges. So always call the routine and let it not create edges for non-control-flow insns. */ - create_trace_edges (insn); + create_trace_edges (control); } add_cfi_insn = NULL;