diff options
Diffstat (limited to 'toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99456.patch')
-rw-r--r-- | toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99456.patch | 3163 |
1 files changed, 0 insertions, 3163 deletions
diff --git a/toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99456.patch b/toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99456.patch deleted file mode 100644 index 35f98d24ab..0000000000 --- a/toolchain-layer/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99456.patch +++ /dev/null @@ -1,3163 +0,0 @@ -2011-01-03 Bernd Schmidt <bernds@codesourcery.com> - - gcc/ - * doc/tm.texi (RETURN_ADDR_REGNUM): Document. - * doc/md.texi (simple_return): Document pattern. - (return): Add a sentence to clarify. - * doc/rtl.texi (simple_return): Document. - * doc/invoke.texi (Optimize Options): Document -fshrink-wrap. - * common.opt (fshrink-wrap): New. - * opts.c (decode_options): Set it for -O2 and above. - * gengenrtl.c (special_rtx): PC, CC0, RETURN and SIMPLE_RETURN - are special. - * rtl.h (ANY_RETURN_P): New macro. - (global_rtl_index): Add GR_RETURN and GR_SIMPLE_RETURN. - (ret_rtx, simple_return_rtx): New macros. - * genemit.c (gen_exp): RETURN and SIMPLE_RETURN have unique rtxs. - (gen_expand, gen_split): Use ANY_RETURN_P. - * rtl.c (copy_rtx): RETURN and SIMPLE_RETURN are shared. - * emit-rtl.c (verify_rtx_sharing): Likewise. - (skip_consecutive_labels): Return the argument if it is a return rtx. - (classify_insn): Handle both kinds of return. - (init_emit_regs): Create global rtl for ret_rtx and simple_return_rtx. - * df-scan.c (df_uses_record): Handle SIMPLE_RETURN. - * rtl.def (SIMPLE_RETURN): New. - * rtlanal.c (tablejump_p): Check JUMP_LABEL for returns. - * final.c (final_scan_insn): Recognize both kinds of return. - * reorg.c (function_return_label, function_simple_return_label): New - static variables. - (end_of_function_label): Remove. - (simplejump_or_return_p): New static function. - (find_end_label): Add a new arg, KIND. All callers changed. - Depending on KIND, look for a label suitable for return or - simple_return. - (make_return_insns): Make corresponding changes. - (get_jump_flags): Check JUMP_LABELs for returns. - (follow_jumps): Likewise. - (get_branch_condition): Check target for return patterns rather - than NULL. - (own_thread_p): Likewise for thread. - (steal_delay_list_from_target): Check JUMP_LABELs for returns. - Use simplejump_or_return_p. - (fill_simple_delay_slots): Likewise. - (optimize_skip): Likewise. - (fill_slots_from_thread): Likewise. - (relax_delay_slots): Likewise. - (dbr_schedule): Adjust handling of end_of_function_label for the - two new variables. - * ifcvt.c (find_if_case_1): Take care when redirecting jumps to the - exit block. - (dead_or_predicable): Change NEW_DEST arg to DEST_EDGE. All callers - changed. Ensure that the right label is passed to redirect_jump. - * jump.c (condjump_p, condjump_in_parallel_p, any_condjump_p, - returnjump_p): Handle SIMPLE_RETURNs. - (delete_related_insns): Check JUMP_LABEL for returns. - (redirect_target): New static function. - (redirect_exp_1): Use it. Handle any kind of return rtx as a label - rather than interpreting NULL as a return. - (redirect_jump_1): Assert that nlabel is not NULL. - (redirect_jump): Likewise. - (redirect_jump_2): Handle any kind of return rtx as a label rather - than interpreting NULL as a return. - * dwarf2out.c (compute_barrier_args_size_1): Check JUMP_LABEL for - returns. - * function.c (emit_return_into_block): Remove useless declaration. - (record_hard_reg_sets, frame_required_for_rtx, gen_return_pattern, - requires_stack_frame_p): New static functions. - (emit_return_into_block): New arg SIMPLE_P. All callers changed. - Generate either kind of return pattern and update the JUMP_LABEL. - (thread_prologue_and_epilogue_insns): Implement a form of - shrink-wrapping. Ensure JUMP_LABELs for return insns are set. - * print-rtl.c (print_rtx): Handle returns in JUMP_LABELs. - * cfglayout.c (fixup_reorder_chain): Ensure JUMP_LABELs for returns - remain correct. - * resource.c (find_dead_or_set_registers): Check JUMP_LABELs for - returns. - (mark_target_live_regs): Don't pass a return rtx to next_active_insn. - * basic-block.h (force_nonfallthru_and_redirect): Declare. - * sched-vis.c (print_pattern): Add case for SIMPLE_RETURN. - * cfgrtl.c (force_nonfallthru_and_redirect): No longer static. New arg - JUMP_LABEL. All callers changed. Use the label when generating - return insns. - - * config/i386/i386.md (returns, return_str, return_cond): New - code_iterator and corresponding code_attrs. - (<return_str>return): Renamed from return and adapted. - (<return_str>return_internal): Likewise for return_internal. - (<return_str>return_internal_long): Likewise for return_internal_long. - (<return_str>return_pop_internal): Likewise for return_pop_internal. - (<return_str>return_indirect_internal): Likewise for - return_indirect_internal. - * config/i386/i386.c (ix86_expand_epilogue): Expand a simple_return as - the last insn. - (ix86_pad_returns): Handle both kinds of return rtx. - * config/arm/arm.c (use_simple_return_p): new function. - (is_jump_table): Handle returns in JUMP_LABELs. - (output_return_instruction): New arg SIMPLE. All callers changed. - Use it to determine which kind of return to generate. - (arm_final_prescan_insn): Handle both kinds of return. - * config/arm/arm.md (returns, return_str, return_simple_p, - return_cond): New code_iterator and corresponding code_attrs. - (<return_str>return): Renamed from return and adapted. - (arm_<return_str>return): Renamed from arm_return and adapted. - (cond_<return_str>return): Renamed from cond_return and adapted. - (cond_<return_str>return_inverted): Renamed from cond_return_inverted - and adapted. - (epilogue): Use ret_rtx instead of gen_rtx_RETURN. - * config/arm/thumb2.md (thumb2_<return_str>return): Renamed from - thumb2_return and adapted. - * config/arm/arm.h (RETURN_ADDR_REGNUM): Define. - * config/arm/arm-protos.h (use_simple_return_p): Declare. - (output_return_instruction): Adjust declaration. - * config/mips/mips.c (mips_expand_epilogue): Generate a simple_return - as final insn. - * config/mips/mips.md (simple_return): New expander. - (*simple_return, simple_return_internal): New patterns. - * config/sh/sh.c (barrier_align): Handle return in a JUMP_LABEL. - (split_branches): Don't pass a null label to redirect_jump. - - From mainline: - * vec.h (FOR_EACH_VEC_ELT, FOR_EACH_VEC_ELT_REVERSE): New macros. - * haifa-sched.c (find_fallthru_edge_from): Rename from - find_fallthru_edge. All callers changed. - * sched-int.h (find_fallthru_edge_from): Rename declaration as well. - * basic-block.h (find_fallthru_edge): New inline function. - -=== modified file 'gcc/basic-block.h' ---- old/gcc/basic-block.h 2010-09-01 13:29:58 +0000 -+++ new/gcc/basic-block.h 2011-01-05 12:12:18 +0000 -@@ -884,6 +884,7 @@ - - /* In cfgrtl.c */ - extern basic_block force_nonfallthru (edge); -+extern basic_block force_nonfallthru_and_redirect (edge, basic_block, rtx); - extern rtx block_label (basic_block); - extern bool purge_all_dead_edges (void); - extern bool purge_dead_edges (basic_block); -@@ -1004,6 +1005,20 @@ - return false; - } - -+/* Return the fallthru edge in EDGES if it exists, NULL otherwise. */ -+static inline edge -+find_fallthru_edge (VEC(edge,gc) *edges) -+{ -+ edge e; -+ edge_iterator ei; -+ -+ FOR_EACH_EDGE (e, ei, edges) -+ if (e->flags & EDGE_FALLTHRU) -+ break; -+ -+ return e; -+} -+ - /* In cfgloopmanip.c. */ - extern edge mfb_kj_edge; - extern bool mfb_keep_just (edge); - -=== modified file 'gcc/cfganal.c' ---- old/gcc/cfganal.c 2009-11-25 10:55:54 +0000 -+++ new/gcc/cfganal.c 2011-01-05 12:12:18 +0000 -@@ -271,6 +271,37 @@ - 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/cfglayout.c' ---- old/gcc/cfglayout.c 2010-05-17 16:30:54 +0000 -+++ new/gcc/cfglayout.c 2011-01-05 12:12:18 +0000 -@@ -766,6 +766,7 @@ - { - edge e_fall, e_taken, e; - rtx bb_end_insn; -+ rtx ret_label = NULL_RTX; - basic_block nb; - edge_iterator ei; - -@@ -785,6 +786,7 @@ - bb_end_insn = BB_END (bb); - if (JUMP_P (bb_end_insn)) - { -+ ret_label = JUMP_LABEL (bb_end_insn); - if (any_condjump_p (bb_end_insn)) - { - /* This might happen if the conditional jump has side -@@ -899,7 +901,7 @@ - } - - /* We got here if we need to add a new jump insn. */ -- nb = force_nonfallthru (e_fall); -+ nb = force_nonfallthru_and_redirect (e_fall, e_fall->dest, ret_label); - if (nb) - { - nb->il.rtl->visited = 1; -@@ -1118,24 +1120,30 @@ - bool - cfg_layout_can_duplicate_bb_p (const_basic_block bb) - { -+ rtx insn; -+ - /* Do not attempt to duplicate tablejumps, as we need to unshare - the dispatch table. This is difficult to do, as the instructions - computing jump destination may be hoisted outside the basic block. */ - if (tablejump_p (BB_END (bb), NULL, NULL)) - return false; - -- /* Do not duplicate blocks containing insns that can't be copied. */ -- if (targetm.cannot_copy_insn_p) -+ insn = BB_HEAD (bb); -+ while (1) - { -- rtx insn = BB_HEAD (bb); -- while (1) -- { -- if (INSN_P (insn) && targetm.cannot_copy_insn_p (insn)) -- return false; -- if (insn == BB_END (bb)) -- break; -- insn = NEXT_INSN (insn); -- } -+ /* Do not duplicate blocks containing insns that can't be copied. */ -+ if (INSN_P (insn) && targetm.cannot_copy_insn_p -+ && targetm.cannot_copy_insn_p (insn)) -+ return false; -+ /* dwarf2out expects that these notes are always paired with a -+ returnjump or sibling call. */ -+ if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_EPILOGUE_BEG -+ && !returnjump_p (BB_END (bb)) -+ && (!CALL_P (BB_END (bb)) || !SIBLING_CALL_P (BB_END (bb)))) -+ return false; -+ if (insn == BB_END (bb)) -+ break; -+ insn = NEXT_INSN (insn); - } - - return true; -@@ -1167,6 +1175,9 @@ - || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC) - break; - copy = emit_copy_of_insn_after (insn, get_last_insn ()); -+ if (JUMP_P (insn) && JUMP_LABEL (insn) != NULL_RTX -+ && ANY_RETURN_P (JUMP_LABEL (insn))) -+ JUMP_LABEL (copy) = JUMP_LABEL (insn); - maybe_copy_epilogue_insn (insn, copy); - break; - - -=== modified file 'gcc/cfgrtl.c' ---- old/gcc/cfgrtl.c 2010-09-20 21:30:35 +0000 -+++ new/gcc/cfgrtl.c 2011-01-05 12:12:18 +0000 -@@ -1107,10 +1107,13 @@ - } - - /* Like force_nonfallthru below, but additionally performs redirection -- Used by redirect_edge_and_branch_force. */ -+ Used by redirect_edge_and_branch_force. JUMP_LABEL is used only -+ when redirecting to the EXIT_BLOCK, it is either a return or a -+ simple_return rtx indicating which kind of returnjump to create. -+ It should be NULL otherwise. */ - --static basic_block --force_nonfallthru_and_redirect (edge e, basic_block target) -+basic_block -+force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label) - { - basic_block jump_block, new_bb = NULL, src = e->src; - rtx note; -@@ -1242,11 +1245,25 @@ - e->flags &= ~EDGE_FALLTHRU; - if (target == EXIT_BLOCK_PTR) - { -+ if (jump_label == ret_rtx) -+ { - #ifdef HAVE_return -- emit_jump_insn_after_setloc (gen_return (), BB_END (jump_block), loc); --#else -- gcc_unreachable (); --#endif -+ emit_jump_insn_after_setloc (gen_return (), BB_END (jump_block), -+ loc); -+#else -+ gcc_unreachable (); -+#endif -+ } -+ else -+ { -+ gcc_assert (jump_label == simple_return_rtx); -+#ifdef HAVE_simple_return -+ emit_jump_insn_after_setloc (gen_simple_return (), -+ BB_END (jump_block), loc); -+#else -+ gcc_unreachable (); -+#endif -+ } - } - else - { -@@ -1273,7 +1290,7 @@ - basic_block - force_nonfallthru (edge e) - { -- return force_nonfallthru_and_redirect (e, e->dest); -+ return force_nonfallthru_and_redirect (e, e->dest, NULL_RTX); - } - - /* Redirect edge even at the expense of creating new jump insn or -@@ -1290,7 +1307,7 @@ - /* In case the edge redirection failed, try to force it to be non-fallthru - and redirect newly created simplejump. */ - df_set_bb_dirty (e->src); -- return force_nonfallthru_and_redirect (e, target); -+ return force_nonfallthru_and_redirect (e, target, NULL_RTX); - } - - /* The given edge should potentially be a fallthru edge. If that is in - -=== modified file 'gcc/common.opt' ---- old/gcc/common.opt 2010-12-10 15:33:37 +0000 -+++ new/gcc/common.opt 2011-01-05 12:12:18 +0000 -@@ -1147,6 +1147,11 @@ - Common C ObjC C++ ObjC++ Report Var(flag_show_column) Init(1) - Show column numbers in diagnostics, when available. Default on - -+fshrink-wrap -+Common Report Var(flag_shrink_wrap) Optimization -+Emit function prologues only before parts of the function that need it, -+rather than at the top of the function. -+ - fsignaling-nans - Common Report Var(flag_signaling_nans) Optimization - Disable optimizations observable by IEEE signaling NaNs - -=== modified file 'gcc/config/arm/arm-protos.h' ---- old/gcc/config/arm/arm-protos.h 2010-11-04 10:45:05 +0000 -+++ new/gcc/config/arm/arm-protos.h 2011-01-05 12:12:18 +0000 -@@ -26,6 +26,7 @@ - extern void arm_override_options (void); - extern void arm_optimization_options (int, int); - extern int use_return_insn (int, rtx); -+extern bool use_simple_return_p (void); - extern enum reg_class arm_regno_class (int); - extern void arm_load_pic_register (unsigned long); - extern int arm_volatile_func (void); -@@ -137,7 +138,7 @@ - extern const char *output_add_immediate (rtx *); - extern const char *arithmetic_instr (rtx, int); - extern void output_ascii_pseudo_op (FILE *, const unsigned char *, int); --extern const char *output_return_instruction (rtx, int, int); -+extern const char *output_return_instruction (rtx, bool, bool, bool); - extern void arm_poke_function_name (FILE *, const char *); - extern void arm_print_operand (FILE *, rtx, int); - extern void arm_print_operand_address (FILE *, rtx); - -=== modified file 'gcc/config/arm/arm.c' ---- old/gcc/config/arm/arm.c 2011-01-05 11:32:50 +0000 -+++ new/gcc/config/arm/arm.c 2011-01-05 12:12:18 +0000 -@@ -2163,6 +2163,18 @@ - return addr; - } - -+/* Return true if we should try to use a simple_return insn, i.e. perform -+ shrink-wrapping if possible. This is the case if we need to emit a -+ prologue, which we can test by looking at the offsets. */ -+bool -+use_simple_return_p (void) -+{ -+ arm_stack_offsets *offsets; -+ -+ offsets = arm_get_frame_offsets (); -+ return offsets->outgoing_args != 0; -+} -+ - /* Return 1 if it is possible to return using a single instruction. - If SIBLING is non-null, this is a test for a return before a sibling - call. SIBLING is the call insn, so we can examine its register usage. */ -@@ -11284,6 +11296,7 @@ - - if (GET_CODE (insn) == JUMP_INSN - && JUMP_LABEL (insn) != NULL -+ && !ANY_RETURN_P (JUMP_LABEL (insn)) - && ((table = next_real_insn (JUMP_LABEL (insn))) - == next_real_insn (insn)) - && table != NULL -@@ -14168,7 +14181,7 @@ - /* Generate a function exit sequence. If REALLY_RETURN is false, then do - everything bar the final return instruction. */ - const char * --output_return_instruction (rtx operand, int really_return, int reverse) -+output_return_instruction (rtx operand, bool really_return, bool reverse, bool simple) - { - char conditional[10]; - char instr[100]; -@@ -14206,10 +14219,15 @@ - - sprintf (conditional, "%%?%%%c0", reverse ? 'D' : 'd'); - -- cfun->machine->return_used_this_function = 1; -+ if (simple) -+ live_regs_mask = 0; -+ else -+ { -+ cfun->machine->return_used_this_function = 1; - -- offsets = arm_get_frame_offsets (); -- live_regs_mask = offsets->saved_regs_mask; -+ offsets = arm_get_frame_offsets (); -+ live_regs_mask = offsets->saved_regs_mask; -+ } - - if (live_regs_mask) - { -@@ -17108,6 +17126,7 @@ - - /* If we start with a return insn, we only succeed if we find another one. */ - int seeking_return = 0; -+ enum rtx_code return_code = UNKNOWN; - - /* START_INSN will hold the insn from where we start looking. This is the - first insn after the following code_label if REVERSE is true. */ -@@ -17146,7 +17165,7 @@ - else - return; - } -- else if (GET_CODE (body) == RETURN) -+ else if (ANY_RETURN_P (body)) - { - start_insn = next_nonnote_insn (start_insn); - if (GET_CODE (start_insn) == BARRIER) -@@ -17157,6 +17176,7 @@ - { - reverse = TRUE; - seeking_return = 1; -+ return_code = GET_CODE (body); - } - else - return; -@@ -17197,11 +17217,15 @@ - label = XEXP (XEXP (SET_SRC (body), 2), 0); - then_not_else = FALSE; - } -- else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN) -- seeking_return = 1; -- else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN) -+ else if (ANY_RETURN_P (XEXP (SET_SRC (body), 1))) -+ { -+ seeking_return = 1; -+ return_code = GET_CODE (XEXP (SET_SRC (body), 1)); -+ } -+ else if (ANY_RETURN_P (XEXP (SET_SRC (body), 2))) - { - seeking_return = 1; -+ return_code = GET_CODE (XEXP (SET_SRC (body), 2)); - then_not_else = FALSE; - } - else -@@ -17302,8 +17326,7 @@ - && !use_return_insn (TRUE, NULL) - && !optimize_size) - fail = TRUE; -- else if (GET_CODE (scanbody) == RETURN -- && seeking_return) -+ else if (GET_CODE (scanbody) == return_code) - { - arm_ccfsm_state = 2; - succeed = TRUE; - -=== modified file 'gcc/config/arm/arm.h' ---- old/gcc/config/arm/arm.h 2010-11-11 11:12:14 +0000 -+++ new/gcc/config/arm/arm.h 2011-01-05 12:12:18 +0000 -@@ -2622,6 +2622,8 @@ - #define RETURN_ADDR_RTX(COUNT, FRAME) \ - arm_return_addr (COUNT, FRAME) - -+#define RETURN_ADDR_REGNUM LR_REGNUM -+ - /* Mask of the bits in the PC that contain the real return address - when running in 26-bit mode. */ - #define RETURN_ADDR_MASK26 (0x03fffffc) - -=== modified file 'gcc/config/arm/arm.md' ---- old/gcc/config/arm/arm.md 2011-01-05 11:52:16 +0000 -+++ new/gcc/config/arm/arm.md 2011-01-05 12:12:18 +0000 -@@ -8882,66 +8882,72 @@ - [(set_attr "type" "call")] - ) - --(define_expand "return" -- [(return)] -- "TARGET_32BIT && USE_RETURN_INSN (FALSE)" -+;; Both kinds of return insn. -+(define_code_iterator returns [return simple_return]) -+(define_code_attr return_str [(return "") (simple_return "simple_")]) -+(define_code_attr return_simple_p [(return "false") (simple_return "true")]) -+(define_code_attr return_cond [(return " && USE_RETURN_INSN (FALSE)") -+ (simple_return " && use_simple_return_p ()")]) -+ -+(define_expand "<return_str>return" -+ [(returns)] -+ "TARGET_32BIT<return_cond>" - "") - --;; Often the return insn will be the same as loading from memory, so set attr --(define_insn "*arm_return" -- [(return)] -- "TARGET_ARM && USE_RETURN_INSN (FALSE)" -- "* -- { -- if (arm_ccfsm_state == 2) -- { -- arm_ccfsm_state += 2; -- return \"\"; -- } -- return output_return_instruction (const_true_rtx, TRUE, FALSE); -- }" -+(define_insn "*arm_<return_str>return" -+ [(returns)] -+ "TARGET_ARM<return_cond>" -+{ -+ if (arm_ccfsm_state == 2) -+ { -+ arm_ccfsm_state += 2; -+ return ""; -+ } -+ return output_return_instruction (const_true_rtx, true, false, -+ <return_simple_p>); -+} - [(set_attr "type" "load1") - (set_attr "length" "12") - (set_attr "predicable" "yes")] - ) - --(define_insn "*cond_return" -+(define_insn "*cond_<return_str>return" - [(set (pc) - (if_then_else (match_operator 0 "arm_comparison_operator" - [(match_operand 1 "cc_register" "") (const_int 0)]) -- (return) -+ (returns) - (pc)))] -- "TARGET_ARM && USE_RETURN_INSN (TRUE)" -- "* -- { -- if (arm_ccfsm_state == 2) -- { -- arm_ccfsm_state += 2; -- return \"\"; -- } -- return output_return_instruction (operands[0], TRUE, FALSE); -- }" -+ "TARGET_ARM<return_cond>" -+{ -+ if (arm_ccfsm_state == 2) -+ { -+ arm_ccfsm_state += 2; -+ return ""; -+ } -+ return output_return_instruction (operands[0], true, false, -+ <return_simple_p>); -+} - [(set_attr "conds" "use") - (set_attr "length" "12") - (set_attr "type" "load1")] - ) - --(define_insn "*cond_return_inverted" -+(define_insn "*cond_<return_str>return_inverted" - [(set (pc) - (if_then_else (match_operator 0 "arm_comparison_operator" - [(match_operand 1 "cc_register" "") (const_int 0)]) - (pc) -- (return)))] -- "TARGET_ARM && USE_RETURN_INSN (TRUE)" -- "* -- { -- if (arm_ccfsm_state == 2) -- { -- arm_ccfsm_state += 2; -- return \"\"; -- } -- return output_return_instruction (operands[0], TRUE, TRUE); -- }" -+ (returns)))] -+ "TARGET_ARM<return_cond>" -+{ -+ if (arm_ccfsm_state == 2) -+ { -+ arm_ccfsm_state += 2; -+ return ""; -+ } -+ return output_return_instruction (operands[0], true, true, -+ <return_simple_p>); -+} - [(set_attr "conds" "use") - (set_attr "length" "12") - (set_attr "type" "load1")] -@@ -10809,8 +10815,7 @@ - DONE; - } - emit_jump_insn (gen_rtx_UNSPEC_VOLATILE (VOIDmode, -- gen_rtvec (1, -- gen_rtx_RETURN (VOIDmode)), -+ gen_rtvec (1, ret_rtx), - VUNSPEC_EPILOGUE)); - DONE; - " -@@ -10827,7 +10832,7 @@ - "TARGET_32BIT" - "* - if (use_return_insn (FALSE, next_nonnote_insn (insn))) -- return output_return_instruction (const_true_rtx, FALSE, FALSE); -+ return output_return_instruction (const_true_rtx, false, false, false); - return arm_output_epilogue (next_nonnote_insn (insn)); - " - ;; Length is absolute worst case - -=== modified file 'gcc/config/arm/thumb2.md' ---- old/gcc/config/arm/thumb2.md 2010-09-22 05:54:42 +0000 -+++ new/gcc/config/arm/thumb2.md 2011-01-05 12:12:18 +0000 -@@ -1020,16 +1020,15 @@ - - ;; Note: this is not predicable, to avoid issues with linker-generated - ;; interworking stubs. --(define_insn "*thumb2_return" -- [(return)] -- "TARGET_THUMB2 && USE_RETURN_INSN (FALSE)" -- "* -- { -- return output_return_instruction (const_true_rtx, TRUE, FALSE); -- }" -+(define_insn "*thumb2_<return_str>return" -+ [(returns)] -+ "TARGET_THUMB2<return_cond>" -+{ -+ return output_return_instruction (const_true_rtx, true, false, -+ <return_simple_p>); -+} - [(set_attr "type" "load1") -- (set_attr "length" "12")] --) -+ (set_attr "length" "12")]) - - (define_insn_and_split "thumb2_eh_return" - [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "r")] - -=== modified file 'gcc/config/i386/i386.c' ---- old/gcc/config/i386/i386.c 2010-11-16 18:05:53 +0000 -+++ new/gcc/config/i386/i386.c 2011-01-05 12:12:18 +0000 -@@ -9308,13 +9308,13 @@ - - pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx, - popc, -1, true); -- emit_jump_insn (gen_return_indirect_internal (ecx)); -+ emit_jump_insn (gen_simple_return_indirect_internal (ecx)); - } - else -- emit_jump_insn (gen_return_pop_internal (popc)); -+ emit_jump_insn (gen_simple_return_pop_internal (popc)); - } - else -- emit_jump_insn (gen_return_internal ()); -+ emit_jump_insn (gen_simple_return_internal ()); - - /* Restore the state back to the state from the prologue, - so that it's correct for the next epilogue. */ -@@ -26596,7 +26596,7 @@ - rtx prev; - bool replace = false; - -- if (!JUMP_P (ret) || GET_CODE (PATTERN (ret)) != RETURN -+ if (!JUMP_P (ret) || !ANY_RETURN_P (PATTERN (ret)) - || optimize_bb_for_size_p (bb)) - continue; - for (prev = PREV_INSN (ret); prev; prev = PREV_INSN (prev)) -@@ -26626,7 +26626,10 @@ - } - if (replace) - { -- emit_jump_insn_before (gen_return_internal_long (), ret); -+ if (PATTERN (ret) == ret_rtx) -+ emit_jump_insn_before (gen_return_internal_long (), ret); -+ else -+ emit_jump_insn_before (gen_simple_return_internal_long (), ret); - delete_insn (ret); - } - } - -=== modified file 'gcc/config/i386/i386.md' ---- old/gcc/config/i386/i386.md 2010-11-27 15:24:12 +0000 -+++ new/gcc/config/i386/i386.md 2011-01-05 12:12:18 +0000 -@@ -13797,24 +13797,29 @@ - "" - [(set_attr "length" "0")]) - -+(define_code_iterator returns [return simple_return]) -+(define_code_attr return_str [(return "") (simple_return "simple_")]) -+(define_code_attr return_cond [(return "ix86_can_use_return_insn_p ()") -+ (simple_return "")]) -+ - ;; Insn emitted into the body of a function to return from a function. - ;; This is only done if the function's epilogue is known to be simple. - ;; See comments for ix86_can_use_return_insn_p in i386.c. - --(define_expand "return" -- [(return)] -- "ix86_can_use_return_insn_p ()" -+(define_expand "<return_str>return" -+ [(returns)] -+ "<return_cond>" - { - if (crtl->args.pops_args) - { - rtx popc = GEN_INT (crtl->args.pops_args); -- emit_jump_insn (gen_return_pop_internal (popc)); -+ emit_jump_insn (gen_<return_str>return_pop_internal (popc)); - DONE; - } - }) - --(define_insn "return_internal" -- [(return)] -+(define_insn "<return_str>return_internal" -+ [(returns)] - "reload_completed" - "ret" - [(set_attr "length" "1") -@@ -13825,8 +13830,8 @@ - ;; Used by x86_machine_dependent_reorg to avoid penalty on single byte RET - ;; instruction Athlon and K8 have. - --(define_insn "return_internal_long" -- [(return) -+(define_insn "<return_str>return_internal_long" -+ [(returns) - (unspec [(const_int 0)] UNSPEC_REP)] - "reload_completed" - "rep\;ret" -@@ -13836,8 +13841,8 @@ - (set_attr "prefix_rep" "1") - (set_attr "modrm" "0")]) - --(define_insn "return_pop_internal" -- [(return) -+(define_insn "<return_str>return_pop_internal" -+ [(returns) - (use (match_operand:SI 0 "const_int_operand" ""))] - "reload_completed" - "ret\t%0" -@@ -13846,8 +13851,8 @@ - (set_attr "length_immediate" "2") - (set_attr "modrm" "0")]) - --(define_insn "return_indirect_internal" -- [(return) -+(define_insn "<return_str>return_indirect_internal" -+ [(returns) - (use (match_operand:SI 0 "register_operand" "r"))] - "reload_completed" - "jmp\t%A0" - -=== modified file 'gcc/config/mips/mips.c' ---- old/gcc/config/mips/mips.c 2010-11-21 10:38:43 +0000 -+++ new/gcc/config/mips/mips.c 2011-01-05 12:12:18 +0000 -@@ -10497,7 +10497,8 @@ - regno = GP_REG_FIRST + 7; - else - regno = RETURN_ADDR_REGNUM; -- emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, regno))); -+ emit_jump_insn (gen_simple_return_internal (gen_rtx_REG (Pmode, -+ regno))); - } - } - - -=== modified file 'gcc/config/mips/mips.md' ---- old/gcc/config/mips/mips.md 2010-04-02 18:54:46 +0000 -+++ new/gcc/config/mips/mips.md 2011-01-05 12:12:18 +0000 -@@ -5815,6 +5815,18 @@ - [(set_attr "type" "jump") - (set_attr "mode" "none")]) - -+(define_expand "simple_return" -+ [(simple_return)] -+ "!mips_can_use_return_insn ()" -+ { mips_expand_before_return (); }) -+ -+(define_insn "*simple_return" -+ [(simple_return)] -+ "!mips_can_use_return_insn ()" -+ "%*j\t$31%/" -+ [(set_attr "type" "jump") -+ (set_attr "mode" "none")]) -+ - ;; Normal return. - - (define_insn "return_internal" -@@ -5825,6 +5837,14 @@ - [(set_attr "type" "jump") - (set_attr "mode" "none")]) - -+(define_insn "simple_return_internal" -+ [(simple_return) -+ (use (match_operand 0 "pmode_register_operand" ""))] -+ "" -+ "%*j\t%0%/" -+ [(set_attr "type" "jump") -+ (set_attr "mode" "none")]) -+ - ;; Exception return. - (define_insn "mips_eret" - [(return) - -=== modified file 'gcc/config/sh/sh.c' ---- old/gcc/config/sh/sh.c 2010-12-10 15:34:19 +0000 -+++ new/gcc/config/sh/sh.c 2011-01-05 12:12:18 +0000 -@@ -5252,7 +5252,8 @@ - } - if (prev - && JUMP_P (prev) -- && JUMP_LABEL (prev)) -+ && JUMP_LABEL (prev) -+ && !ANY_RETURN_P (JUMP_LABEL (prev))) - { - rtx x; - if (jump_to_next -@@ -5951,7 +5952,7 @@ - JUMP_LABEL (insn) = far_label; - LABEL_NUSES (far_label)++; - } -- redirect_jump (insn, NULL_RTX, 1); -+ redirect_jump (insn, ret_rtx, 1); - far_label = 0; - } - } - -=== modified file 'gcc/df-scan.c' ---- old/gcc/df-scan.c 2010-11-16 22:17:17 +0000 -+++ new/gcc/df-scan.c 2011-01-05 12:12:18 +0000 -@@ -3296,6 +3296,7 @@ - } - - case RETURN: -+ case SIMPLE_RETURN: - break; - - case ASM_OPERANDS: - -=== modified file 'gcc/doc/invoke.texi' ---- old/gcc/doc/invoke.texi 2010-11-04 14:29:09 +0000 -+++ new/gcc/doc/invoke.texi 2011-01-05 12:12:18 +0000 -@@ -5750,6 +5750,7 @@ - -fipa-pure-const @gol - -fipa-reference @gol - -fmerge-constants -+-fshrink-wrap @gol - -fsplit-wide-types @gol - -ftree-builtin-call-dce @gol - -ftree-ccp @gol -@@ -6504,6 +6505,12 @@ - When pipelining loops during selective scheduling, also pipeline outer loops. - This option has no effect until @option{-fsel-sched-pipelining} is turned on. - -+@item -fshrink-wrap -+@opindex fshrink-wrap -+Emit function prologues only before parts of the function that need it, -+rather than at the top of the function. This flag is enabled by default at -+@option{-O} and higher. -+ - @item -fcaller-saves - @opindex fcaller-saves - Enable values to be allocated in registers that will be clobbered by - -=== modified file 'gcc/doc/md.texi' ---- old/gcc/doc/md.texi 2009-12-15 18:36:44 +0000 -+++ new/gcc/doc/md.texi 2011-01-05 12:12:18 +0000 -@@ -4801,7 +4801,19 @@ - multiple instructions are usually needed to return from a function, but - some class of functions only requires one instruction to implement a - return. Normally, the applicable functions are those which do not need --to save any registers or allocate stack space. -+to save any registers or allocate stack space, although some targets -+have instructions that can perform both the epilogue and function return -+in one instruction. -+ -+@cindex @code{simple_return} instruction pattern -+@item @samp{simple_return} -+Subroutine return instruction. This instruction pattern name should be -+defined only if a single instruction can do all the work of returning -+from a function on a path where no epilogue is required. This pattern -+is very similar to the @code{return} instruction pattern, but it is emitted -+only by the shrink-wrapping optimization on paths where the function -+prologue has not been executed, and a function return should occur without -+any of the effects of the epilogue. - - @findex reload_completed - @findex leaf_function_p - -=== modified file 'gcc/doc/rtl.texi' ---- old/gcc/doc/rtl.texi 2010-07-06 19:23:53 +0000 -+++ new/gcc/doc/rtl.texi 2011-01-05 12:12:18 +0000 -@@ -2888,6 +2888,13 @@ - Note that an insn pattern of @code{(return)} is logically equivalent to - @code{(set (pc) (return))}, but the latter form is never used. - -+@findex simple_return -+@item (simple_return) -+Like @code{(return)}, but truly represents only a function return, while -+@code{(return)} may represent an insn that also performs other functions -+of the function epilogue. Like @code{(return)}, this may also occur in -+conditional jumps. -+ - @findex call - @item (call @var{function} @var{nargs}) - Represents a function call. @var{function} is a @code{mem} expression -@@ -3017,7 +3024,7 @@ - brackets stand for a vector; the operand of @code{parallel} is a - vector of expressions. @var{x0}, @var{x1} and so on are individual - side effect expressions---expressions of code @code{set}, @code{call}, --@code{return}, @code{clobber} or @code{use}. -+@code{return}, @code{simple_return}, @code{clobber} or @code{use}. - - ``In parallel'' means that first all the values used in the individual - side-effects are computed, and second all the actual side-effects are -@@ -3656,14 +3663,16 @@ - @table @code - @findex PATTERN - @item PATTERN (@var{i}) --An expression for the side effect performed by this insn. This must be --one of the following codes: @code{set}, @code{call}, @code{use}, --@code{clobber}, @code{return}, @code{asm_input}, @code{asm_output}, --@code{addr_vec}, @code{addr_diff_vec}, @code{trap_if}, @code{unspec}, --@code{unspec_volatile}, @code{parallel}, @code{cond_exec}, or @code{sequence}. If it is a @code{parallel}, --each element of the @code{parallel} must be one these codes, except that --@code{parallel} expressions cannot be nested and @code{addr_vec} and --@code{addr_diff_vec} are not permitted inside a @code{parallel} expression. -+An expression for the side effect performed by this insn. This must -+be one of the following codes: @code{set}, @code{call}, @code{use}, -+@code{clobber}, @code{return}, @code{simple_return}, @code{asm_input}, -+@code{asm_output}, @code{addr_vec}, @code{addr_diff_vec}, -+@code{trap_if}, @code{unspec}, @code{unspec_volatile}, -+@code{parallel}, @code{cond_exec}, or @code{sequence}. If it is a -+@code{parallel}, each element of the @code{parallel} must be one these -+codes, except that @code{parallel} expressions cannot be nested and -+@code{addr_vec} and @code{addr_diff_vec} are not permitted inside a -+@code{parallel} expression. - - @findex INSN_CODE - @item INSN_CODE (@var{i}) - -=== modified file 'gcc/doc/tm.texi' ---- old/gcc/doc/tm.texi 2010-09-01 13:29:58 +0000 -+++ new/gcc/doc/tm.texi 2011-01-05 12:12:18 +0000 -@@ -3287,6 +3287,12 @@ - from the frame pointer of the previous stack frame. - @end defmac - -+@defmac RETURN_ADDR_REGNUM -+If defined, a C expression whose value is the register number of the return -+address for the current function. Targets that pass the return address on -+the stack should not define this macro. -+@end defmac -+ - @defmac INCOMING_RETURN_ADDR_RTX - A C expression whose value is RTL representing the location of the - incoming return address at the beginning of any function, before the - -=== modified file 'gcc/dwarf2out.c' ---- old/gcc/dwarf2out.c 2010-12-21 18:46:10 +0000 -+++ new/gcc/dwarf2out.c 2011-01-05 12:12:18 +0000 -@@ -1396,7 +1396,7 @@ - { - rtx dest = JUMP_LABEL (insn); - -- if (dest) -+ if (dest && !ANY_RETURN_P (dest)) - { - if (barrier_args_size [INSN_UID (dest)] < 0) - { - -=== modified file 'gcc/emit-rtl.c' ---- old/gcc/emit-rtl.c 2010-10-04 00:50:43 +0000 -+++ new/gcc/emit-rtl.c 2011-01-05 12:12:18 +0000 -@@ -2432,6 +2432,8 @@ - case CODE_LABEL: - case PC: - case CC0: -+ case RETURN: -+ case SIMPLE_RETURN: - case SCRATCH: - return; - /* SCRATCH must be shared because they represent distinct values. */ -@@ -3323,14 +3325,17 @@ - return insn; - } - --/* Return the last label to mark the same position as LABEL. Return null -- if LABEL itself is null. */ -+/* Return the last label to mark the same position as LABEL. Return LABEL -+ itself if it is null or any return rtx. */ - - rtx - skip_consecutive_labels (rtx label) - { - rtx insn; - -+ if (label && ANY_RETURN_P (label)) -+ return label; -+ - for (insn = label; insn != 0 && !INSN_P (insn); insn = NEXT_INSN (insn)) - if (LABEL_P (insn)) - label = insn; -@@ -5209,7 +5214,7 @@ - return CODE_LABEL; - if (GET_CODE (x) == CALL) - return CALL_INSN; -- if (GET_CODE (x) == RETURN) -+ if (GET_CODE (x) == RETURN || GET_CODE (x) == SIMPLE_RETURN) - return JUMP_INSN; - if (GET_CODE (x) == SET) - { -@@ -5715,8 +5720,10 @@ - init_reg_modes_target (); - - /* Assign register numbers to the globally defined register rtx. */ -- pc_rtx = gen_rtx_PC (VOIDmode); -- cc0_rtx = gen_rtx_CC0 (VOIDmode); -+ pc_rtx = gen_rtx_fmt_ (PC, VOIDmode); -+ ret_rtx = gen_rtx_fmt_ (RETURN, VOIDmode); -+ simple_return_rtx = gen_rtx_fmt_ (SIMPLE_RETURN, VOIDmode); -+ cc0_rtx = gen_rtx_fmt_ (CC0, VOIDmode); - stack_pointer_rtx = gen_raw_REG (Pmode, STACK_POINTER_REGNUM); - frame_pointer_rtx = gen_raw_REG (Pmode, FRAME_POINTER_REGNUM); - hard_frame_pointer_rtx = gen_raw_REG (Pmode, HARD_FRAME_POINTER_REGNUM); - -=== modified file 'gcc/final.c' ---- old/gcc/final.c 2010-03-26 16:18:51 +0000 -+++ new/gcc/final.c 2011-01-05 12:12:18 +0000 -@@ -2428,7 +2428,7 @@ - delete_insn (insn); - break; - } -- else if (GET_CODE (SET_SRC (body)) == RETURN) -+ else if (ANY_RETURN_P (SET_SRC (body))) - /* Replace (set (pc) (return)) with (return). */ - PATTERN (insn) = body = SET_SRC (body); - - -=== modified file 'gcc/function.c' ---- old/gcc/function.c 2010-08-16 19:18:08 +0000 -+++ new/gcc/function.c 2011-01-05 12:12:18 +0000 -@@ -147,9 +147,6 @@ - can always export `prologue_epilogue_contains'. */ - static void record_insns (rtx, rtx, htab_t *) ATTRIBUTE_UNUSED; - static bool contains (const_rtx, htab_t); --#ifdef HAVE_return --static void emit_return_into_block (basic_block); --#endif - static void prepare_function_start (void); - static void do_clobber_return_reg (rtx, void *); - static void do_use_return_reg (rtx, void *); -@@ -4987,35 +4984,189 @@ - return 0; - } - -+#ifdef HAVE_simple_return -+/* This collects sets and clobbers of hard registers in a HARD_REG_SET, -+ which is pointed to by DATA. */ -+static void -+record_hard_reg_sets (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data) -+{ -+ HARD_REG_SET *pset = (HARD_REG_SET *)data; -+ if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER) -+ { -+ int nregs = hard_regno_nregs[REGNO (x)][GET_MODE (x)]; -+ while (nregs-- > 0) -+ SET_HARD_REG_BIT (*pset, REGNO (x) + nregs); -+ } -+} -+ -+/* A subroutine of requires_stack_frame_p, called via for_each_rtx. -+ If any change is made, set CHANGED -+ to true. */ -+ -+static int -+frame_required_for_rtx (rtx *loc, void *data ATTRIBUTE_UNUSED) -+{ -+ rtx x = *loc; -+ if (x == stack_pointer_rtx || x == hard_frame_pointer_rtx -+ || x == arg_pointer_rtx || x == pic_offset_table_rtx -+#ifdef RETURN_ADDR_REGNUM -+ || (REG_P (x) && REGNO (x) == RETURN_ADDR_REGNUM) -+#endif -+ ) -+ return 1; -+ return 0; -+} -+ -+static bool -+requires_stack_frame_p (rtx insn) -+{ -+ HARD_REG_SET hardregs; -+ unsigned regno; -+ -+ if (!INSN_P (insn) || DEBUG_INSN_P (insn)) -+ return false; -+ if (CALL_P (insn)) -+ return !SIBLING_CALL_P (insn); -+ if (for_each_rtx (&PATTERN (insn), frame_required_for_rtx, NULL)) -+ return true; -+ CLEAR_HARD_REG_SET (hardregs); -+ note_stores (PATTERN (insn), record_hard_reg_sets, &hardregs); -+ AND_COMPL_HARD_REG_SET (hardregs, call_used_reg_set); -+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) -+ if (TEST_HARD_REG_BIT (hardregs, regno) -+ && df_regs_ever_live_p (regno)) -+ return true; -+ return false; -+} -+#endif -+ - #ifdef HAVE_return --/* Insert gen_return at the end of block BB. This also means updating -- block_for_insn appropriately. */ -+ -+static rtx -+gen_return_pattern (bool simple_p) -+{ -+#ifdef HAVE_simple_return -+ return simple_p ? gen_simple_return () : gen_return (); -+#else -+ gcc_assert (!simple_p); -+ return gen_return (); -+#endif -+} -+ -+/* Insert an appropriate return pattern at the end of block BB. This -+ also means updating block_for_insn appropriately. */ - - static void --emit_return_into_block (basic_block bb) -+emit_return_into_block (bool simple_p, basic_block bb) - { -- emit_jump_insn_after (gen_return (), BB_END (bb)); -+ rtx jump; -+ jump = emit_jump_insn_after (gen_return_pattern (simple_p), BB_END (bb)); -+ JUMP_LABEL (jump) = simple_p ? simple_return_rtx : ret_rtx; - } --#endif /* HAVE_return */ -+#endif - - /* 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. */ -+ the epilogue begins. Update the basic block information when possible. -+ -+ Notes on epilogue placement: -+ There are several kinds of edges to the exit block: -+ * a single fallthru edge from LAST_BB -+ * possibly, edges from blocks containing sibcalls -+ * possibly, fake edges from infinite loops -+ -+ The epilogue is always emitted on the fallthru edge from the last basic -+ block in the function, LAST_BB, into the exit block. -+ -+ If LAST_BB is empty except for a label, it is the target of every -+ other basic block in the function that ends in a return. If a -+ target has a return or simple_return pattern (possibly with -+ conditional variants), these basic blocks can be changed so that a -+ return insn is emitted into them, and their target is adjusted to -+ the real exit block. -+ -+ Notes on shrink wrapping: We implement a fairly conservative -+ version of shrink-wrapping rather than the textbook one. We only -+ generate a single prologue and a single epilogue. This is -+ sufficient to catch a number of interesting cases involving early -+ exits. -+ -+ First, we identify the blocks that require the prologue to occur before -+ them. These are the ones that modify a call-saved register, or reference -+ any of the stack or frame pointer registers. To simplify things, we then -+ mark everything reachable from these blocks as also requiring a prologue. -+ This takes care of loops automatically, and avoids the need to examine -+ whether MEMs reference the frame, since it is sufficient to check for -+ occurrences of the stack or frame pointer. -+ -+ We then compute the set of blocks for which the need for a prologue -+ is anticipatable (borrowing terminology from the shrink-wrapping -+ description in Muchnick's book). These are the blocks which either -+ require a prologue themselves, or those that have only successors -+ where the prologue is anticipatable. The prologue needs to be -+ inserted on all edges from BB1->BB2 where BB2 is in ANTIC and BB1 -+ is not. For the moment, we ensure that only one such edge exists. -+ -+ The epilogue is placed as described above, but we make a -+ distinction between inserting return and simple_return patterns -+ when modifying other blocks that end in a return. Blocks that end -+ in a sibcall omit the sibcall_epilogue if the block is not in -+ ANTIC. */ - - static void - thread_prologue_and_epilogue_insns (void) - { - int inserted = 0; -+ basic_block last_bb; -+ bool last_bb_active; -+#ifdef HAVE_simple_return -+ bool unconverted_simple_returns = false; -+ basic_block simple_return_block = NULL; -+#endif -+ rtx returnjump ATTRIBUTE_UNUSED; -+ rtx seq ATTRIBUTE_UNUSED, epilogue_end ATTRIBUTE_UNUSED; -+ rtx prologue_seq ATTRIBUTE_UNUSED, split_prologue_seq ATTRIBUTE_UNUSED; -+ edge entry_edge, orig_entry_edge, exit_fallthru_edge; - edge e; --#if defined (HAVE_sibcall_epilogue) || defined (HAVE_epilogue) || defined (HAVE_return) || defined (HAVE_prologue) -- rtx seq; --#endif --#if defined (HAVE_epilogue) || defined(HAVE_return) -- rtx epilogue_end = NULL_RTX; --#endif - edge_iterator ei; -+ bitmap_head bb_flags; -+ -+ df_analyze (); - - rtl_profile_for_bb (ENTRY_BLOCK_PTR); -+ -+ epilogue_end = NULL_RTX; -+ -+ /* Can't deal with multiple successors of the entry block at the -+ moment. Function should always have at least one entry -+ point. */ -+ gcc_assert (single_succ_p (ENTRY_BLOCK_PTR)); -+ entry_edge = single_succ_edge (ENTRY_BLOCK_PTR); -+ orig_entry_edge = entry_edge; -+ -+ 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); -+ } -+ else -+ { -+ last_bb = NULL; -+ last_bb_active = false; -+ } -+ - #ifdef HAVE_prologue - if (HAVE_prologue) - { -@@ -5040,19 +5191,168 @@ - emit_insn (gen_blockage ()); - #endif - -- seq = get_insns (); -+ prologue_seq = get_insns (); - end_sequence (); - set_insn_locators (seq, prologue_locator); -- -- /* Can't deal with multiple successors of the entry block -- at the moment. Function should always have at least one -- entry point. */ -- gcc_assert (single_succ_p (ENTRY_BLOCK_PTR)); -- -- insert_insn_on_edge (seq, single_succ_edge (ENTRY_BLOCK_PTR)); -- inserted = 1; -- } --#endif -+ } -+#endif -+ -+ bitmap_initialize (&bb_flags, &bitmap_default_obstack); -+ -+#ifdef HAVE_simple_return -+ /* Try to perform a kind of shrink-wrapping, making sure the -+ prologue/epilogue is emitted only around those parts of the -+ function that require it. */ -+ -+ if (flag_shrink_wrap && HAVE_simple_return && !flag_non_call_exceptions -+ && HAVE_prologue && !crtl->calls_eh_return) -+ { -+ HARD_REG_SET prologue_clobbered, live_on_edge; -+ rtx p_insn; -+ VEC(basic_block, heap) *vec; -+ basic_block bb; -+ bitmap_head bb_antic_flags; -+ bitmap_head bb_on_list; -+ -+ bitmap_initialize (&bb_antic_flags, &bitmap_default_obstack); -+ bitmap_initialize (&bb_on_list, &bitmap_default_obstack); -+ -+ vec = VEC_alloc (basic_block, heap, n_basic_blocks); -+ -+ FOR_EACH_BB (bb) -+ { -+ rtx insn; -+ FOR_BB_INSNS (bb, insn) -+ { -+ if (requires_stack_frame_p (insn)) -+ { -+ bitmap_set_bit (&bb_flags, bb->index); -+ VEC_quick_push (basic_block, vec, bb); -+ break; -+ } -+ } -+ } -+ -+ /* For every basic block that needs a prologue, mark all blocks -+ reachable from it, so as to ensure they are also seen as -+ requiring a prologue. */ -+ while (!VEC_empty (basic_block, vec)) -+ { -+ basic_block tmp_bb = VEC_pop (basic_block, vec); -+ edge e; -+ edge_iterator ei; -+ FOR_EACH_EDGE (e, ei, tmp_bb->succs) -+ { -+ if (e->dest == EXIT_BLOCK_PTR -+ || bitmap_bit_p (&bb_flags, e->dest->index)) -+ continue; -+ bitmap_set_bit (&bb_flags, e->dest->index); -+ VEC_quick_push (basic_block, vec, e->dest); -+ } -+ } -+ /* If the last basic block contains only a label, we'll be able -+ to convert jumps to it to (potentially conditional) return -+ insns later. This means we don't necessarily need a prologue -+ for paths reaching it. */ -+ if (last_bb) -+ { -+ if (!last_bb_active) -+ bitmap_clear_bit (&bb_flags, last_bb->index); -+ else if (!bitmap_bit_p (&bb_flags, last_bb->index)) -+ goto fail_shrinkwrap; -+ } -+ -+ /* Now walk backwards from every block that is marked as needing -+ a prologue to compute the bb_antic_flags bitmap. */ -+ bitmap_copy (&bb_antic_flags, &bb_flags); -+ FOR_EACH_BB (bb) -+ { -+ edge e; -+ edge_iterator ei; -+ if (!bitmap_bit_p (&bb_flags, bb->index)) -+ continue; -+ FOR_EACH_EDGE (e, ei, bb->preds) -+ if (!bitmap_bit_p (&bb_antic_flags, e->src->index)) -+ { -+ VEC_quick_push (basic_block, vec, e->src); -+ bitmap_set_bit (&bb_on_list, e->src->index); -+ } -+ } -+ while (!VEC_empty (basic_block, vec)) -+ { -+ basic_block tmp_bb = VEC_pop (basic_block, vec); -+ edge e; -+ edge_iterator ei; -+ bool all_set = true; -+ -+ bitmap_clear_bit (&bb_on_list, tmp_bb->index); -+ FOR_EACH_EDGE (e, ei, tmp_bb->succs) -+ { -+ if (!bitmap_bit_p (&bb_antic_flags, e->dest->index)) -+ { -+ all_set = false; -+ break; -+ } -+ } -+ if (all_set) -+ { -+ bitmap_set_bit (&bb_antic_flags, tmp_bb->index); -+ FOR_EACH_EDGE (e, ei, tmp_bb->preds) -+ if (!bitmap_bit_p (&bb_antic_flags, e->src->index)) -+ { -+ VEC_quick_push (basic_block, vec, e->src); -+ bitmap_set_bit (&bb_on_list, e->src->index); -+ } -+ } -+ } -+ /* Find exactly one edge that leads to a block in ANTIC from -+ a block that isn't. */ -+ if (!bitmap_bit_p (&bb_antic_flags, entry_edge->dest->index)) -+ FOR_EACH_BB (bb) -+ { -+ if (!bitmap_bit_p (&bb_antic_flags, bb->index)) -+ continue; -+ FOR_EACH_EDGE (e, ei, bb->preds) -+ if (!bitmap_bit_p (&bb_antic_flags, e->src->index)) -+ { -+ if (entry_edge != orig_entry_edge) -+ { -+ entry_edge = orig_entry_edge; -+ goto fail_shrinkwrap; -+ } -+ entry_edge = e; -+ } -+ } -+ -+ /* Test whether the prologue is known to clobber any register -+ (other than FP or SP) which are live on the edge. */ -+ CLEAR_HARD_REG_SET (prologue_clobbered); -+ for (p_insn = prologue_seq; p_insn; p_insn = NEXT_INSN (p_insn)) -+ if (NONDEBUG_INSN_P (p_insn)) -+ note_stores (PATTERN (p_insn), record_hard_reg_sets, -+ &prologue_clobbered); -+ CLEAR_HARD_REG_BIT (prologue_clobbered, STACK_POINTER_REGNUM); -+ if (frame_pointer_needed) -+ CLEAR_HARD_REG_BIT (prologue_clobbered, HARD_FRAME_POINTER_REGNUM); -+ -+ CLEAR_HARD_REG_SET (live_on_edge); -+ reg_set_to_hard_reg_set (&live_on_edge, -+ df_get_live_in (entry_edge->dest)); -+ if (hard_reg_set_intersect_p (live_on_edge, prologue_clobbered)) -+ entry_edge = orig_entry_edge; -+ -+ fail_shrinkwrap: -+ bitmap_clear (&bb_antic_flags); -+ bitmap_clear (&bb_on_list); -+ VEC_free (basic_block, heap, vec); -+ } -+#endif -+ -+ if (prologue_seq != NULL_RTX) -+ { -+ insert_insn_on_edge (prologue_seq, entry_edge); -+ inserted = true; -+ } - - /* If the exit block has no non-fake predecessors, we don't need - an epilogue. */ -@@ -5063,100 +5363,130 @@ - goto epilogue_done; - - rtl_profile_for_bb (EXIT_BLOCK_PTR); -+ - #ifdef HAVE_return -- if (optimize && HAVE_return) -+ /* If we're allowed to generate a simple return instruction, then by -+ definition we don't need a full epilogue. If the last basic -+ block before the exit block does not contain active instructions, -+ examine its predecessors and try to emit (conditional) return -+ instructions. */ -+ if (optimize && !last_bb_active -+ && (HAVE_return || entry_edge != orig_entry_edge)) - { -- /* If we're allowed to generate a simple return instruction, -- then by definition we don't need a full epilogue. Examine -- the block that falls through to EXIT. If it does not -- contain any code, examine its predecessors and try to -- emit (conditional) return instructions. */ -- -- basic_block last; -+ edge_iterator ei2; -+ int i; -+ basic_block bb; - rtx label; -+ VEC(basic_block,heap) *src_bbs; - -- FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds) -- if (e->flags & EDGE_FALLTHRU) -- break; -- if (e == NULL) -+ if (exit_fallthru_edge == NULL) - goto epilogue_done; -- last = e->src; -- -- /* Verify that there are no active instructions in the last block. */ -- label = BB_END (last); -- while (label && !LABEL_P (label)) -+ label = BB_HEAD (last_bb); -+ -+ src_bbs = VEC_alloc (basic_block, heap, EDGE_COUNT (last_bb->preds)); -+ FOR_EACH_EDGE (e, ei2, last_bb->preds) -+ if (e->src != ENTRY_BLOCK_PTR) -+ VEC_quick_push (basic_block, src_bbs, e->src); -+ -+ FOR_EACH_VEC_ELT (basic_block, src_bbs, i, bb) - { -- if (active_insn_p (label)) -- break; -- label = PREV_INSN (label); -+ bool simple_p; -+ rtx jump; -+ e = find_edge (bb, last_bb); -+ -+ jump = BB_END (bb); -+ -+#ifdef HAVE_simple_return -+ simple_p = (entry_edge != orig_entry_edge -+ ? !bitmap_bit_p (&bb_flags, bb->index) : false); -+#else -+ simple_p = false; -+#endif -+ -+ if (!simple_p -+ && (!HAVE_return || !JUMP_P (jump) -+ || JUMP_LABEL (jump) != label)) -+ continue; -+ -+ /* If we have an unconditional jump, we can replace that -+ with a simple return instruction. */ -+ if (!JUMP_P (jump)) -+ { -+ emit_barrier_after (BB_END (bb)); -+ emit_return_into_block (simple_p, bb); -+ } -+ else if (simplejump_p (jump)) -+ { -+ emit_return_into_block (simple_p, bb); -+ delete_insn (jump); -+ } -+ else if (condjump_p (jump) && JUMP_LABEL (jump) != label) -+ { -+ basic_block new_bb; -+ edge new_e; -+ -+ gcc_assert (simple_p); -+ new_bb = split_edge (e); -+ emit_barrier_after (BB_END (new_bb)); -+ emit_return_into_block (simple_p, new_bb); -+#ifdef HAVE_simple_return -+ simple_return_block = new_bb; -+#endif -+ new_e = single_succ_edge (new_bb); -+ redirect_edge_succ (new_e, EXIT_BLOCK_PTR); -+ -+ continue; -+ } -+ /* If we have a conditional jump branching to the last -+ block, we can try to replace that with a conditional -+ return instruction. */ -+ else if (condjump_p (jump)) -+ { -+ rtx dest; -+ if (simple_p) -+ dest = simple_return_rtx; -+ else -+ dest = ret_rtx; -+ if (! redirect_jump (jump, dest, 0)) -+ { -+#ifdef HAVE_simple_return -+ if (simple_p) -+ unconverted_simple_returns = true; -+#endif -+ continue; -+ } -+ -+ /* If this block has only one successor, it both jumps -+ and falls through to the fallthru block, so we can't -+ delete the edge. */ -+ if (single_succ_p (bb)) -+ continue; -+ } -+ else -+ { -+#ifdef HAVE_simple_return -+ if (simple_p) -+ unconverted_simple_returns = true; -+#endif -+ continue; -+ } -+ -+ /* Fix up the CFG for the successful change we just made. */ -+ redirect_edge_succ (e, EXIT_BLOCK_PTR); - } -+ VEC_free (basic_block, heap, src_bbs); - -- if (BB_HEAD (last) == label && LABEL_P (label)) -+ if (HAVE_return) - { -- edge_iterator ei2; -- -- for (ei2 = ei_start (last->preds); (e = ei_safe_edge (ei2)); ) -- { -- basic_block bb = e->src; -- rtx jump; -- -- if (bb == ENTRY_BLOCK_PTR) -- { -- ei_next (&ei2); -- continue; -- } -- -- jump = BB_END (bb); -- if (!JUMP_P (jump) || JUMP_LABEL (jump) != label) -- { -- ei_next (&ei2); -- continue; -- } -- -- /* If we have an unconditional jump, we can replace that -- with a simple return instruction. */ -- if (simplejump_p (jump)) -- { -- emit_return_into_block (bb); -- delete_insn (jump); -- } -- -- /* If we have a conditional jump, we can try to replace -- that with a conditional return instruction. */ -- else if (condjump_p (jump)) -- { -- if (! redirect_jump (jump, 0, 0)) -- { -- ei_next (&ei2); -- continue; -- } -- -- /* If this block has only one successor, it both jumps -- and falls through to the fallthru block, so we can't -- delete the edge. */ -- if (single_succ_p (bb)) -- { -- ei_next (&ei2); -- continue; -- } -- } -- else -- { -- ei_next (&ei2); -- continue; -- } -- -- /* Fix up the CFG for the successful change we just made. */ -- redirect_edge_succ (e, EXIT_BLOCK_PTR); -- } -- - /* Emit a return insn for the exit fallthru block. Whether - this is still reachable will be determined later. */ - -- emit_barrier_after (BB_END (last)); -- emit_return_into_block (last); -- epilogue_end = BB_END (last); -- single_succ_edge (last)->flags &= ~EDGE_FALLTHRU; -+ emit_barrier_after (BB_END (last_bb)); -+ emit_return_into_block (false, last_bb); -+ epilogue_end = BB_END (last_bb); -+ if (JUMP_P (epilogue_end)) -+ JUMP_LABEL (epilogue_end) = ret_rtx; -+ single_succ_edge (last_bb)->flags &= ~EDGE_FALLTHRU; - goto epilogue_done; - } - } -@@ -5193,15 +5523,10 @@ - } - #endif - -- /* Find the edge that falls through to EXIT. Other edges may exist -- due to RETURN instructions, but those don't need epilogues. -- There really shouldn't be a mixture -- either all should have -- been converted or none, however... */ -+ /* If nothing falls through into the exit block, we don't need an -+ epilogue. */ - -- FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds) -- if (e->flags & EDGE_FALLTHRU) -- break; -- if (e == NULL) -+ if (exit_fallthru_edge == NULL) - goto epilogue_done; - - #ifdef HAVE_epilogue -@@ -5217,25 +5542,38 @@ - set_insn_locators (seq, epilogue_locator); - - seq = get_insns (); -+ returnjump = get_last_insn (); - end_sequence (); - -- insert_insn_on_edge (seq, e); -+ insert_insn_on_edge (seq, exit_fallthru_edge); - inserted = 1; -+ if (JUMP_P (returnjump)) -+ { -+ rtx pat = PATTERN (returnjump); -+ if (GET_CODE (pat) == PARALLEL) -+ pat = XVECEXP (pat, 0, 0); -+ if (ANY_RETURN_P (pat)) -+ JUMP_LABEL (returnjump) = pat; -+ else -+ JUMP_LABEL (returnjump) = ret_rtx; -+ } -+ else -+ returnjump = NULL_RTX; - } - else - #endif - { - basic_block cur_bb; - -- if (! next_active_insn (BB_END (e->src))) -+ if (! next_active_insn (BB_END (exit_fallthru_edge->src))) - goto epilogue_done; - /* We have a fall-through edge to the exit block, the source is not -- at the end of the function, and there will be an assembler epilogue -- at the end of the function. -- We can't use force_nonfallthru here, because that would try to -- use return. Inserting a jump 'by hand' is extremely messy, so -+ at the end of the function, and there will be an assembler epilogue -+ at the end of the function. -+ We can't use force_nonfallthru here, because that would try to -+ use return. Inserting a jump 'by hand' is extremely messy, so - we take advantage of cfg_layout_finalize using -- fixup_fallthru_exit_predecessor. */ -+ fixup_fallthru_exit_predecessor. */ - cfg_layout_initialize (0); - FOR_EACH_BB (cur_bb) - if (cur_bb->index >= NUM_FIXED_BLOCKS -@@ -5244,6 +5582,7 @@ - cfg_layout_finalize (); - } - epilogue_done: -+ - default_rtl_profile (); - - if (inserted) -@@ -5260,33 +5599,93 @@ - } - } - -+#ifdef HAVE_simple_return -+ /* If there were branches to an empty LAST_BB which we tried to -+ convert to conditional simple_returns, but couldn't for some -+ reason, create a block to hold a simple_return insn and redirect -+ those remaining edges. */ -+ if (unconverted_simple_returns) -+ { -+ edge_iterator ei2; -+ basic_block exit_pred = EXIT_BLOCK_PTR->prev_bb; -+ -+ gcc_assert (entry_edge != orig_entry_edge); -+ -+#ifdef HAVE_epilogue -+ if (simple_return_block == NULL && returnjump != NULL_RTX -+ && JUMP_LABEL (returnjump) == simple_return_rtx) -+ { -+ edge e = split_block (exit_fallthru_edge->src, -+ PREV_INSN (returnjump)); -+ simple_return_block = e->dest; -+ } -+#endif -+ if (simple_return_block == NULL) -+ { -+ basic_block bb; -+ rtx start; -+ -+ bb = create_basic_block (NULL, NULL, exit_pred); -+ start = emit_jump_insn_after (gen_simple_return (), -+ BB_END (bb)); -+ JUMP_LABEL (start) = simple_return_rtx; -+ emit_barrier_after (start); -+ -+ simple_return_block = bb; -+ make_edge (bb, EXIT_BLOCK_PTR, 0); -+ } -+ -+ restart_scan: -+ for (ei2 = ei_start (last_bb->preds); (e = ei_safe_edge (ei2)); ) -+ { -+ basic_block bb = e->src; -+ -+ if (bb != ENTRY_BLOCK_PTR -+ && !bitmap_bit_p (&bb_flags, bb->index)) -+ { -+ redirect_edge_and_branch_force (e, simple_return_block); -+ goto restart_scan; -+ } -+ ei_next (&ei2); -+ -+ } -+ } -+#endif -+ - #ifdef HAVE_sibcall_epilogue - /* Emit sibling epilogues before any sibling call sites. */ - for (ei = ei_start (EXIT_BLOCK_PTR->preds); (e = ei_safe_edge (ei)); ) - { - basic_block bb = e->src; - rtx insn = BB_END (bb); -+ rtx ep_seq; - - if (!CALL_P (insn) -- || ! SIBLING_CALL_P (insn)) -+ || ! SIBLING_CALL_P (insn) -+ || (entry_edge != orig_entry_edge -+ && !bitmap_bit_p (&bb_flags, bb->index))) - { - ei_next (&ei); - continue; - } - -- start_sequence (); -- emit_note (NOTE_INSN_EPILOGUE_BEG); -- emit_insn (gen_sibcall_epilogue ()); -- seq = get_insns (); -- end_sequence (); -- -- /* Retain a map of the epilogue insns. Used in life analysis to -- avoid getting rid of sibcall epilogue insns. Do this before we -- actually emit the sequence. */ -- record_insns (seq, NULL, &epilogue_insn_hash); -- set_insn_locators (seq, epilogue_locator); -- -- emit_insn_before (seq, insn); -+ ep_seq = gen_sibcall_epilogue (); -+ if (ep_seq) -+ { -+ start_sequence (); -+ emit_note (NOTE_INSN_EPILOGUE_BEG); -+ emit_insn (ep_seq); -+ seq = get_insns (); -+ end_sequence (); -+ -+ /* Retain a map of the epilogue insns. Used in life analysis to -+ avoid getting rid of sibcall epilogue insns. Do this before we -+ actually emit the sequence. */ -+ record_insns (seq, NULL, &epilogue_insn_hash); -+ set_insn_locators (seq, epilogue_locator); -+ -+ emit_insn_before (seq, insn); -+ } - ei_next (&ei); - } - #endif -@@ -5311,6 +5710,8 @@ - } - #endif - -+ bitmap_clear (&bb_flags); -+ - /* Threading the prologue and epilogue changes the artificial refs - in the entry and exit blocks. */ - epilogue_completed = 1; - -=== modified file 'gcc/genemit.c' ---- old/gcc/genemit.c 2009-11-27 11:37:06 +0000 -+++ new/gcc/genemit.c 2011-01-05 12:12:18 +0000 -@@ -222,6 +222,12 @@ - case PC: - printf ("pc_rtx"); - return; -+ case RETURN: -+ printf ("ret_rtx"); -+ return; -+ case SIMPLE_RETURN: -+ printf ("simple_return_rtx"); -+ return; - case CLOBBER: - if (REG_P (XEXP (x, 0))) - { -@@ -544,8 +550,8 @@ - || (GET_CODE (next) == PARALLEL - && ((GET_CODE (XVECEXP (next, 0, 0)) == SET - && GET_CODE (SET_DEST (XVECEXP (next, 0, 0))) == PC) -- || GET_CODE (XVECEXP (next, 0, 0)) == RETURN)) -- || GET_CODE (next) == RETURN) -+ || ANY_RETURN_P (XVECEXP (next, 0, 0)))) -+ || ANY_RETURN_P (next)) - printf (" emit_jump_insn ("); - else if ((GET_CODE (next) == SET && GET_CODE (SET_SRC (next)) == CALL) - || GET_CODE (next) == CALL -@@ -660,7 +666,7 @@ - || (GET_CODE (next) == PARALLEL - && GET_CODE (XVECEXP (next, 0, 0)) == SET - && GET_CODE (SET_DEST (XVECEXP (next, 0, 0))) == PC) -- || GET_CODE (next) == RETURN) -+ || ANY_RETURN_P (next)) - printf (" emit_jump_insn ("); - else if ((GET_CODE (next) == SET && GET_CODE (SET_SRC (next)) == CALL) - || GET_CODE (next) == CALL - -=== modified file 'gcc/gengenrtl.c' ---- old/gcc/gengenrtl.c 2007-08-22 23:30:39 +0000 -+++ new/gcc/gengenrtl.c 2011-01-05 12:12:18 +0000 -@@ -146,6 +146,10 @@ - || strcmp (defs[idx].enumname, "REG") == 0 - || strcmp (defs[idx].enumname, "SUBREG") == 0 - || strcmp (defs[idx].enumname, "MEM") == 0 -+ || strcmp (defs[idx].enumname, "PC") == 0 -+ || strcmp (defs[idx].enumname, "CC0") == 0 -+ || strcmp (defs[idx].enumname, "RETURN") == 0 -+ || strcmp (defs[idx].enumname, "SIMPLE_RETURN") == 0 - || strcmp (defs[idx].enumname, "CONST_VECTOR") == 0); - } - - -=== modified file 'gcc/haifa-sched.c' ---- old/gcc/haifa-sched.c 2010-08-12 08:14:47 +0000 -+++ new/gcc/haifa-sched.c 2011-01-05 12:12:18 +0000 -@@ -4231,7 +4231,7 @@ - /* Helper function. - Find fallthru edge from PRED. */ - edge --find_fallthru_edge (basic_block pred) -+find_fallthru_edge_from (basic_block pred) - { - edge e; - edge_iterator ei; -@@ -4298,7 +4298,7 @@ - edge e; - - last = EXIT_BLOCK_PTR->prev_bb; -- e = find_fallthru_edge (last); -+ e = find_fallthru_edge_from (last); - - if (e) - { -@@ -5234,6 +5234,11 @@ - gcc_assert (/* Usual case. */ - (EDGE_COUNT (bb->succs) > 1 - && !BARRIER_P (NEXT_INSN (head))) -+ /* Special cases, see cfglayout.c: -+ fixup_reorder_chain. */ -+ || (EDGE_COUNT (bb->succs) == 1 -+ && (!onlyjump_p (head) -+ || returnjump_p (head))) - /* Or jump to the next instruction. */ - || (EDGE_COUNT (bb->succs) == 1 - && (BB_HEAD (EDGE_I (bb->succs, 0)->dest) - -=== modified file 'gcc/ifcvt.c' ---- old/gcc/ifcvt.c 2010-11-26 12:03:32 +0000 -+++ new/gcc/ifcvt.c 2011-01-05 12:12:18 +0000 -@@ -105,7 +105,7 @@ - static int find_if_case_2 (basic_block, edge, edge); - static int find_memory (rtx *, void *); - static int dead_or_predicable (basic_block, basic_block, basic_block, -- basic_block, int); -+ edge, int); - static void noce_emit_move_insn (rtx, rtx); - static rtx block_has_only_trap (basic_block); - -@@ -3791,6 +3791,7 @@ - basic_block then_bb = then_edge->dest; - basic_block else_bb = else_edge->dest; - basic_block new_bb; -+ rtx else_target = NULL_RTX; - int then_bb_index; - - /* If we are partitioning hot/cold basic blocks, we don't want to -@@ -3840,9 +3841,16 @@ - predictable_edge_p (then_edge))))) - return FALSE; - -+ if (else_bb == EXIT_BLOCK_PTR) -+ { -+ rtx jump = BB_END (else_edge->src); -+ gcc_assert (JUMP_P (jump)); -+ else_target = JUMP_LABEL (jump); -+ } -+ - /* Registers set are dead, or are predicable. */ - if (! dead_or_predicable (test_bb, then_bb, else_bb, -- single_succ (then_bb), 1)) -+ single_succ_edge (then_bb), 1)) - return FALSE; - - /* Conversion went ok, including moving the insns and fixing up the -@@ -3859,6 +3867,9 @@ - redirect_edge_succ (FALLTHRU_EDGE (test_bb), else_bb); - new_bb = 0; - } -+ else if (else_bb == EXIT_BLOCK_PTR) -+ new_bb = force_nonfallthru_and_redirect (FALLTHRU_EDGE (test_bb), -+ else_bb, else_target); - else - new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb), - else_bb); -@@ -3957,7 +3968,7 @@ - return FALSE; - - /* Registers set are dead, or are predicable. */ -- if (! dead_or_predicable (test_bb, else_bb, then_bb, else_succ->dest, 0)) -+ if (! dead_or_predicable (test_bb, else_bb, then_bb, else_succ, 0)) - return FALSE; - - /* Conversion went ok, including moving the insns and fixing up the -@@ -3995,12 +4006,34 @@ - - static int - dead_or_predicable (basic_block test_bb, basic_block merge_bb, -- basic_block other_bb, basic_block new_dest, int reversep) -+ basic_block other_bb, edge dest_edge, int reversep) - { -- rtx head, end, jump, earliest = NULL_RTX, old_dest, new_label = NULL_RTX; -+ basic_block new_dest = dest_edge->dest; -+ rtx head, end, jump, earliest = NULL_RTX, old_dest; - bitmap merge_set = NULL; - /* Number of pending changes. */ - int n_validated_changes = 0; -+ rtx new_dest_label; -+ -+ jump = BB_END (dest_edge->src); -+ if (JUMP_P (jump)) -+ { -+ new_dest_label = JUMP_LABEL (jump); -+ if (new_dest_label == NULL_RTX) -+ { -+ new_dest_label = PATTERN (jump); -+ gcc_assert (ANY_RETURN_P (new_dest_label)); -+ } -+ } -+ else if (other_bb != new_dest) -+ { -+ if (new_dest == EXIT_BLOCK_PTR) -+ new_dest_label = ret_rtx; -+ else -+ new_dest_label = block_label (new_dest); -+ } -+ else -+ new_dest_label = NULL_RTX; - - jump = BB_END (test_bb); - -@@ -4220,10 +4253,9 @@ - old_dest = JUMP_LABEL (jump); - if (other_bb != new_dest) - { -- new_label = block_label (new_dest); - if (reversep -- ? ! invert_jump_1 (jump, new_label) -- : ! redirect_jump_1 (jump, new_label)) -+ ? ! invert_jump_1 (jump, new_dest_label) -+ : ! redirect_jump_1 (jump, new_dest_label)) - goto cancel; - } - -@@ -4234,7 +4266,7 @@ - - if (other_bb != new_dest) - { -- redirect_jump_2 (jump, old_dest, new_label, 0, reversep); -+ redirect_jump_2 (jump, old_dest, new_dest_label, 0, reversep); - - redirect_edge_succ (BRANCH_EDGE (test_bb), new_dest); - if (reversep) - -=== modified file 'gcc/jump.c' ---- old/gcc/jump.c 2010-12-13 10:05:52 +0000 -+++ new/gcc/jump.c 2011-01-05 12:12:18 +0000 -@@ -29,7 +29,8 @@ - JUMP_LABEL internal field. With this we can detect labels that - become unused because of the deletion of all the jumps that - formerly used them. The JUMP_LABEL info is sometimes looked -- at by later passes. -+ at by later passes. For return insns, it contains either a -+ RETURN or a SIMPLE_RETURN rtx. - - The subroutines redirect_jump and invert_jump are used - from other passes as well. */ -@@ -742,10 +743,10 @@ - return (GET_CODE (x) == IF_THEN_ELSE - && ((GET_CODE (XEXP (x, 2)) == PC - && (GET_CODE (XEXP (x, 1)) == LABEL_REF -- || GET_CODE (XEXP (x, 1)) == RETURN)) -+ || ANY_RETURN_P (XEXP (x, 1)))) - || (GET_CODE (XEXP (x, 1)) == PC - && (GET_CODE (XEXP (x, 2)) == LABEL_REF -- || GET_CODE (XEXP (x, 2)) == RETURN)))); -+ || ANY_RETURN_P (XEXP (x, 2)))))); - } - - /* Return nonzero if INSN is a (possibly) conditional jump inside a -@@ -774,11 +775,11 @@ - return 0; - if (XEXP (SET_SRC (x), 2) == pc_rtx - && (GET_CODE (XEXP (SET_SRC (x), 1)) == LABEL_REF -- || GET_CODE (XEXP (SET_SRC (x), 1)) == RETURN)) -+ || ANY_RETURN_P (XEXP (SET_SRC (x), 1)) == RETURN)) - return 1; - if (XEXP (SET_SRC (x), 1) == pc_rtx - && (GET_CODE (XEXP (SET_SRC (x), 2)) == LABEL_REF -- || GET_CODE (XEXP (SET_SRC (x), 2)) == RETURN)) -+ || ANY_RETURN_P (XEXP (SET_SRC (x), 2)))) - return 1; - return 0; - } -@@ -840,8 +841,9 @@ - a = GET_CODE (XEXP (SET_SRC (x), 1)); - b = GET_CODE (XEXP (SET_SRC (x), 2)); - -- return ((b == PC && (a == LABEL_REF || a == RETURN)) -- || (a == PC && (b == LABEL_REF || b == RETURN))); -+ return ((b == PC && (a == LABEL_REF || a == RETURN || a == SIMPLE_RETURN)) -+ || (a == PC -+ && (b == LABEL_REF || b == RETURN || b == SIMPLE_RETURN))); - } - - /* Return the label of a conditional jump. */ -@@ -878,6 +880,7 @@ - switch (GET_CODE (x)) - { - case RETURN: -+ case SIMPLE_RETURN: - case EH_RETURN: - return true; - -@@ -1200,7 +1203,7 @@ - /* If deleting a jump, decrement the count of the label, - and delete the label if it is now unused. */ - -- if (JUMP_P (insn) && JUMP_LABEL (insn)) -+ if (JUMP_P (insn) && JUMP_LABEL (insn) && !ANY_RETURN_P (JUMP_LABEL (insn))) - { - rtx lab = JUMP_LABEL (insn), lab_next; - -@@ -1331,6 +1334,18 @@ - is also an unconditional jump in that case. */ - } - -+/* A helper function for redirect_exp_1; examines its input X and returns -+ either a LABEL_REF around a label, or a RETURN if X was NULL. */ -+static rtx -+redirect_target (rtx x) -+{ -+ if (x == NULL_RTX) -+ return ret_rtx; -+ if (!ANY_RETURN_P (x)) -+ return gen_rtx_LABEL_REF (Pmode, x); -+ return x; -+} -+ - /* Throughout LOC, redirect OLABEL to NLABEL. Treat null OLABEL or - NLABEL as a return. Accrue modifications into the change group. */ - -@@ -1342,37 +1357,19 @@ - int i; - const char *fmt; - -- if (code == LABEL_REF) -- { -- if (XEXP (x, 0) == olabel) -- { -- rtx n; -- if (nlabel) -- n = gen_rtx_LABEL_REF (Pmode, nlabel); -- else -- n = gen_rtx_RETURN (VOIDmode); -- -- validate_change (insn, loc, n, 1); -- return; -- } -- } -- else if (code == RETURN && olabel == 0) -- { -- if (nlabel) -- x = gen_rtx_LABEL_REF (Pmode, nlabel); -- else -- x = gen_rtx_RETURN (VOIDmode); -- if (loc == &PATTERN (insn)) -- x = gen_rtx_SET (VOIDmode, pc_rtx, x); -- validate_change (insn, loc, x, 1); -+ if ((code == LABEL_REF && XEXP (x, 0) == olabel) -+ || x == olabel) -+ { -+ validate_change (insn, loc, redirect_target (nlabel), 1); - return; - } - -- if (code == SET && nlabel == 0 && SET_DEST (x) == pc_rtx -+ if (code == SET && SET_DEST (x) == pc_rtx -+ && ANY_RETURN_P (nlabel) - && GET_CODE (SET_SRC (x)) == LABEL_REF - && XEXP (SET_SRC (x), 0) == olabel) - { -- validate_change (insn, loc, gen_rtx_RETURN (VOIDmode), 1); -+ validate_change (insn, loc, nlabel, 1); - return; - } - -@@ -1409,6 +1406,7 @@ - int ochanges = num_validated_changes (); - rtx *loc, asmop; - -+ gcc_assert (nlabel); - asmop = extract_asm_operands (PATTERN (jump)); - if (asmop) - { -@@ -1430,17 +1428,20 @@ - jump target label is unused as a result, it and the code following - it may be deleted. - -- If NLABEL is zero, we are to turn the jump into a (possibly conditional) -- RETURN insn. -+ Normally, NLABEL will be a label, but it may also be a RETURN or -+ SIMPLE_RETURN rtx; in that case we are to turn the jump into a -+ (possibly conditional) return insn. - - The return value will be 1 if the change was made, 0 if it wasn't -- (this can only occur for NLABEL == 0). */ -+ (this can only occur when trying to produce return insns). */ - - int - redirect_jump (rtx jump, rtx nlabel, int delete_unused) - { - rtx olabel = JUMP_LABEL (jump); - -+ gcc_assert (nlabel != NULL_RTX); -+ - if (nlabel == olabel) - return 1; - -@@ -1452,7 +1453,7 @@ - } - - /* Fix up JUMP_LABEL and label ref counts after OLABEL has been replaced with -- NLABEL in JUMP. -+ NEW_DEST in JUMP. - If DELETE_UNUSED is positive, delete related insn to OLABEL if its ref - count has dropped to zero. */ - void -@@ -1468,13 +1469,14 @@ - about this. */ - gcc_assert (delete_unused >= 0); - JUMP_LABEL (jump) = nlabel; -- if (nlabel) -+ if (nlabel && !ANY_RETURN_P (nlabel)) - ++LABEL_NUSES (nlabel); - - /* Update labels in any REG_EQUAL note. */ - if ((note = find_reg_note (jump, REG_EQUAL, NULL_RTX)) != NULL_RTX) - { -- if (!nlabel || (invert && !invert_exp_1 (XEXP (note, 0), jump))) -+ if (ANY_RETURN_P (nlabel) -+ || (invert && !invert_exp_1 (XEXP (note, 0), jump))) - remove_note (jump, note); - else - { -@@ -1483,7 +1485,8 @@ - } - } - -- if (olabel && --LABEL_NUSES (olabel) == 0 && delete_unused > 0 -+ if (olabel && !ANY_RETURN_P (olabel) -+ && --LABEL_NUSES (olabel) == 0 && delete_unused > 0 - /* Undefined labels will remain outside the insn stream. */ - && INSN_UID (olabel)) - delete_related_insns (olabel); - -=== modified file 'gcc/opts.c' ---- old/gcc/opts.c 2010-12-10 15:33:37 +0000 -+++ new/gcc/opts.c 2011-01-05 12:12:18 +0000 -@@ -908,6 +908,7 @@ - flag_ipa_cp = opt2; - flag_ipa_sra = opt2; - flag_ee = opt2; -+ flag_shrink_wrap = opt2; - - /* Track fields in field-sensitive alias analysis. */ - set_param_value ("max-fields-for-field-sensitive", - -=== modified file 'gcc/print-rtl.c' ---- old/gcc/print-rtl.c 2010-03-26 16:18:51 +0000 -+++ new/gcc/print-rtl.c 2011-01-05 12:12:18 +0000 -@@ -308,9 +308,16 @@ - } - } - else if (i == 8 && JUMP_P (in_rtx) && JUMP_LABEL (in_rtx) != NULL) -- /* Output the JUMP_LABEL reference. */ -- fprintf (outfile, "\n%s%*s -> %d", print_rtx_head, indent * 2, "", -- INSN_UID (JUMP_LABEL (in_rtx))); -+ { -+ /* Output the JUMP_LABEL reference. */ -+ fprintf (outfile, "\n%s%*s -> ", print_rtx_head, indent * 2, ""); -+ if (GET_CODE (JUMP_LABEL (in_rtx)) == RETURN) -+ fprintf (outfile, "return"); -+ else if (GET_CODE (JUMP_LABEL (in_rtx)) == SIMPLE_RETURN) -+ fprintf (outfile, "simple_return"); -+ else -+ fprintf (outfile, "%d", INSN_UID (JUMP_LABEL (in_rtx))); -+ } - else if (i == 0 && GET_CODE (in_rtx) == VALUE) - { - #ifndef GENERATOR_FILE - -=== modified file 'gcc/reorg.c' ---- old/gcc/reorg.c 2010-09-15 22:51:44 +0000 -+++ new/gcc/reorg.c 2011-01-05 12:12:18 +0000 -@@ -161,8 +161,11 @@ - #define unfilled_slots_next \ - ((rtx *) obstack_next_free (&unfilled_slots_obstack)) - --/* Points to the label before the end of the function. */ --static rtx end_of_function_label; -+/* Points to the label before the end of the function, or before a -+ return insn. */ -+static rtx function_return_label; -+/* Likewise for a simple_return. */ -+static rtx function_simple_return_label; - - /* Mapping between INSN_UID's and position in the code since INSN_UID's do - not always monotonically increase. */ -@@ -175,7 +178,7 @@ - static int resource_conflicts_p (struct resources *, struct resources *); - static int insn_references_resource_p (rtx, struct resources *, bool); - static int insn_sets_resource_p (rtx, struct resources *, bool); --static rtx find_end_label (void); -+static rtx find_end_label (rtx); - static rtx emit_delay_sequence (rtx, rtx, int); - static rtx add_to_delay_list (rtx, rtx); - static rtx delete_from_delay_slot (rtx); -@@ -220,6 +223,15 @@ - static void make_return_insns (rtx); - #endif - -+/* Return true iff INSN is a simplejump, or any kind of return insn. */ -+ -+static bool -+simplejump_or_return_p (rtx insn) -+{ -+ return (JUMP_P (insn) -+ && (simplejump_p (insn) || ANY_RETURN_P (PATTERN (insn)))); -+} -+ - /* Return TRUE if this insn should stop the search for insn to fill delay - slots. LABELS_P indicates that labels should terminate the search. - In all cases, jumps terminate the search. */ -@@ -335,23 +347,29 @@ - - ??? There may be a problem with the current implementation. Suppose - we start with a bare RETURN insn and call find_end_label. It may set -- end_of_function_label just before the RETURN. Suppose the machinery -+ function_return_label just before the RETURN. Suppose the machinery - is able to fill the delay slot of the RETURN insn afterwards. Then -- end_of_function_label is no longer valid according to the property -+ function_return_label is no longer valid according to the property - described above and find_end_label will still return it unmodified. - Note that this is probably mitigated by the following observation: -- once end_of_function_label is made, it is very likely the target of -+ once function_return_label is made, it is very likely the target of - a jump, so filling the delay slot of the RETURN will be much more - difficult. */ - - static rtx --find_end_label (void) -+find_end_label (rtx kind) - { - rtx insn; -+ rtx *plabel; -+ -+ if (kind == ret_rtx) -+ plabel = &function_return_label; -+ else -+ plabel = &function_simple_return_label; - - /* If we found one previously, return it. */ -- if (end_of_function_label) -- return end_of_function_label; -+ if (*plabel) -+ return *plabel; - - /* Otherwise, see if there is a label at the end of the function. If there - is, it must be that RETURN insns aren't needed, so that is our return -@@ -366,44 +384,44 @@ - - /* When a target threads its epilogue we might already have a - suitable return insn. If so put a label before it for the -- end_of_function_label. */ -+ function_return_label. */ - if (BARRIER_P (insn) - && JUMP_P (PREV_INSN (insn)) -- && GET_CODE (PATTERN (PREV_INSN (insn))) == RETURN) -+ && PATTERN (PREV_INSN (insn)) == kind) - { - rtx temp = PREV_INSN (PREV_INSN (insn)); -- end_of_function_label = gen_label_rtx (); -- LABEL_NUSES (end_of_function_label) = 0; -+ rtx label = gen_label_rtx (); -+ LABEL_NUSES (label) = 0; - - /* Put the label before an USE insns that may precede the RETURN insn. */ - while (GET_CODE (temp) == USE) - temp = PREV_INSN (temp); - -- emit_label_after (end_of_function_label, temp); -+ emit_label_after (label, temp); -+ *plabel = label; - } - - else if (LABEL_P (insn)) -- end_of_function_label = insn; -+ *plabel = insn; - else - { -- end_of_function_label = gen_label_rtx (); -- LABEL_NUSES (end_of_function_label) = 0; -+ rtx label = gen_label_rtx (); -+ LABEL_NUSES (label) = 0; - /* If the basic block reorder pass moves the return insn to - some other place try to locate it again and put our -- end_of_function_label there. */ -- while (insn && ! (JUMP_P (insn) -- && (GET_CODE (PATTERN (insn)) == RETURN))) -+ function_return_label there. */ -+ while (insn && ! (JUMP_P (insn) && (PATTERN (insn) == kind))) - insn = PREV_INSN (insn); - if (insn) - { - insn = PREV_INSN (insn); - -- /* Put the label before an USE insns that may proceed the -+ /* Put the label before an USE insns that may precede the - RETURN insn. */ - while (GET_CODE (insn) == USE) - insn = PREV_INSN (insn); - -- emit_label_after (end_of_function_label, insn); -+ emit_label_after (label, insn); - } - else - { -@@ -413,19 +431,16 @@ - && ! HAVE_return - #endif - ) -- { -- /* The RETURN insn has its delay slot filled so we cannot -- emit the label just before it. Since we already have -- an epilogue and cannot emit a new RETURN, we cannot -- emit the label at all. */ -- end_of_function_label = NULL_RTX; -- return end_of_function_label; -- } -+ /* The RETURN insn has its delay slot filled so we cannot -+ emit the label just before it. Since we already have -+ an epilogue and cannot emit a new RETURN, we cannot -+ emit the label at all. */ -+ return NULL_RTX; - #endif /* HAVE_epilogue */ - - /* Otherwise, make a new label and emit a RETURN and BARRIER, - if needed. */ -- emit_label (end_of_function_label); -+ emit_label (label); - #ifdef HAVE_return - /* We don't bother trying to create a return insn if the - epilogue has filled delay-slots; we would have to try and -@@ -437,19 +452,21 @@ - /* The return we make may have delay slots too. */ - rtx insn = gen_return (); - insn = emit_jump_insn (insn); -+ JUMP_LABEL (insn) = ret_rtx; - emit_barrier (); - if (num_delay_slots (insn) > 0) - obstack_ptr_grow (&unfilled_slots_obstack, insn); - } - #endif - } -+ *plabel = label; - } - - /* Show one additional use for this label so it won't go away until - we are done. */ -- ++LABEL_NUSES (end_of_function_label); -+ ++LABEL_NUSES (*plabel); - -- return end_of_function_label; -+ return *plabel; - } - - /* Put INSN and LIST together in a SEQUENCE rtx of LENGTH, and replace -@@ -797,10 +814,8 @@ - if ((next_trial == next_active_insn (JUMP_LABEL (insn)) - && ! (next_trial == 0 && crtl->epilogue_delay_list != 0)) - || (next_trial != 0 -- && JUMP_P (next_trial) -- && JUMP_LABEL (insn) == JUMP_LABEL (next_trial) -- && (simplejump_p (next_trial) -- || GET_CODE (PATTERN (next_trial)) == RETURN))) -+ && simplejump_or_return_p (next_trial) -+ && JUMP_LABEL (insn) == JUMP_LABEL (next_trial))) - { - if (eligible_for_annul_false (insn, 0, trial, flags)) - { -@@ -819,13 +834,11 @@ - branch, thread our jump to the target of that branch. Don't - change this into a RETURN here, because it may not accept what - we have in the delay slot. We'll fix this up later. */ -- if (next_trial && JUMP_P (next_trial) -- && (simplejump_p (next_trial) -- || GET_CODE (PATTERN (next_trial)) == RETURN)) -+ if (next_trial && simplejump_or_return_p (next_trial)) - { - rtx target_label = JUMP_LABEL (next_trial); -- if (target_label == 0) -- target_label = find_end_label (); -+ if (ANY_RETURN_P (target_label)) -+ target_label = find_end_label (target_label); - - if (target_label) - { -@@ -866,7 +879,7 @@ - if (JUMP_P (insn) - && (condjump_p (insn) || condjump_in_parallel_p (insn)) - && INSN_UID (insn) <= max_uid -- && label != 0 -+ && label != 0 && !ANY_RETURN_P (label) - && INSN_UID (label) <= max_uid) - flags - = (uid_to_ruid[INSN_UID (label)] > uid_to_ruid[INSN_UID (insn)]) -@@ -1038,7 +1051,7 @@ - pat = XVECEXP (pat, 0, 0); - - if (GET_CODE (pat) == RETURN) -- return target == 0 ? const_true_rtx : 0; -+ return ANY_RETURN_P (target) ? const_true_rtx : 0; - - else if (GET_CODE (pat) != SET || SET_DEST (pat) != pc_rtx) - return 0; -@@ -1318,7 +1331,11 @@ - } - - /* Show the place to which we will be branching. */ -- *pnew_thread = next_active_insn (JUMP_LABEL (XVECEXP (seq, 0, 0))); -+ temp = JUMP_LABEL (XVECEXP (seq, 0, 0)); -+ if (ANY_RETURN_P (temp)) -+ *pnew_thread = temp; -+ else -+ *pnew_thread = next_active_insn (temp); - - /* Add any new insns to the delay list and update the count of the - number of slots filled. */ -@@ -1358,8 +1375,7 @@ - /* We can't do anything if SEQ's delay insn isn't an - unconditional branch. */ - -- if (! simplejump_p (XVECEXP (seq, 0, 0)) -- && GET_CODE (PATTERN (XVECEXP (seq, 0, 0))) != RETURN) -+ if (! simplejump_or_return_p (XVECEXP (seq, 0, 0))) - return delay_list; - - for (i = 1; i < XVECLEN (seq, 0); i++) -@@ -1827,7 +1843,7 @@ - rtx insn; - - /* We don't own the function end. */ -- if (thread == 0) -+ if (ANY_RETURN_P (thread)) - return 0; - - /* Get the first active insn, or THREAD, if it is an active insn. */ -@@ -2245,7 +2261,8 @@ - && (!JUMP_P (insn) - || ((condjump_p (insn) || condjump_in_parallel_p (insn)) - && ! simplejump_p (insn) -- && JUMP_LABEL (insn) != 0))) -+ && JUMP_LABEL (insn) != 0 -+ && !ANY_RETURN_P (JUMP_LABEL (insn))))) - { - /* Invariant: If insn is a JUMP_INSN, the insn's jump - label. Otherwise, zero. */ -@@ -2270,7 +2287,7 @@ - target = JUMP_LABEL (insn); - } - -- if (target == 0) -+ if (target == 0 || ANY_RETURN_P (target)) - for (trial = next_nonnote_insn (insn); trial; trial = next_trial) - { - next_trial = next_nonnote_insn (trial); -@@ -2349,6 +2366,7 @@ - && JUMP_P (trial) - && simplejump_p (trial) - && (target == 0 || JUMP_LABEL (trial) == target) -+ && !ANY_RETURN_P (JUMP_LABEL (trial)) - && (next_trial = next_active_insn (JUMP_LABEL (trial))) != 0 - && ! (NONJUMP_INSN_P (next_trial) - && GET_CODE (PATTERN (next_trial)) == SEQUENCE) -@@ -2371,7 +2389,7 @@ - if (new_label != 0) - new_label = get_label_before (new_label); - else -- new_label = find_end_label (); -+ new_label = find_end_label (simple_return_rtx); - - if (new_label) - { -@@ -2503,7 +2521,8 @@ - - /* Follow any unconditional jump at LABEL; - return the ultimate label reached by any such chain of jumps. -- Return null if the chain ultimately leads to a return instruction. -+ Return a suitable return rtx if the chain ultimately leads to a -+ return instruction. - If LABEL is not followed by a jump, return LABEL. - If the chain loops or we can't find end, return LABEL, - since that tells caller to avoid changing the insn. */ -@@ -2518,6 +2537,7 @@ - - for (depth = 0; - (depth < 10 -+ && !ANY_RETURN_P (value) - && (insn = next_active_insn (value)) != 0 - && JUMP_P (insn) - && ((JUMP_LABEL (insn) != 0 && any_uncondjump_p (insn) -@@ -2527,18 +2547,22 @@ - && BARRIER_P (next)); - depth++) - { -- rtx tem; -+ rtx this_label = JUMP_LABEL (insn); - - /* If we have found a cycle, make the insn jump to itself. */ -- if (JUMP_LABEL (insn) == label) -+ if (this_label == label) - return label; - -- tem = next_active_insn (JUMP_LABEL (insn)); -- if (tem && (GET_CODE (PATTERN (tem)) == ADDR_VEC -+ if (!ANY_RETURN_P (this_label)) -+ { -+ rtx tem = next_active_insn (this_label); -+ if (tem -+ && (GET_CODE (PATTERN (tem)) == ADDR_VEC - || GET_CODE (PATTERN (tem)) == ADDR_DIFF_VEC)) -- break; -+ break; -+ } - -- value = JUMP_LABEL (insn); -+ value = this_label; - } - if (depth == 10) - return label; -@@ -2901,6 +2925,7 @@ - arithmetic insn after the jump insn and put the arithmetic insn in the - delay slot. If we can't do this, return. */ - if (delay_list == 0 && likely && new_thread -+ && !ANY_RETURN_P (new_thread) - && NONJUMP_INSN_P (new_thread) - && GET_CODE (PATTERN (new_thread)) != ASM_INPUT - && asm_noperands (PATTERN (new_thread)) < 0) -@@ -2985,16 +3010,14 @@ - - gcc_assert (thread_if_true); - -- if (new_thread && JUMP_P (new_thread) -- && (simplejump_p (new_thread) -- || GET_CODE (PATTERN (new_thread)) == RETURN) -+ if (new_thread && simplejump_or_return_p (new_thread) - && redirect_with_delay_list_safe_p (insn, - JUMP_LABEL (new_thread), - delay_list)) - new_thread = follow_jumps (JUMP_LABEL (new_thread)); - -- if (new_thread == 0) -- label = find_end_label (); -+ if (ANY_RETURN_P (new_thread)) -+ label = find_end_label (new_thread); - else if (LABEL_P (new_thread)) - label = new_thread; - else -@@ -3340,11 +3363,12 @@ - group of consecutive labels. */ - if (JUMP_P (insn) - && (condjump_p (insn) || condjump_in_parallel_p (insn)) -- && (target_label = JUMP_LABEL (insn)) != 0) -+ && (target_label = JUMP_LABEL (insn)) != 0 -+ && !ANY_RETURN_P (target_label)) - { - target_label = skip_consecutive_labels (follow_jumps (target_label)); -- if (target_label == 0) -- target_label = find_end_label (); -+ if (ANY_RETURN_P (target_label)) -+ target_label = find_end_label (target_label); - - if (target_label && next_active_insn (target_label) == next - && ! condjump_in_parallel_p (insn)) -@@ -3359,9 +3383,8 @@ - /* See if this jump conditionally branches around an unconditional - jump. If so, invert this jump and point it to the target of the - second jump. */ -- if (next && JUMP_P (next) -+ if (next && simplejump_or_return_p (next) - && any_condjump_p (insn) -- && (simplejump_p (next) || GET_CODE (PATTERN (next)) == RETURN) - && target_label - && next_active_insn (target_label) == next_active_insn (next) - && no_labels_between_p (insn, next)) -@@ -3403,8 +3426,7 @@ - Don't do this if we expect the conditional branch to be true, because - we would then be making the more common case longer. */ - -- if (JUMP_P (insn) -- && (simplejump_p (insn) || GET_CODE (PATTERN (insn)) == RETURN) -+ if (simplejump_or_return_p (insn) - && (other = prev_active_insn (insn)) != 0 - && any_condjump_p (other) - && no_labels_between_p (other, insn) -@@ -3445,10 +3467,10 @@ - Only do so if optimizing for size since this results in slower, but - smaller code. */ - if (optimize_function_for_size_p (cfun) -- && GET_CODE (PATTERN (delay_insn)) == RETURN -+ && ANY_RETURN_P (PATTERN (delay_insn)) - && next - && JUMP_P (next) -- && GET_CODE (PATTERN (next)) == RETURN) -+ && PATTERN (next) == PATTERN (delay_insn)) - { - rtx after; - int i; -@@ -3487,14 +3509,16 @@ - continue; - - target_label = JUMP_LABEL (delay_insn); -+ if (target_label && ANY_RETURN_P (target_label)) -+ continue; - - if (target_label) - { - /* If this jump goes to another unconditional jump, thread it, but - don't convert a jump into a RETURN here. */ - trial = skip_consecutive_labels (follow_jumps (target_label)); -- if (trial == 0) -- trial = find_end_label (); -+ if (ANY_RETURN_P (trial)) -+ trial = find_end_label (trial); - - if (trial && trial != target_label - && redirect_with_delay_slots_safe_p (delay_insn, trial, insn)) -@@ -3517,7 +3541,7 @@ - later incorrectly compute register live/death info. */ - rtx tmp = next_active_insn (trial); - if (tmp == 0) -- tmp = find_end_label (); -+ tmp = find_end_label (simple_return_rtx); - - if (tmp) - { -@@ -3537,14 +3561,12 @@ - delay list and that insn is redundant, thread the jump. */ - if (trial && GET_CODE (PATTERN (trial)) == SEQUENCE - && XVECLEN (PATTERN (trial), 0) == 2 -- && JUMP_P (XVECEXP (PATTERN (trial), 0, 0)) -- && (simplejump_p (XVECEXP (PATTERN (trial), 0, 0)) -- || GET_CODE (PATTERN (XVECEXP (PATTERN (trial), 0, 0))) == RETURN) -+ && simplejump_or_return_p (XVECEXP (PATTERN (trial), 0, 0)) - && redundant_insn (XVECEXP (PATTERN (trial), 0, 1), insn, 0)) - { - target_label = JUMP_LABEL (XVECEXP (PATTERN (trial), 0, 0)); -- if (target_label == 0) -- target_label = find_end_label (); -+ if (ANY_RETURN_P (target_label)) -+ target_label = find_end_label (target_label); - - if (target_label - && redirect_with_delay_slots_safe_p (delay_insn, target_label, -@@ -3622,16 +3644,15 @@ - a RETURN here. */ - if (! INSN_ANNULLED_BRANCH_P (delay_insn) - && any_condjump_p (delay_insn) -- && next && JUMP_P (next) -- && (simplejump_p (next) || GET_CODE (PATTERN (next)) == RETURN) -+ && next && simplejump_or_return_p (next) - && next_active_insn (target_label) == next_active_insn (next) - && no_labels_between_p (insn, next)) - { - rtx label = JUMP_LABEL (next); - rtx old_label = JUMP_LABEL (delay_insn); - -- if (label == 0) -- label = find_end_label (); -+ if (ANY_RETURN_P (label)) -+ label = find_end_label (label); - - /* find_end_label can generate a new label. Check this first. */ - if (label -@@ -3692,7 +3713,8 @@ - make_return_insns (rtx first) - { - rtx insn, jump_insn, pat; -- rtx real_return_label = end_of_function_label; -+ rtx real_return_label = function_return_label; -+ rtx real_simple_return_label = function_simple_return_label; - int slots, i; - - #ifdef DELAY_SLOTS_FOR_EPILOGUE -@@ -3707,18 +3729,25 @@ - #endif - - /* See if there is a RETURN insn in the function other than the one we -- made for END_OF_FUNCTION_LABEL. If so, set up anything we can't change -+ made for FUNCTION_RETURN_LABEL. If so, set up anything we can't change - into a RETURN to jump to it. */ - for (insn = first; insn; insn = NEXT_INSN (insn)) -- if (JUMP_P (insn) && GET_CODE (PATTERN (insn)) == RETURN) -+ if (JUMP_P (insn) && ANY_RETURN_P (PATTERN (insn))) - { -- real_return_label = get_label_before (insn); -+ rtx t = get_label_before (insn); -+ if (PATTERN (insn) == ret_rtx) -+ real_return_label = t; -+ else -+ real_simple_return_label = t; - break; - } - - /* Show an extra usage of REAL_RETURN_LABEL so it won't go away if it -- was equal to END_OF_FUNCTION_LABEL. */ -- LABEL_NUSES (real_return_label)++; -+ was equal to FUNCTION_RETURN_LABEL. */ -+ if (real_return_label) -+ LABEL_NUSES (real_return_label)++; -+ if (real_simple_return_label) -+ LABEL_NUSES (real_simple_return_label)++; - - /* Clear the list of insns to fill so we can use it. */ - obstack_free (&unfilled_slots_obstack, unfilled_firstobj); -@@ -3726,13 +3755,27 @@ - for (insn = first; insn; insn = NEXT_INSN (insn)) - { - int flags; -+ rtx kind, real_label; - - /* Only look at filled JUMP_INSNs that go to the end of function - label. */ - if (!NONJUMP_INSN_P (insn) - || GET_CODE (PATTERN (insn)) != SEQUENCE -- || !JUMP_P (XVECEXP (PATTERN (insn), 0, 0)) -- || JUMP_LABEL (XVECEXP (PATTERN (insn), 0, 0)) != end_of_function_label) -+ || !JUMP_P (XVECEXP (PATTERN (insn), 0, 0))) -+ continue; -+ -+ if (JUMP_LABEL (XVECEXP (PATTERN (insn), 0, 0)) == function_return_label) -+ { -+ kind = ret_rtx; -+ real_label = real_return_label; -+ } -+ else if (JUMP_LABEL (XVECEXP (PATTERN (insn), 0, 0)) -+ == function_simple_return_label) -+ { -+ kind = simple_return_rtx; -+ real_label = real_simple_return_label; -+ } -+ else - continue; - - pat = PATTERN (insn); -@@ -3740,14 +3783,12 @@ - - /* If we can't make the jump into a RETURN, try to redirect it to the best - RETURN and go on to the next insn. */ -- if (! reorg_redirect_jump (jump_insn, NULL_RTX)) -+ if (! reorg_redirect_jump (jump_insn, kind)) - { - /* Make sure redirecting the jump will not invalidate the delay - slot insns. */ -- if (redirect_with_delay_slots_safe_p (jump_insn, -- real_return_label, -- insn)) -- reorg_redirect_jump (jump_insn, real_return_label); -+ if (redirect_with_delay_slots_safe_p (jump_insn, real_label, insn)) -+ reorg_redirect_jump (jump_insn, real_label); - continue; - } - -@@ -3787,7 +3828,7 @@ - RETURN, delete the SEQUENCE and output the individual insns, - followed by the RETURN. Then set things up so we try to find - insns for its delay slots, if it needs some. */ -- if (GET_CODE (PATTERN (jump_insn)) == RETURN) -+ if (ANY_RETURN_P (PATTERN (jump_insn))) - { - rtx prev = PREV_INSN (insn); - -@@ -3804,13 +3845,16 @@ - else - /* It is probably more efficient to keep this with its current - delay slot as a branch to a RETURN. */ -- reorg_redirect_jump (jump_insn, real_return_label); -+ reorg_redirect_jump (jump_insn, real_label); - } - - /* Now delete REAL_RETURN_LABEL if we never used it. Then try to fill any - new delay slots we have created. */ -- if (--LABEL_NUSES (real_return_label) == 0) -+ if (real_return_label != NULL_RTX && --LABEL_NUSES (real_return_label) == 0) - delete_related_insns (real_return_label); -+ if (real_simple_return_label != NULL_RTX -+ && --LABEL_NUSES (real_simple_return_label) == 0) -+ delete_related_insns (real_simple_return_label); - - fill_simple_delay_slots (1); - fill_simple_delay_slots (0); -@@ -3878,7 +3922,7 @@ - init_resource_info (epilogue_insn); - - /* Show we haven't computed an end-of-function label yet. */ -- end_of_function_label = 0; -+ function_return_label = function_simple_return_label = NULL_RTX; - - /* Initialize the statistics for this function. */ - memset (num_insns_needing_delays, 0, sizeof num_insns_needing_delays); -@@ -3900,11 +3944,23 @@ - /* If we made an end of function label, indicate that it is now - safe to delete it by undoing our prior adjustment to LABEL_NUSES. - If it is now unused, delete it. */ -- if (end_of_function_label && --LABEL_NUSES (end_of_function_label) == 0) -- delete_related_insns (end_of_function_label); -+ if (function_return_label && --LABEL_NUSES (function_return_label) == 0) -+ delete_related_insns (function_return_label); -+ if (function_simple_return_label -+ && --LABEL_NUSES (function_simple_return_label) == 0) -+ delete_related_insns (function_simple_return_label); - -+#if defined HAVE_return || defined HAVE_simple_return -+ if ( - #ifdef HAVE_return -- if (HAVE_return && end_of_function_label != 0) -+ (HAVE_return && function_return_label != 0) -+#else -+ 0 -+#endif -+#ifdef HAVE_simple_return -+ || (HAVE_simple_return && function_simple_return_label != 0) -+#endif -+ ) - make_return_insns (first); - #endif - - -=== modified file 'gcc/resource.c' ---- old/gcc/resource.c 2009-11-25 10:55:54 +0000 -+++ new/gcc/resource.c 2011-01-05 12:12:18 +0000 -@@ -495,6 +495,8 @@ - || GET_CODE (PATTERN (this_jump_insn)) == RETURN) - { - next = JUMP_LABEL (this_jump_insn); -+ if (next && ANY_RETURN_P (next)) -+ next = NULL_RTX; - if (jump_insn == 0) - { - jump_insn = insn; -@@ -562,9 +564,10 @@ - AND_COMPL_HARD_REG_SET (scratch, needed.regs); - AND_COMPL_HARD_REG_SET (fallthrough_res.regs, scratch); - -- find_dead_or_set_registers (JUMP_LABEL (this_jump_insn), -- &target_res, 0, jump_count, -- target_set, needed); -+ if (!ANY_RETURN_P (JUMP_LABEL (this_jump_insn))) -+ find_dead_or_set_registers (JUMP_LABEL (this_jump_insn), -+ &target_res, 0, jump_count, -+ target_set, needed); - find_dead_or_set_registers (next, - &fallthrough_res, 0, jump_count, - set, needed); -@@ -1097,6 +1100,8 @@ - struct resources new_resources; - rtx stop_insn = next_active_insn (jump_insn); - -+ if (jump_target && ANY_RETURN_P (jump_target)) -+ jump_target = NULL_RTX; - mark_target_live_regs (insns, next_active_insn (jump_target), - &new_resources); - CLEAR_RESOURCE (&set); - -=== modified file 'gcc/rtl.c' ---- old/gcc/rtl.c 2010-12-13 10:05:52 +0000 -+++ new/gcc/rtl.c 2011-01-05 12:12:18 +0000 -@@ -256,6 +256,8 @@ - case CODE_LABEL: - case PC: - case CC0: -+ case RETURN: -+ case SIMPLE_RETURN: - case SCRATCH: - /* SCRATCH must be shared because they represent distinct values. */ - return orig; - -=== modified file 'gcc/rtl.def' ---- old/gcc/rtl.def 2010-04-02 18:54:46 +0000 -+++ new/gcc/rtl.def 2011-01-05 12:12:18 +0000 -@@ -296,6 +296,10 @@ - - DEF_RTL_EXPR(RETURN, "return", "", RTX_EXTRA) - -+/* A plain return, to be used on paths that are reached without going -+ through the function prologue. */ -+DEF_RTL_EXPR(SIMPLE_RETURN, "simple_return", "", RTX_EXTRA) -+ - /* Special for EH return from subroutine. */ - - DEF_RTL_EXPR(EH_RETURN, "eh_return", "", RTX_EXTRA) - -=== modified file 'gcc/rtl.h' ---- old/gcc/rtl.h 2010-11-16 22:17:17 +0000 -+++ new/gcc/rtl.h 2011-01-05 12:12:18 +0000 -@@ -411,6 +411,10 @@ - (JUMP_P (INSN) && (GET_CODE (PATTERN (INSN)) == ADDR_VEC || \ - GET_CODE (PATTERN (INSN)) == ADDR_DIFF_VEC)) - -+/* Predicate yielding nonzero iff X is a return or simple_preturn. */ -+#define ANY_RETURN_P(X) \ -+ (GET_CODE (X) == RETURN || GET_CODE (X) == SIMPLE_RETURN) -+ - /* 1 if X is a unary operator. */ - - #define UNARY_P(X) \ -@@ -1998,6 +2002,8 @@ - { - GR_PC, - GR_CC0, -+ GR_RETURN, -+ GR_SIMPLE_RETURN, - GR_STACK_POINTER, - GR_FRAME_POINTER, - /* For register elimination to work properly these hard_frame_pointer_rtx, -@@ -2032,6 +2038,8 @@ - - /* Standard pieces of rtx, to be substituted directly into things. */ - #define pc_rtx (global_rtl[GR_PC]) -+#define ret_rtx (global_rtl[GR_RETURN]) -+#define simple_return_rtx (global_rtl[GR_SIMPLE_RETURN]) - #define cc0_rtx (global_rtl[GR_CC0]) - - /* All references to certain hard regs, except those created - -=== modified file 'gcc/rtlanal.c' ---- old/gcc/rtlanal.c 2010-11-16 22:17:17 +0000 -+++ new/gcc/rtlanal.c 2011-01-05 12:12:18 +0000 -@@ -2673,6 +2673,7 @@ - - if (JUMP_P (insn) - && (label = JUMP_LABEL (insn)) != NULL_RTX -+ && !ANY_RETURN_P (label) - && (table = next_active_insn (label)) != NULL_RTX - && JUMP_TABLE_DATA_P (table)) - { - -=== modified file 'gcc/sched-int.h' ---- old/gcc/sched-int.h 2010-06-02 16:31:39 +0000 -+++ new/gcc/sched-int.h 2011-01-05 12:12:18 +0000 -@@ -199,7 +199,7 @@ - - extern void ebb_compute_jump_reg_dependencies (rtx, regset, regset, regset); - --extern edge find_fallthru_edge (basic_block); -+extern edge find_fallthru_edge_from (basic_block); - - extern void (* sched_init_only_bb) (basic_block, basic_block); - extern basic_block (* sched_split_block) (basic_block, rtx); - -=== modified file 'gcc/sched-vis.c' ---- old/gcc/sched-vis.c 2009-11-25 10:55:54 +0000 -+++ new/gcc/sched-vis.c 2011-01-05 12:12:18 +0000 -@@ -549,6 +549,9 @@ - case RETURN: - sprintf (buf, "return"); - break; -+ case SIMPLE_RETURN: -+ sprintf (buf, "simple_return"); -+ break; - case CALL: - print_exp (buf, x, verbose); - break; - -=== modified file 'gcc/sel-sched-ir.c' ---- old/gcc/sel-sched-ir.c 2010-08-31 11:52:01 +0000 -+++ new/gcc/sel-sched-ir.c 2011-01-05 12:12:18 +0000 -@@ -686,7 +686,7 @@ - - /* Find fallthrough edge. */ - gcc_assert (BLOCK_FOR_INSN (insn)->prev_bb); -- candidate = find_fallthru_edge (BLOCK_FOR_INSN (insn)->prev_bb); -+ candidate = find_fallthru_edge_from (BLOCK_FOR_INSN (insn)->prev_bb); - - if (!candidate - || (candidate->src != BLOCK_FOR_INSN (last_scheduled_insn) - -=== modified file 'gcc/sel-sched.c' ---- old/gcc/sel-sched.c 2010-11-12 15:47:38 +0000 -+++ new/gcc/sel-sched.c 2011-01-05 12:12:18 +0000 -@@ -617,8 +617,8 @@ - if (bb == BLOCK_FOR_INSN (succ)) - return true; - -- if (find_fallthru_edge (bb)) -- bb = find_fallthru_edge (bb)->dest; -+ if (find_fallthru_edge_from (bb)) -+ bb = find_fallthru_edge_from (bb)->dest; - else - return false; - -@@ -4911,7 +4911,7 @@ - next = PREV_INSN (insn); - BND_TO (bnd) = insn; - -- ft_edge = find_fallthru_edge (block_from); -+ ft_edge = find_fallthru_edge_from (block_from); - block_next = ft_edge->dest; - /* There must be a fallthrough block (or where should go - control flow in case of false jump predicate otherwise?). */ - -=== modified file 'gcc/vec.h' ---- old/gcc/vec.h 2010-01-09 14:46:25 +0000 -+++ new/gcc/vec.h 2011-01-05 12:12:18 +0000 -@@ -188,6 +188,18 @@ - - #define VEC_iterate(T,V,I,P) (VEC_OP(T,base,iterate)(VEC_BASE(V),I,&(P))) - -+/* Convenience macro for forward iteration. */ -+ -+#define FOR_EACH_VEC_ELT(T, V, I, P) \ -+ for (I = 0; VEC_iterate (T, (V), (I), (P)); ++(I)) -+ -+/* Convenience macro for reverse iteration. */ -+ -+#define FOR_EACH_VEC_ELT_REVERSE(T,V,I,P) \ -+ for (I = VEC_length (T, (V)) - 1; \ -+ VEC_iterate (T, (V), (I), (P)); \ -+ (I)--) -+ - /* Allocate new vector. - VEC(T,A) *VEC_T_A_alloc(int reserve); - - |