2011-03-09 Bernd Schmidt Issue #10649 gcc/ * dwarf2out.c (dwarf2out_begin_epilogue): Accept simplejumps as well as returnjumps. * cfganal.c (set_edge_can_fallthru_flag): Revert previous change that tried to keep epilogue blocks adjacent. 2011-02-03 Bernd Schmidt gcc/ * function.c (prepare_shrink_wrap): New function. (thread_prologue_and_epilogue_insns): Call it. === modified file 'gcc/cfganal.c' --- old/gcc/cfganal.c 2011-02-08 10:51:58 +0000 +++ new/gcc/cfganal.c 2011-03-10 14:55:10 +0000 @@ -271,37 +271,6 @@ EDGE_SUCC (bb, 0)->flags |= EDGE_CAN_FALLTHRU; EDGE_SUCC (bb, 1)->flags |= EDGE_CAN_FALLTHRU; } - /* dwarf2out expects that a NOTE_INSN_EPILOGUE_BEGIN is always paired - with a return or a sibcall. Ensure that this remains the case if - they are in different basic blocks. */ - FOR_EACH_BB (bb) - { - edge e; - edge_iterator ei; - rtx insn, end; - - end = BB_END (bb); - FOR_BB_INSNS (bb, insn) - if (GET_CODE (insn) == NOTE - && NOTE_KIND (insn) == NOTE_INSN_EPILOGUE_BEG - && !(CALL_P (end) && SIBLING_CALL_P (end)) - && !returnjump_p (end)) - { - basic_block other_bb = NULL; - FOR_EACH_EDGE (e, ei, bb->succs) - { - if (e->flags & EDGE_FALLTHRU) - other_bb = e->dest; - else - e->flags &= ~EDGE_CAN_FALLTHRU; - } - FOR_EACH_EDGE (e, ei, other_bb->preds) - { - if (!(e->flags & EDGE_FALLTHRU)) - e->flags &= ~EDGE_CAN_FALLTHRU; - } - } - } } /* Find unreachable blocks. An unreachable block will have 0 in === modified file 'gcc/dwarf2out.c' --- old/gcc/dwarf2out.c 2011-02-08 10:51:58 +0000 +++ new/gcc/dwarf2out.c 2011-03-10 14:55:10 +0000 @@ -2782,10 +2782,10 @@ dwarf2out_frame_debug_expr (insn, label); } -/* 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_begin_epilogue (rtx insn) @@ -2800,8 +2800,10 @@ 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; === modified file 'gcc/function.c' --- old/gcc/function.c 2011-02-08 10:51:58 +0000 +++ new/gcc/function.c 2011-03-10 14:55:10 +0000 @@ -5038,6 +5038,127 @@ 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 @@ -5215,6 +5336,8 @@ bitmap_head bb_antic_flags; bitmap_head bb_on_list; + prepare_shrink_wrap (entry_edge->dest); + bitmap_initialize (&bb_antic_flags, &bitmap_default_obstack); bitmap_initialize (&bb_on_list, &bitmap_default_obstack);