From patchwork Fri Aug 5 02:28:28 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 108600 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 255F3B6F65 for ; Fri, 5 Aug 2011 12:28:49 +1000 (EST) Received: (qmail 1544 invoked by alias); 5 Aug 2011 02:28:47 -0000 Received: (qmail 1532 invoked by uid 22791); 5 Aug 2011 02:28:46 -0000 X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW X-Spam-Check-By: sourceware.org Received: from mail-iy0-f175.google.com (HELO mail-iy0-f175.google.com) (209.85.210.175) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 05 Aug 2011 02:28:31 +0000 Received: by iyn15 with SMTP id 15so2350843iyn.34 for ; Thu, 04 Aug 2011 19:28:30 -0700 (PDT) Received: by 10.42.28.2 with SMTP id l2mr1511105icc.57.1312511310791; Thu, 04 Aug 2011 19:28:30 -0700 (PDT) Received: from pebble.twiddle.home (c-71-227-161-214.hsd1.wa.comcast.net [71.227.161.214]) by mx.google.com with ESMTPS id w9sm1657395ibc.39.2011.08.04.19.28.29 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 04 Aug 2011 19:28:30 -0700 (PDT) Message-ID: <4E3B554C.7020902@twiddle.net> Date: Thu, 04 Aug 2011 19:28:28 -0700 From: Richard Henderson User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.18) Gecko/20110621 Fedora/3.1.11-1.fc14 Thunderbird/3.1.11 MIME-Version: 1.0 To: GCC Patches Subject: [CFT, delay slots] Fix middle-end/49977 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 This seems to do the trick for sim testing of sh-elf and cris-elf. I'm interested in advice re debugging experiences with delay slots. It seems like for calls there's no alternative but to have the unwind info be incorrect when stopped at the call insn itself. It also seems like we've similarly been generating unwind info that was incorrect for branches with frame-related insns in delay slots. Further, that by delaying the unwind info until after the sequence we can avoid that incorrectness. Have any of you experienced that incorrectness before, when debugging on your respective targets? r~ diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c index f6ab38d..80cce32 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;