From patchwork Wed Oct 5 20:48:06 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bernd Schmidt X-Patchwork-Id: 117915 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 B78C4B7010 for ; Thu, 6 Oct 2011 07:48:32 +1100 (EST) Received: (qmail 29696 invoked by alias); 5 Oct 2011 20:48:29 -0000 Received: (qmail 29684 invoked by uid 22791); 5 Oct 2011 20:48:26 -0000 X-SWARE-Spam-Status: No, hits=-0.9 required=5.0 tests=AWL, BAYES_00, FROM_12LTRDOM X-Spam-Check-By: sourceware.org Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 05 Oct 2011 20:48:12 +0000 Received: from nat-ies.mentorg.com ([192.94.31.2] helo=EU1-MAIL.mgc.mentorg.com) by relay1.mentorg.com with esmtp id 1RBYNv-0002TS-7O from Bernd_Schmidt@mentor.com for gcc-patches@gcc.gnu.org; Wed, 05 Oct 2011 13:48:11 -0700 Received: from [127.0.0.1] ([172.16.63.104]) by EU1-MAIL.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.1830); Wed, 5 Oct 2011 21:48:09 +0100 Message-ID: <4E8CC286.80107@codesourcery.com> Date: Wed, 05 Oct 2011 22:48:06 +0200 From: Bernd Schmidt User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.20) Gecko/20110920 Lightning/1.0b3pre Thunderbird/3.1.12 MIME-Version: 1.0 To: GCC Patches Subject: Find more shrink-wrapping opportunities 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 adds a little mini-pass to shrink-wrapping, to eliminate a common case that often makes shrink-wrapping unavailable. If a move insn copies an argument registers to a call-saved register, the prologue must be emitted before this insn. We should therefore try to delay such moves for as long as possible. A followup patch will add an extra cprop pass, which replaces uses of the call-saved register with uses of the incoming argument register, thereby allowing us to move the copies in even more cases. Bootstrapped and tested on i686-linux. Ok? Bernd * function.c (prepare_shrink_wrap, bb_active_p): New function. (thread_prologue_and_epilogue_insns): Use bb_active_p. Call prepare_shrink_wrap, then recompute bb_active_p for the last block. Index: gcc/function.c =================================================================== --- gcc/function.c (revision 179577) +++ gcc/function.c (working copy) @@ -5352,6 +5352,127 @@ requires_stack_frame_p (rtx insn, HARD_R return true; return false; } + +/* Look for sets of call-saved registers in the first block of the + function, and move them down into successor blocks if the register + is used only on one path. This exposes more opportunities for + shrink-wrapping. + These kinds of sets often occur when incoming argument registers are + moved to call-saved registers because their values are live across + one or more calls during the function. */ + +static void +prepare_shrink_wrap (basic_block entry_block) +{ + rtx insn, curr; + FOR_BB_INSNS_SAFE (entry_block, insn, curr) + { + basic_block next_bb; + edge e, live_edge; + edge_iterator ei; + rtx set, scan; + unsigned destreg, srcreg; + + if (!NONDEBUG_INSN_P (insn)) + continue; + set = single_set (insn); + if (!set) + continue; + + if (!REG_P (SET_SRC (set)) || !REG_P (SET_DEST (set))) + continue; + srcreg = REGNO (SET_SRC (set)); + destreg = REGNO (SET_DEST (set)); + if (hard_regno_nregs[srcreg][GET_MODE (SET_SRC (set))] > 1 + || hard_regno_nregs[destreg][GET_MODE (SET_DEST (set))] > 1) + continue; + + next_bb = entry_block; + scan = insn; + + for (;;) + { + live_edge = NULL; + FOR_EACH_EDGE (e, ei, next_bb->succs) + { + if (REGNO_REG_SET_P (df_get_live_in (e->dest), destreg)) + { + if (live_edge) + { + live_edge = NULL; + break; + } + live_edge = e; + } + } + if (!live_edge) + break; + /* We can sometimes encounter dead code. Don't try to move it + into the exit block. */ + if (live_edge->dest == EXIT_BLOCK_PTR) + break; + if (EDGE_COUNT (live_edge->dest->preds) > 1) + break; + while (scan != BB_END (next_bb)) + { + scan = NEXT_INSN (scan); + if (NONDEBUG_INSN_P (scan)) + { + rtx link; + HARD_REG_SET set_regs; + + CLEAR_HARD_REG_SET (set_regs); + note_stores (PATTERN (scan), record_hard_reg_sets, + &set_regs); + if (CALL_P (scan)) + IOR_HARD_REG_SET (set_regs, call_used_reg_set); + for (link = REG_NOTES (scan); link; link = XEXP (link, 1)) + if (REG_NOTE_KIND (link) == REG_INC) + record_hard_reg_sets (XEXP (link, 0), NULL, &set_regs); + + if (TEST_HARD_REG_BIT (set_regs, srcreg) + || reg_referenced_p (SET_DEST (set), + PATTERN (scan))) + { + scan = NULL_RTX; + break; + } + if (CALL_P (scan)) + { + rtx link = CALL_INSN_FUNCTION_USAGE (scan); + while (link) + { + rtx tmp = XEXP (link, 0); + if (GET_CODE (tmp) == USE + && reg_referenced_p (SET_DEST (set), tmp)) + break; + link = XEXP (link, 1); + } + if (link) + { + scan = NULL_RTX; + break; + } + } + } + } + if (!scan) + break; + next_bb = live_edge->dest; + } + + if (next_bb != entry_block) + { + rtx after = BB_HEAD (next_bb); + while (!NOTE_P (after) + || NOTE_KIND (after) != NOTE_INSN_BASIC_BLOCK) + after = NEXT_INSN (after); + emit_insn_after (PATTERN (insn), after); + delete_insn (insn); + } + } +} + #endif #ifdef HAVE_return @@ -5400,6 +5521,23 @@ emit_return_into_block (bool simple_p, b } #endif +/* Return true if BB has any active insns. */ +static bool +bb_active_p (basic_block bb) +{ + rtx label; + + /* Test whether there are active instructions in the last block. */ + label = BB_END (bb); + while (label && !LABEL_P (label)) + { + if (active_insn_p (label)) + break; + label = PREV_INSN (label); + } + return BB_HEAD (bb) != label || !LABEL_P (label); +} + /* Generate the prologue and epilogue RTL if the machine supports it. Thread this into place with notes indicating where the prologue ends and where the epilogue begins. Update the basic block information when possible. @@ -5486,19 +5624,8 @@ thread_prologue_and_epilogue_insns (void exit_fallthru_edge = find_fallthru_edge (EXIT_BLOCK_PTR->preds); if (exit_fallthru_edge != NULL) { - rtx label; - last_bb = exit_fallthru_edge->src; - /* Test whether there are active instructions in the last block. */ - label = BB_END (last_bb); - while (label && !LABEL_P (label)) - { - if (active_insn_p (label)) - break; - label = PREV_INSN (label); - } - - last_bb_active = BB_HEAD (last_bb) != label || !LABEL_P (label); + last_bb_active = bb_active_p (last_bb); } else { @@ -5607,6 +5734,12 @@ thread_prologue_and_epilogue_insns (void note_stores (PATTERN (p_insn), record_hard_reg_sets, &prologue_clobbered); + prepare_shrink_wrap (entry_edge->dest); + + /* That may have inserted instructions into the last block. */ + if (last_bb && !last_bb_active) + last_bb_active = bb_active_p (last_bb); + bitmap_initialize (&bb_antic_flags, &bitmap_default_obstack); bitmap_initialize (&bb_on_list, &bitmap_default_obstack);