+dup_block_and_redirect (basic_block bb, basic_block copy_bb, rtx before,
+ bitmap_head *need_prologue)
+{
+ edge_iterator ei;
+ edge e;
+ rtx insn = BB_END (bb);
+
+ /* We know BB has a single successor, so there is no need to copy a
+ simple jump at the end of BB. */
+ if (simplejump_p (insn))
+ insn = PREV_INSN (insn);
+
+ start_sequence ();
+ duplicate_insn_chain (BB_HEAD (bb), insn);
+ if (dump_file)
+ {
+ unsigned count = 0;
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (active_insn_p (insn))
+ ++count;
+ fprintf (dump_file, "Duplicating bb %d to bb %d, %u active insns.\n",
+ bb->index, copy_bb->index, count);
+ }
+ insn = get_insns ();
+ end_sequence ();
+ emit_insn_before (insn, before);
+
+ /* Redirect all the paths that need no prologue into copy_bb. */
+ for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
+ if (!bitmap_bit_p (need_prologue, e->src->index))
+ {
+ redirect_edge_and_branch_force (e, copy_bb);
+ continue;
+ }
+ else
+ ei_next (&ei);
+}
+#endif
+
+#if defined (HAVE_return) || defined (HAVE_simple_return)
+/* Return true if there are any active insns between HEAD and TAIL. */
+static bool
+active_insn_between (rtx head, rtx tail)
+{
+ while (tail)
+ {
+ if (active_insn_p (tail))
+ return true;
+ if (tail == head)
+ return false;
+ tail = PREV_INSN (tail);
+ }
+ return false;
+}
+
+/* LAST_BB is a block that exits, and empty of active instructions.
+ Examine its predecessors for jumps that can be converted to
+ (conditional) returns. */
+static VEC (edge, heap) *
+convert_jumps_to_returns (basic_block last_bb, bool simple_p,
+ VEC (edge, heap) *unconverted ATTRIBUTE_UNUSED)
+{
+ int i;
+ basic_block bb;
+ rtx label;
+ edge_iterator ei;
+ edge e;
+ VEC(basic_block,heap) *src_bbs;
+
+ src_bbs = VEC_alloc (basic_block, heap, EDGE_COUNT (last_bb->preds));
+ FOR_EACH_EDGE (e, ei, last_bb->preds)
+ if (e->src != ENTRY_BLOCK_PTR)
+ VEC_quick_push (basic_block, src_bbs, e->src);
+
+ label = BB_HEAD (last_bb);
+
+ FOR_EACH_VEC_ELT (basic_block, src_bbs, i, bb)
+ {
+ rtx jump = BB_END (bb);
+
+ if (!JUMP_P (jump) || JUMP_LABEL (jump) != label)
+ continue;
+
+ e = find_edge (bb, last_bb);
+
+ /* If we have an unconditional jump, we can replace that
+ with a simple return instruction. */
+ if (simplejump_p (jump))
+ {
+ /* The use of the return register might be present in the exit
+ fallthru block. Either:
+ - removing the use is safe, and we should remove the use in
+ the exit fallthru block, or
+ - removing the use is not safe, and we should add it here.
+ For now, we conservatively choose the latter. Either of the
+ 2 helps in crossjumping. */
+ emit_use_return_register_into_block (bb);
+
+ emit_return_into_block (simple_p, bb);
+ delete_insn (jump);
+ }
+
+ /* 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)
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "Failed to redirect bb %d branch.\n", bb->index);
+ VEC_safe_push (edge, heap, unconverted, e);
+ }
+#endif
+ continue;
+ }
+
+ /* See comment in simplejump_p case above. */
+ emit_use_return_register_into_block (bb);
+
+ /* 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)
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "Failed to redirect bb %d branch.\n", bb->index);
+ VEC_safe_push (edge, heap, unconverted, e);
+ }
+#endif
+ continue;
+ }
+
+ /* Fix up the CFG for the successful change we just made. */
+ redirect_edge_succ (e, EXIT_BLOCK_PTR);
+ e->flags &= ~EDGE_CROSSING;
+ }
+ VEC_free (basic_block, heap, src_bbs);
+ return unconverted;
+}
+
+/* Emit a return insn for the exit fallthru block. */
+static basic_block
+emit_return_for_exit (edge exit_fallthru_edge, bool simple_p)