From patchwork Mon Jul 25 22:46:32 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 106759 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 9D4B9B7091 for ; Tue, 26 Jul 2011 08:46:54 +1000 (EST) Received: (qmail 23369 invoked by alias); 25 Jul 2011 22:46:52 -0000 Received: (qmail 23359 invoked by uid 22791); 25 Jul 2011 22:46:51 -0000 X-SWARE-Spam-Status: No, hits=-6.9 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SPF_HELO_PASS 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; Mon, 25 Jul 2011 22:46:33 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p6PMkXgX031183 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 25 Jul 2011 18:46:33 -0400 Received: from anchor.twiddle.net (vpn-227-66.phx2.redhat.com [10.3.227.66]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p6PMkWFi009106 for ; Mon, 25 Jul 2011 18:46:32 -0400 Message-ID: <4E2DF248.1080502@redhat.com> Date: Mon, 25 Jul 2011 15:46:32 -0700 From: Richard Henderson User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:5.0) Gecko/20110707 Thunderbird/5.0 MIME-Version: 1.0 To: GCC Patches Subject: [dwarf2cfi] Generate remember/restore_state. 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 Fixes an (intentional) .eh_frame size regression from before the rewrite. Without any actual shrink-wrapping, there are not many differences around the function. If two traces do differ, it's easy to look back to the beginning of the previous trace, which is probably an epilogue, and emit the remember/restore around the previous trace. Once we actually do some shrink-wrapping, we can look back and see if a more complex algorithm is warranted. Tested on x86_64 and i686 linux. r~ * dwarf2cfi.c (dw_trace_info): Add ID member. (get_trace_index): Remove. Change users to use ID member. (before_next_cfi_note): New. (connect_traces): Remove unreachable traces before the main loop. Look across one trace and generate remember/restore_state if needed. diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c index 1b54278..99b37ab 100644 --- a/gcc/dwarf2cfi.c +++ b/gcc/dwarf2cfi.c @@ -109,9 +109,6 @@ typedef struct /* The row state at the beginning and end of the trace. */ dw_cfi_row *beg_row, *end_row; - /* True if this trace immediately follows NOTE_INSN_SWITCH_TEXT_SECTIONS. */ - bool switch_sections; - /* The following variables contain data used in interpreting frame related expressions. These are not part of the "real" row state as defined by Dwarf, but it seems like they need to be propagated into a trace in case @@ -139,6 +136,11 @@ typedef struct a maximum of 5 entries. */ VEC(reg_saved_in_data, heap) *regs_saved_in_regs; + /* An identifier for this trace. Used only for debugging dumps. */ + unsigned id; + + /* True if this trace immediately follows NOTE_INSN_SWITCH_TEXT_SECTIONS. */ + bool switch_sections; } dw_trace_info; DEF_VEC_O (dw_trace_info); @@ -288,12 +290,6 @@ dw_trace_info_eq (const void *ptr_a, const void *ptr_b) return a->head == b->head; } -static unsigned -get_trace_index (dw_trace_info *trace) -{ - return trace - VEC_address (dw_trace_info, trace_info); -} - static dw_trace_info * get_trace_info (rtx insn) { @@ -2410,7 +2406,7 @@ maybe_record_trace_start (rtx start, rtx origin, bool abnormal) if (dump_file) { fprintf (dump_file, " saw edge from trace %u to %u (via %s %d)\n", - get_trace_index (cur_trace), get_trace_index (ti), + cur_trace->id, ti->id, (origin ? rtx_name[(int) GET_CODE (origin)] : "fallthru"), (origin ? INSN_UID (origin) : 0)); } @@ -2433,8 +2429,7 @@ maybe_record_trace_start (rtx start, rtx origin, bool abnormal) VEC_safe_push (dw_trace_info_ref, heap, trace_work_list, ti); if (dump_file) - fprintf (dump_file, "\tpush trace %u to worklist\n", - get_trace_index (ti)); + fprintf (dump_file, "\tpush trace %u to worklist\n", ti->id); } else { @@ -2534,7 +2529,7 @@ scan_trace (dw_trace_info *trace) if (dump_file) fprintf (dump_file, "Processing trace %u : start at %s %d\n", - get_trace_index (trace), rtx_name[(int) GET_CODE (insn)], + trace->id, rtx_name[(int) GET_CODE (insn)], INSN_UID (insn)); trace->end_row = copy_cfi_row (trace->beg_row); @@ -2630,8 +2625,23 @@ create_cfi_notes (void) VEC_free (dw_trace_info_ref, heap, trace_work_list); } +/* Return the insn before the first NOTE_INSN_CFI after START. */ + +static rtx +before_next_cfi_note (rtx start) +{ + rtx prev = start; + while (start) + { + if (NOTE_P (start) && NOTE_KIND (start) == NOTE_INSN_CFI) + return prev; + prev = start; + start = NEXT_INSN (start); + } + gcc_unreachable (); +} + /* Insert CFI notes between traces to properly change state between them. */ -/* ??? TODO: Make use of remember/restore_state. */ static void connect_traces (void) @@ -2639,24 +2649,37 @@ connect_traces (void) unsigned i, n = VEC_length (dw_trace_info, trace_info); dw_trace_info *prev_ti, *ti; - prev_ti = VEC_index (dw_trace_info, trace_info, 0); + /* ??? Ideally, we should have both queued and processed every trace. + However the current representation of constant pools on various targets + is indistinguishable from unreachable code. Assume for the moment that + we can simply skip over such traces. */ + /* ??? Consider creating a DATA_INSN rtx code to indicate that + these are not "real" instructions, and should not be considered. + This could be generically useful for tablejump data as well. */ + /* Remove all unprocessed traces from the list. */ + for (i = n - 1; i > 0; --i) + { + ti = VEC_index (dw_trace_info, trace_info, i); + if (ti->beg_row == NULL) + { + VEC_ordered_remove (dw_trace_info, trace_info, i); + n -= 1; + } + else + gcc_assert (ti->end_row != NULL); + } - for (i = 1; i < n; ++i) + /* Work from the end back to the beginning. This lets us easily insert + remember/restore_state notes in the correct order wrt other notes. */ + prev_ti = VEC_index (dw_trace_info, trace_info, n - 1); + for (i = n - 1; i > 0; --i) { dw_cfi_row *old_row; - ti = VEC_index (dw_trace_info, trace_info, i); + ti = prev_ti; + prev_ti = VEC_index (dw_trace_info, trace_info, i - 1); - /* ??? Ideally, we should have both queued and processed. However - the current representation of constant pools on various targets - is indistinguishable from unreachable code. Assume for the - moment that we can simply skip over such traces. */ - /* ??? Consider creating a DATA_INSN rtx code to indicate that - these are not "real" instructions, and should not be considered. - This could be generically useful for tablejump data as well. */ - if (ti->beg_row == NULL) - continue; - gcc_assert (ti->end_row != NULL); + add_cfi_insn = ti->head; /* In dwarf2out_switch_text_section, we'll begin a new FDE for the portion of the function in the alternate text @@ -2665,16 +2688,47 @@ connect_traces (void) if (ti->switch_sections) old_row = cie_cfi_row; else - old_row = prev_ti->end_row; + { + old_row = prev_ti->end_row; + /* If there's no change from the previous end state, fine. */ + if (cfi_row_equal_p (old_row, ti->beg_row)) + ; + /* Otherwise check for the common case of sharing state with + the beginning of an epilogue, but not the end. Insert + remember/restore opcodes in that case. */ + else if (cfi_row_equal_p (prev_ti->beg_row, ti->beg_row)) + { + dw_cfi_ref cfi; + + /* Note that if we blindly insert the remember at the + start of the trace, we can wind up increasing the + size of the unwind info due to extra advance opcodes. + Instead, put the remember immediately before the next + state change. We know there must be one, because the + state at the beginning and head of the trace differ. */ + add_cfi_insn = before_next_cfi_note (prev_ti->head); + cfi = new_cfi (); + cfi->dw_cfi_opc = DW_CFA_remember_state; + add_cfi (cfi); + + add_cfi_insn = ti->head; + cfi = new_cfi (); + cfi->dw_cfi_opc = DW_CFA_restore_state; + add_cfi (cfi); + + old_row = prev_ti->beg_row; + } + /* Otherwise, we'll simply change state from the previous end. */ + } - add_cfi_insn = ti->head; change_cfi_row (old_row, ti->beg_row); if (dump_file && add_cfi_insn != ti->head) { rtx note; - fprintf (dump_file, "Fixup between trace %u and %u:\n", i - 1, i); + fprintf (dump_file, "Fixup between trace %u and %u:\n", + prev_ti->id, ti->id); note = ti->head; do @@ -2685,8 +2739,6 @@ connect_traces (void) } while (note != add_cfi_insn); } - - prev_ti = ti; } } @@ -2739,6 +2791,7 @@ create_pseudo_cfg (void) memset (ti, 0, sizeof (*ti)); ti->head = insn; ti->switch_sections = switch_sections; + ti->id = VEC_length (dw_trace_info, trace_info) - 1; saw_barrier = false; switch_sections = false;