X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fcfgrtl.c;h=5af13dd4eff4ecba351799e4a52c3e25e8f7165a;hp=2f6ea7dc965aee606d618218a791ab0a18cc417a;hb=0958a641e614f832728291f512df7a293137f784;hpb=8fcc0f14bf54b8bbd5d23665a757304a135de07e diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c index 2f6ea7dc965..5af13dd4eff 100644 --- a/gcc/cfgrtl.c +++ b/gcc/cfgrtl.c @@ -1,12 +1,13 @@ /* Control flow graph manipulation code for GNU compiler. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + 2011, 2012 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +along with GCC; see the file COPYING3. If not see +. */ /* This file contains low level functions to manipulate the CFG and analyze it that are aware of the RTL intermediate language. @@ -30,6 +30,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA insert_insn_on_edge, commit_edge_insertions - CFG updating after insn simplification purge_dead_edges, purge_all_dead_edges + - CFG fixing after coarse manipulation + fixup_abnormal_edges Functions not supposed for generic use: - Infrastructure to determine quickly basic block for insn @@ -42,7 +44,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "coretypes.h" #include "tm.h" #include "tree.h" -#include "rtl.h" #include "hard-reg-set.h" #include "basic-block.h" #include "regs.h" @@ -50,20 +51,22 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "output.h" #include "function.h" #include "except.h" -#include "toplev.h" +#include "rtl-error.h" #include "tm_p.h" #include "obstack.h" +#include "insn-attr.h" #include "insn-config.h" #include "cfglayout.h" #include "expr.h" #include "target.h" +#include "common/common-target.h" #include "cfgloop.h" #include "ggc.h" #include "tree-pass.h" +#include "df.h" -static int can_delete_note_p (rtx); -static int can_delete_label_p (rtx); -static void commit_one_edge_insertion (edge); +static int can_delete_note_p (const_rtx); +static int can_delete_label_p (const_rtx); static basic_block rtl_split_edge (edge); static bool rtl_move_block_after (basic_block, basic_block); static int rtl_verify_flow_info (void); @@ -75,7 +78,7 @@ static void rtl_delete_block (basic_block); static basic_block rtl_redirect_edge_and_branch_force (edge, basic_block); static edge rtl_redirect_edge_and_branch (edge, basic_block); static basic_block rtl_split_block (basic_block, void *); -static void rtl_dump_bb (basic_block, FILE *, int); +static void rtl_dump_bb (basic_block, FILE *, int, int); static int rtl_verify_flow_info_1 (void); static void rtl_make_forwarder_block (edge); @@ -83,16 +86,24 @@ static void rtl_make_forwarder_block (edge); so that we may simply delete it. */ static int -can_delete_note_p (rtx note) +can_delete_note_p (const_rtx note) { - return (NOTE_KIND (note) == NOTE_INSN_DELETED - || NOTE_KIND (note) == NOTE_INSN_BASIC_BLOCK); + switch (NOTE_KIND (note)) + { + case NOTE_INSN_DELETED: + case NOTE_INSN_BASIC_BLOCK: + case NOTE_INSN_EPILOGUE_BEG: + return true; + + default: + return false; + } } /* True if a given label can be deleted. */ static int -can_delete_label_p (rtx label) +can_delete_label_p (const_rtx label) { return (!LABEL_PRESERVE_P (label) /* User declared labels must be preserved. */ @@ -137,15 +148,15 @@ delete_insn (rtx insn) /* If deleting a jump, decrement the use count of the label. Deleting the label itself should happen in the normal course of block merging. */ - if (JUMP_P (insn) - && JUMP_LABEL (insn) - && LABEL_P (JUMP_LABEL (insn))) - LABEL_NUSES (JUMP_LABEL (insn))--; - - /* Also if deleting an insn that references a label. */ - else + if (JUMP_P (insn)) { - while ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != NULL_RTX + if (JUMP_LABEL (insn) + && LABEL_P (JUMP_LABEL (insn))) + LABEL_NUSES (JUMP_LABEL (insn))--; + + /* If there are more targets, remove them too. */ + while ((note + = find_reg_note (insn, REG_LABEL_TARGET, NULL_RTX)) != NULL_RTX && LABEL_P (XEXP (note, 0))) { LABEL_NUSES (XEXP (note, 0))--; @@ -153,9 +164,15 @@ delete_insn (rtx insn) } } - if (JUMP_P (insn) - && (GET_CODE (PATTERN (insn)) == ADDR_VEC - || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)) + /* Also if deleting any insn that references a label as an operand. */ + while ((note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX)) != NULL_RTX + && LABEL_P (XEXP (note, 0))) + { + LABEL_NUSES (XEXP (note, 0))--; + remove_note (insn, note); + } + + if (JUMP_TABLE_DATA_P (insn)) { rtx pat = PATTERN (insn); int diff_vec_p = GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC; @@ -178,6 +195,7 @@ delete_insn (rtx insn) } /* Like delete_insn but also purge dead edges from BB. */ + rtx delete_insn_and_edges (rtx insn) { @@ -195,10 +213,11 @@ delete_insn_and_edges (rtx insn) } /* Unlink a chain of insns between START and FINISH, leaving notes - that must be paired. */ + that must be paired. If CLEAR_BB is true, we set bb field for + insns that cannot be removed to NULL. */ void -delete_insn_chain (rtx start, rtx finish) +delete_insn_chain (rtx start, rtx finish, bool clear_bb) { rtx next; @@ -213,26 +232,14 @@ delete_insn_chain (rtx start, rtx finish) else next = delete_insn (start); + if (clear_bb && !INSN_DELETED_P (start)) + set_block_for_insn (start, NULL); + if (start == finish) break; start = next; } } - -/* Like delete_insn but also purge dead edges from BB. */ -void -delete_insn_chain_and_edges (rtx first, rtx last) -{ - bool purge = false; - - if (INSN_P (last) - && BLOCK_FOR_INSN (last) - && BB_END (BLOCK_FOR_INSN (last)) == last) - purge = true; - delete_insn_chain (first, last); - if (purge) - purge_dead_edges (BLOCK_FOR_INSN (last)); -} /* Create a new basic block consisting of the instructions between HEAD and END inclusive. This function is designed to allow fast BB construction - reuses @@ -303,6 +310,7 @@ create_basic_block_structure (rtx head, rtx end, rtx bb_note, basic_block after) bb->flags = BB_NEW | BB_RTL; link_block (bb, after); SET_BASIC_BLOCK (bb->index, bb); + df_bb_refs_record (bb->index, false); update_bb_for_insn (bb); BB_SET_PARTITION (bb, BB_UNPARTITIONED); @@ -314,14 +322,14 @@ create_basic_block_structure (rtx head, rtx end, rtx bb_note, basic_block after) } /* Create new basic block consisting of instructions in between HEAD and END - and place it to the BB chain after block AFTER. END can be NULL in to - create new empty basic block before HEAD. Both END and HEAD can be NULL to - create basic block at the end of INSN chain. */ + and place it to the BB chain after block AFTER. END can be NULL to + create a new empty basic block before HEAD. Both END and HEAD can be + NULL to create basic block at the end of INSN chain. */ static basic_block rtl_create_basic_block (void *headp, void *endp, basic_block after) { - rtx head = headp, end = endp; + rtx head = (rtx) headp, end = (rtx) endp; basic_block bb; /* Grow the basic block array if needed. */ @@ -363,21 +371,17 @@ rtl_delete_block (basic_block b) label for an exception handler which can't be reached. We need to remove the label from the exception_handler_label list. */ insn = BB_HEAD (b); - if (LABEL_P (insn)) - maybe_remove_eh_handler (insn); end = get_last_bb_insn (b); /* Selectively delete the entire chain. */ BB_HEAD (b) = NULL; - delete_insn_chain (insn, end); - if (b->il.rtl->global_live_at_start) - { - FREE_REG_SET (b->il.rtl->global_live_at_start); - FREE_REG_SET (b->il.rtl->global_live_at_end); - b->il.rtl->global_live_at_start = NULL; - b->il.rtl->global_live_at_end = NULL; - } + delete_insn_chain (insn, end, true); + + + if (dump_file) + fprintf (dump_file, "deleting block %d\n", b->index); + df_bb_delete (b->index); } /* Records the basic block struct in BLOCK_FOR_INSN for every insn. */ @@ -413,21 +417,40 @@ free_bb_for_insn (void) return 0; } -struct tree_opt_pass pass_free_cfg = +static unsigned int +rest_of_pass_free_cfg (void) { - NULL, /* name */ +#ifdef DELAY_SLOTS + /* The resource.c machinery uses DF but the CFG isn't guaranteed to be + valid at that point so it would be too late to call df_analyze. */ + if (optimize > 0 && flag_delayed_branch) + { + df_note_add_problem (); + df_analyze (); + } +#endif + + free_bb_for_insn (); + return 0; +} + +struct rtl_opt_pass pass_free_cfg = +{ + { + RTL_PASS, + "*free_cfg", /* name */ NULL, /* gate */ - free_bb_for_insn, /* execute */ + rest_of_pass_free_cfg, /* execute */ NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - 0, /* tv_id */ + TV_NONE, /* tv_id */ 0, /* properties_required */ 0, /* properties_provided */ PROP_cfg, /* properties_destroyed */ 0, /* todo_flags_start */ 0, /* todo_flags_finish */ - 0 /* letter */ + } }; /* Return RTX to emit after when we want to emit code on the entry of function. */ @@ -451,22 +474,66 @@ emit_insn_at_entry (rtx insn) commit_edge_insertions (); } -/* Update insns block within BB. */ +/* Update BLOCK_FOR_INSN of insns between BEGIN and END + (or BARRIER if found) and notify df of the bb change. + The insn chain range is inclusive + (i.e. both BEGIN and END will be updated. */ + +static void +update_bb_for_insn_chain (rtx begin, rtx end, basic_block bb) +{ + rtx insn; + + end = NEXT_INSN (end); + for (insn = begin; insn != end; insn = NEXT_INSN (insn)) + if (!BARRIER_P (insn)) + df_insn_change_bb (insn, bb); +} + +/* Update BLOCK_FOR_INSN of insns in BB to BB, + and notify df of the change. */ void update_bb_for_insn (basic_block bb) { + update_bb_for_insn_chain (BB_HEAD (bb), BB_END (bb), bb); +} + + +/* Return the NOTE_INSN_BASIC_BLOCK of BB. */ +rtx +bb_note (basic_block bb) +{ + rtx note; + + note = BB_HEAD (bb); + if (LABEL_P (note)) + note = NEXT_INSN (note); + + gcc_assert (NOTE_INSN_BASIC_BLOCK_P (note)); + return note; +} + +/* Return the INSN immediately following the NOTE_INSN_BASIC_BLOCK + note associated with the BLOCK. */ + +static rtx +first_insn_after_basic_block_note (basic_block block) +{ rtx insn; - for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn)) - { - if (!BARRIER_P (insn)) - set_block_for_insn (insn, bb); - if (insn == BB_END (bb)) - break; - } + /* Get the first instruction in the block. */ + insn = BB_HEAD (block); + + if (insn == NULL_RTX) + return NULL_RTX; + if (LABEL_P (insn)) + insn = NEXT_INSN (insn); + gcc_assert (NOTE_INSN_BASIC_BLOCK_P (insn)); + + return NEXT_INSN (insn); } - + /* Creates a new basic block just after basic block B by splitting everything after specified instruction I. */ @@ -474,7 +541,7 @@ static basic_block rtl_split_block (basic_block bb, void *insnp) { basic_block new_bb; - rtx insn = insnp; + rtx insn = (rtx) insnp; edge e; edge_iterator ei; @@ -483,7 +550,26 @@ rtl_split_block (basic_block bb, void *insnp) insn = first_insn_after_basic_block_note (bb); if (insn) - insn = PREV_INSN (insn); + { + rtx next = insn; + + insn = PREV_INSN (insn); + + /* If the block contains only debug insns, insn would have + been NULL in a non-debug compilation, and then we'd end + up emitting a DELETED note. For -fcompare-debug + stability, emit the note too. */ + if (insn != BB_END (bb) + && DEBUG_INSN_P (next) + && DEBUG_INSN_P (BB_END (bb))) + { + while (next != BB_END (bb) && DEBUG_INSN_P (next)) + next = NEXT_INSN (next); + + if (next == BB_END (bb)) + emit_note_after (NOTE_INSN_DELETED, next); + } + } else insn = get_last_insn (); } @@ -505,32 +591,8 @@ rtl_split_block (basic_block bb, void *insnp) FOR_EACH_EDGE (e, ei, new_bb->succs) e->src = new_bb; - if (bb->il.rtl->global_live_at_start) - { - new_bb->il.rtl->global_live_at_start = ALLOC_REG_SET (®_obstack); - new_bb->il.rtl->global_live_at_end = ALLOC_REG_SET (®_obstack); - COPY_REG_SET (new_bb->il.rtl->global_live_at_end, bb->il.rtl->global_live_at_end); - - /* We now have to calculate which registers are live at the end - of the split basic block and at the start of the new basic - block. Start with those registers that are known to be live - at the end of the original basic block and get - propagate_block to determine which registers are live. */ - COPY_REG_SET (new_bb->il.rtl->global_live_at_start, bb->il.rtl->global_live_at_end); - propagate_block (new_bb, new_bb->il.rtl->global_live_at_start, NULL, NULL, 0); - COPY_REG_SET (bb->il.rtl->global_live_at_end, - new_bb->il.rtl->global_live_at_start); -#ifdef HAVE_conditional_execution - /* In the presence of conditional execution we are not able to update - liveness precisely. */ - if (reload_completed) - { - bb->flags |= BB_DIRTY; - new_bb->flags |= BB_DIRTY; - } -#endif - } - + /* The new block starts off being dirty. */ + df_set_bb_dirty (bb); return new_bb; } @@ -542,15 +604,20 @@ rtl_merge_blocks (basic_block a, basic_block b) { rtx b_head = BB_HEAD (b), b_end = BB_END (b), a_end = BB_END (a); rtx del_first = NULL_RTX, del_last = NULL_RTX; + rtx b_debug_start = b_end, b_debug_end = b_end; + bool forwarder_p = (b->flags & BB_FORWARDER_BLOCK) != 0; int b_empty = 0; + if (dump_file) + fprintf (dump_file, "Merging block %d into block %d...\n", b->index, + a->index); + + while (DEBUG_INSN_P (b_end)) + b_end = PREV_INSN (b_debug_start = b_end); + /* If there was a CODE_LABEL beginning B, delete it. */ if (LABEL_P (b_head)) { - /* This might have been an EH label that no longer has incoming - EH edges. Update data structures to match. */ - maybe_remove_eh_handler (b_head); - /* Detect basic blocks with nothing but a label. This can happen in particular at the end of a function. */ if (b_head == b_end) @@ -608,28 +675,44 @@ rtl_merge_blocks (basic_block a, basic_block b) /* Delete everything marked above as well as crap that might be hanging out between the two blocks. */ BB_HEAD (b) = NULL; - delete_insn_chain (del_first, del_last); + delete_insn_chain (del_first, del_last, true); /* Reassociate the insns of B with A. */ if (!b_empty) { - rtx x; - - for (x = a_end; x != b_end; x = NEXT_INSN (x)) - set_block_for_insn (x, a); - - set_block_for_insn (b_end, a); + update_bb_for_insn_chain (a_end, b_debug_end, a); - a_end = b_end; + a_end = b_debug_end; + } + else if (b_end != b_debug_end) + { + /* Move any deleted labels and other notes between the end of A + and the debug insns that make up B after the debug insns, + bringing the debug insns into A while keeping the notes after + the end of A. */ + if (NEXT_INSN (a_end) != b_debug_start) + reorder_insns_nobb (NEXT_INSN (a_end), PREV_INSN (b_debug_start), + b_debug_end); + update_bb_for_insn_chain (b_debug_start, b_debug_end, a); + a_end = b_debug_end; } + df_bb_delete (b->index); BB_END (a) = a_end; - a->il.rtl->global_live_at_end = b->il.rtl->global_live_at_end; + + /* If B was a forwarder block, propagate the locus on the edge. */ + if (forwarder_p && !EDGE_SUCC (b, 0)->goto_locus) + EDGE_SUCC (b, 0)->goto_locus = EDGE_SUCC (a, 0)->goto_locus; + + if (dump_file) + fprintf (dump_file, "Merged blocks %d and %d.\n", a->index, b->index); } + /* Return true when block A and B can be merged. */ + static bool -rtl_can_merge_blocks (basic_block a,basic_block b) +rtl_can_merge_blocks (basic_block a, basic_block b) { /* If we are partitioning hot/cold basic blocks, we don't want to mess up unconditional or indirect jumps that cross between hot @@ -745,7 +828,7 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout) { rtx insn = src->il.rtl->footer; - delete_insn_chain (kill_from, BB_END (src)); + delete_insn_chain (kill_from, BB_END (src), false); /* Remove barriers but keep jumptables. */ while (insn) @@ -765,7 +848,8 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout) } } else - delete_insn_chain (kill_from, PREV_INSN (BB_HEAD (target))); + delete_insn_chain (kill_from, PREV_INSN (BB_HEAD (target)), + false); } /* If this already is simplejump, redirect it. */ @@ -801,13 +885,13 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout) INSN_UID (insn), INSN_UID (BB_END (src))); - delete_insn_chain (kill_from, insn); + delete_insn_chain (kill_from, insn, false); /* Recognize a tablejump that we are converting to a simple jump and remove its associated CODE_LABEL and ADDR_VEC or ADDR_DIFF_VEC. */ if (tablejump_p (insn, &label, &table)) - delete_insn_chain (label, table); + delete_insn_chain (label, table, false); barrier = next_nonnote_insn (BB_END (src)); if (!barrier || !BARRIER_P (barrier)) @@ -820,11 +904,9 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout) which originally were or were created before jump table are inside the basic block. */ rtx new_insn = BB_END (src); - rtx tmp; - for (tmp = NEXT_INSN (BB_END (src)); tmp != barrier; - tmp = NEXT_INSN (tmp)) - set_block_for_insn (tmp, src); + update_bb_for_insn_chain (NEXT_INSN (BB_END (src)), + PREV_INSN (barrier), src); NEXT_INSN (PREV_INSN (new_insn)) = NEXT_INSN (new_insn); PREV_INSN (NEXT_INSN (new_insn)) = PREV_INSN (new_insn); @@ -854,35 +936,28 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout) if (e->dest != target) redirect_edge_succ (e, target); - return e; } -/* Redirect edge representing branch of (un)conditional jump or tablejump, - NULL on failure */ -static edge -redirect_branch_edge (edge e, basic_block target) +/* Subroutine of redirect_branch_edge that tries to patch the jump + instruction INSN so that it reaches block NEW. Do this + only when it originally reached block OLD. Return true if this + worked or the original target wasn't OLD, return false if redirection + doesn't work. */ + +static bool +patch_jump_insn (rtx insn, rtx old_label, basic_block new_bb) { rtx tmp; - rtx old_label = BB_HEAD (e->dest); - basic_block src = e->src; - rtx insn = BB_END (src); - - /* We can only redirect non-fallthru edges of jump insn. */ - if (e->flags & EDGE_FALLTHRU) - return NULL; - else if (!JUMP_P (insn)) - return NULL; - /* Recognize a tablejump and adjust all matching cases. */ if (tablejump_p (insn, NULL, &tmp)) { rtvec vec; int j; - rtx new_label = block_label (target); + rtx new_label = block_label (new_bb); - if (target == EXIT_BLOCK_PTR) - return NULL; + if (new_bb == EXIT_BLOCK_PTR) + return false; if (GET_CODE (PATTERN (tmp)) == ADDR_VEC) vec = XVEC (PATTERN (tmp), 0); else @@ -909,6 +984,48 @@ redirect_branch_edge (edge e, basic_block target) ++LABEL_NUSES (new_label); } } + else if ((tmp = extract_asm_operands (PATTERN (insn))) != NULL) + { + int i, n = ASM_OPERANDS_LABEL_LENGTH (tmp); + rtx new_label, note; + + if (new_bb == EXIT_BLOCK_PTR) + return false; + new_label = block_label (new_bb); + + for (i = 0; i < n; ++i) + { + rtx old_ref = ASM_OPERANDS_LABEL (tmp, i); + gcc_assert (GET_CODE (old_ref) == LABEL_REF); + if (XEXP (old_ref, 0) == old_label) + { + ASM_OPERANDS_LABEL (tmp, i) + = gen_rtx_LABEL_REF (Pmode, new_label); + --LABEL_NUSES (old_label); + ++LABEL_NUSES (new_label); + } + } + + if (JUMP_LABEL (insn) == old_label) + { + JUMP_LABEL (insn) = new_label; + note = find_reg_note (insn, REG_LABEL_TARGET, new_label); + if (note) + remove_note (insn, note); + } + else + { + note = find_reg_note (insn, REG_LABEL_TARGET, old_label); + if (note) + remove_note (insn, note); + if (JUMP_LABEL (insn) != new_label + && !find_reg_note (insn, REG_LABEL_TARGET, new_label)) + add_reg_note (insn, REG_LABEL_TARGET, new_label); + } + while ((note = find_reg_note (insn, REG_LABEL_OPERAND, old_label)) + != NULL_RTX) + XEXP (note, 0) = new_label; + } else { /* ?? We may play the games with moving the named labels from @@ -917,20 +1034,54 @@ redirect_branch_edge (edge e, basic_block target) if (computed_jump_p (insn) /* A return instruction can't be redirected. */ || returnjump_p (insn)) - return NULL; + return false; - /* If the insn doesn't go where we think, we're confused. */ - gcc_assert (JUMP_LABEL (insn) == old_label); - - /* If the substitution doesn't succeed, die. This can happen - if the back end emitted unrecognizable instructions or if - target is exit block on some arches. */ - if (!redirect_jump (insn, block_label (target), 0)) + if (!currently_expanding_to_rtl || JUMP_LABEL (insn) == old_label) { - gcc_assert (target == EXIT_BLOCK_PTR); - return NULL; + /* If the insn doesn't go where we think, we're confused. */ + gcc_assert (JUMP_LABEL (insn) == old_label); + + /* If the substitution doesn't succeed, die. This can happen + if the back end emitted unrecognizable instructions or if + target is exit block on some arches. */ + if (!redirect_jump (insn, block_label (new_bb), 0)) + { + gcc_assert (new_bb == EXIT_BLOCK_PTR); + return false; + } } } + return true; +} + + +/* Redirect edge representing branch of (un)conditional jump or tablejump, + NULL on failure */ +static edge +redirect_branch_edge (edge e, basic_block target) +{ + rtx old_label = BB_HEAD (e->dest); + basic_block src = e->src; + rtx insn = BB_END (src); + + /* We can only redirect non-fallthru edges of jump insn. */ + if (e->flags & EDGE_FALLTHRU) + return NULL; + else if (!JUMP_P (insn) && !currently_expanding_to_rtl) + return NULL; + + if (!currently_expanding_to_rtl) + { + if (!patch_jump_insn (insn, old_label, target)) + return NULL; + } + else + /* When expanding this BB might actually contain multiple + jumps (i.e. not yet split by find_many_sub_basic_blocks). + Redirect all of those that match our label. */ + FOR_BB_INSNS (src, insn) + if (JUMP_P (insn) && !patch_jump_insn (insn, old_label, target)) + return NULL; if (dump_file) fprintf (dump_file, "Edge %i->%i redirected to %i\n", @@ -938,6 +1089,7 @@ redirect_branch_edge (edge e, basic_block target) if (e->dest != target) e = redirect_edge_succ_nodup (e, target); + return e; } @@ -966,7 +1118,7 @@ rtl_redirect_edge_and_branch (edge e, basic_block target) if ((ret = try_redirect_by_replacing_jump (e, target, false)) != NULL) { - src->flags |= BB_DIRTY; + df_set_bb_dirty (src); return ret; } @@ -974,20 +1126,25 @@ rtl_redirect_edge_and_branch (edge e, basic_block target) if (!ret) return NULL; - src->flags |= BB_DIRTY; + df_set_bb_dirty (src); return ret; } /* 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 ret_rtx or + 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; edge new_edge; int abnormal_edge_flags = 0; + bool asm_goto_edge = false; + int loc; /* In the case the last instruction is conditional jump to the next instruction, first redirect the jump itself and then continue @@ -1066,8 +1223,60 @@ force_nonfallthru_and_redirect (edge e, basic_block target) } } - if (EDGE_COUNT (e->src->succs) >= 2 || abnormal_edge_flags) + /* If e->src ends with asm goto, see if any of the ASM_OPERANDS_LABELs + don't point to the target or fallthru label. */ + if (JUMP_P (BB_END (e->src)) + && target != EXIT_BLOCK_PTR + && (e->flags & EDGE_FALLTHRU) + && (note = extract_asm_operands (PATTERN (BB_END (e->src))))) { + int i, n = ASM_OPERANDS_LABEL_LENGTH (note); + bool adjust_jump_target = false; + + for (i = 0; i < n; ++i) + { + if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (e->dest)) + { + LABEL_NUSES (XEXP (ASM_OPERANDS_LABEL (note, i), 0))--; + XEXP (ASM_OPERANDS_LABEL (note, i), 0) = block_label (target); + LABEL_NUSES (XEXP (ASM_OPERANDS_LABEL (note, i), 0))++; + adjust_jump_target = true; + } + if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (target)) + asm_goto_edge = true; + } + if (adjust_jump_target) + { + rtx insn = BB_END (e->src), note; + rtx old_label = BB_HEAD (e->dest); + rtx new_label = BB_HEAD (target); + + if (JUMP_LABEL (insn) == old_label) + { + JUMP_LABEL (insn) = new_label; + note = find_reg_note (insn, REG_LABEL_TARGET, new_label); + if (note) + remove_note (insn, note); + } + else + { + note = find_reg_note (insn, REG_LABEL_TARGET, old_label); + if (note) + remove_note (insn, note); + if (JUMP_LABEL (insn) != new_label + && !find_reg_note (insn, REG_LABEL_TARGET, new_label)) + add_reg_note (insn, REG_LABEL_TARGET, new_label); + } + while ((note = find_reg_note (insn, REG_LABEL_OPERAND, old_label)) + != NULL_RTX) + XEXP (note, 0) = new_label; + } + } + + if (EDGE_COUNT (e->src->succs) >= 2 || abnormal_edge_flags || asm_goto_edge) + { + gcov_type count = e->count; + int probability = e->probability; /* Create the new structures. */ /* If the old block ended with a tablejump, skip its table @@ -1078,61 +1287,79 @@ force_nonfallthru_and_redirect (edge e, basic_block target) note = NEXT_INSN (note); jump_block = create_basic_block (note, NULL, e->src); - jump_block->count = e->count; + jump_block->count = count; jump_block->frequency = EDGE_FREQUENCY (e); jump_block->loop_depth = target->loop_depth; - if (target->il.rtl->global_live_at_start) - { - jump_block->il.rtl->global_live_at_start = ALLOC_REG_SET (®_obstack); - jump_block->il.rtl->global_live_at_end = ALLOC_REG_SET (®_obstack); - COPY_REG_SET (jump_block->il.rtl->global_live_at_start, - target->il.rtl->global_live_at_start); - COPY_REG_SET (jump_block->il.rtl->global_live_at_end, - target->il.rtl->global_live_at_start); - } - /* Make sure new block ends up in correct hot/cold section. */ BB_COPY_PARTITION (jump_block, e->src); if (flag_reorder_blocks_and_partition - && targetm.have_named_sections + && targetm_common.have_named_sections && JUMP_P (BB_END (jump_block)) && !any_condjump_p (BB_END (jump_block)) && (EDGE_SUCC (jump_block, 0)->flags & EDGE_CROSSING)) - REG_NOTES (BB_END (jump_block)) = gen_rtx_EXPR_LIST (REG_CROSSING_JUMP, - NULL_RTX, - REG_NOTES - (BB_END - (jump_block))); + add_reg_note (BB_END (jump_block), REG_CROSSING_JUMP, NULL_RTX); /* Wire edge in. */ new_edge = make_edge (e->src, jump_block, EDGE_FALLTHRU); - new_edge->probability = e->probability; - new_edge->count = e->count; + new_edge->probability = probability; + new_edge->count = count; /* Redirect old edge. */ redirect_edge_pred (e, jump_block); e->probability = REG_BR_PROB_BASE; + /* If asm goto has any label refs to target's label, + add also edge from asm goto bb to target. */ + if (asm_goto_edge) + { + new_edge->probability /= 2; + new_edge->count /= 2; + jump_block->count /= 2; + jump_block->frequency /= 2; + new_edge = make_edge (new_edge->src, target, + e->flags & ~EDGE_FALLTHRU); + new_edge->probability = probability - probability / 2; + new_edge->count = count - count / 2; + } + new_bb = jump_block; } else jump_block = e->src; + if (e->goto_locus && e->goto_block == NULL) + loc = e->goto_locus; + else + loc = 0; e->flags &= ~EDGE_FALLTHRU; if (target == EXIT_BLOCK_PTR) { + if (jump_label == ret_rtx) + { #ifdef HAVE_return - emit_jump_insn_after_noloc (gen_return (), BB_END (jump_block)); + emit_jump_insn_after_setloc (gen_return (), BB_END (jump_block), loc); #else - gcc_unreachable (); + 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 + } + set_return_jump_label (BB_END (jump_block)); } else { rtx label = block_label (target); - emit_jump_insn_after_noloc (gen_jump (label), BB_END (jump_block)); + emit_jump_insn_after_setloc (gen_jump (label), BB_END (jump_block), loc); JUMP_LABEL (BB_END (jump_block)) = label; LABEL_NUSES (label)++; } @@ -1143,6 +1370,7 @@ force_nonfallthru_and_redirect (edge e, basic_block target) if (abnormal_edge_flags) make_edge (src, target, abnormal_edge_flags); + df_mark_solutions_dirty (); return new_bb; } @@ -1150,10 +1378,10 @@ force_nonfallthru_and_redirect (edge e, basic_block target) (and possibly create new basic block) to make edge non-fallthru. Return newly created BB or NULL if none. */ -basic_block -force_nonfallthru (edge e) +static basic_block +rtl_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 @@ -1169,8 +1397,8 @@ rtl_redirect_edge_and_branch_force (edge e, basic_block target) /* In case the edge redirection failed, try to force it to be non-fallthru and redirect newly created simplejump. */ - e->src->flags |= BB_DIRTY; - return force_nonfallthru_and_redirect (e, target); + df_set_bb_dirty (e->src); + return force_nonfallthru_and_redirect (e, target, NULL_RTX); } /* The given edge should potentially be a fallthru edge. If that is in @@ -1217,7 +1445,7 @@ rtl_tidy_fallthru_edge (edge e) /* Selectively unlink the sequence. */ if (q != PREV_INSN (BB_HEAD (c))) - delete_insn_chain (NEXT_INSN (q), PREV_INSN (BB_HEAD (c))); + delete_insn_chain (NEXT_INSN (q), PREV_INSN (BB_HEAD (c)), false); e->flags |= EDGE_FALLTHRU; } @@ -1251,12 +1479,7 @@ rtl_split_edge (edge edge_in) Avoid existence of fallthru predecessors. */ if ((edge_in->flags & EDGE_FALLTHRU) == 0) { - edge e; - edge_iterator ei; - - FOR_EACH_EDGE (e, ei, edge_in->dest->preds) - if (e->flags & EDGE_FALLTHRU) - break; + edge e = find_fallthru_edge (edge_in->dest->preds); if (e) force_nonfallthru (e); @@ -1269,8 +1492,8 @@ rtl_split_edge (edge edge_in) before = NULL_RTX; /* If this is a fall through edge to the exit block, the blocks might be - not adjacent, and the right place is the after the source. */ - if (edge_in->flags & EDGE_FALLTHRU && edge_in->dest == EXIT_BLOCK_PTR) + not adjacent, and the right place is after the source. */ + if ((edge_in->flags & EDGE_FALLTHRU) && edge_in->dest == EXIT_BLOCK_PTR) { before = NEXT_INSN (BB_END (edge_in->src)); bb = create_basic_block (before, NULL, edge_in->src); @@ -1283,17 +1506,6 @@ rtl_split_edge (edge edge_in) BB_COPY_PARTITION (bb, edge_in->dest); } - /* ??? This info is likely going to be out of date very soon. */ - if (edge_in->dest->il.rtl->global_live_at_start) - { - bb->il.rtl->global_live_at_start = ALLOC_REG_SET (®_obstack); - bb->il.rtl->global_live_at_end = ALLOC_REG_SET (®_obstack); - COPY_REG_SET (bb->il.rtl->global_live_at_start, - edge_in->dest->il.rtl->global_live_at_start); - COPY_REG_SET (bb->il.rtl->global_live_at_end, - edge_in->dest->il.rtl->global_live_at_start); - } - make_single_succ_edge (bb, edge_in->dest, EDGE_FALLTHRU); /* For non-fallthru edges, we must adjust the predecessor's @@ -1304,7 +1516,22 @@ rtl_split_edge (edge edge_in) gcc_assert (redirected); } else - redirect_edge_succ (edge_in, bb); + { + if (edge_in->src != ENTRY_BLOCK_PTR) + { + /* For asm goto even splitting of fallthru edge might + need insn patching, as other labels might point to the + old label. */ + rtx last = BB_END (edge_in->src); + if (last + && JUMP_P (last) + && edge_in->dest != EXIT_BLOCK_PTR + && extract_asm_operands (PATTERN (last)) != NULL_RTX + && patch_jump_insn (last, before, bb)) + df_set_bb_dirty (edge_in->src); + } + redirect_edge_succ (edge_in, bb); + } return bb; } @@ -1333,105 +1560,87 @@ insert_insn_on_edge (rtx pattern, edge e) /* Update the CFG for the instructions queued on edge E. */ -static void +void commit_one_edge_insertion (edge e) { rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last; - basic_block bb = NULL; + basic_block bb; /* Pull the insns off the edge now since the edge might go away. */ insns = e->insns.r; e->insns.r = NULL_RTX; - if (!before && !after) - { - /* Figure out where to put these things. If the destination has - one predecessor, insert there. Except for the exit block. */ - if (single_pred_p (e->dest) && e->dest != EXIT_BLOCK_PTR) - { - bb = e->dest; - - /* Get the location correct wrt a code label, and "nice" wrt - a basic block note, and before everything else. */ - tmp = BB_HEAD (bb); - if (LABEL_P (tmp)) - tmp = NEXT_INSN (tmp); - if (NOTE_INSN_BASIC_BLOCK_P (tmp)) - tmp = NEXT_INSN (tmp); - if (tmp == BB_HEAD (bb)) - before = tmp; - else if (tmp) - after = PREV_INSN (tmp); - else - after = get_last_insn (); - } + /* Figure out where to put these insns. If the destination has + one predecessor, insert there. Except for the exit block. */ + if (single_pred_p (e->dest) && e->dest != EXIT_BLOCK_PTR) + { + bb = e->dest; + + /* Get the location correct wrt a code label, and "nice" wrt + a basic block note, and before everything else. */ + tmp = BB_HEAD (bb); + if (LABEL_P (tmp)) + tmp = NEXT_INSN (tmp); + if (NOTE_INSN_BASIC_BLOCK_P (tmp)) + tmp = NEXT_INSN (tmp); + if (tmp == BB_HEAD (bb)) + before = tmp; + else if (tmp) + after = PREV_INSN (tmp); + else + after = get_last_insn (); + } - /* If the source has one successor and the edge is not abnormal, - insert there. Except for the entry block. */ - else if ((e->flags & EDGE_ABNORMAL) == 0 - && single_succ_p (e->src) - && e->src != ENTRY_BLOCK_PTR) - { - bb = e->src; + /* If the source has one successor and the edge is not abnormal, + insert there. Except for the entry block. */ + else if ((e->flags & EDGE_ABNORMAL) == 0 + && single_succ_p (e->src) + && e->src != ENTRY_BLOCK_PTR) + { + bb = e->src; - /* It is possible to have a non-simple jump here. Consider a target - where some forms of unconditional jumps clobber a register. This - happens on the fr30 for example. + /* It is possible to have a non-simple jump here. Consider a target + where some forms of unconditional jumps clobber a register. This + happens on the fr30 for example. - We know this block has a single successor, so we can just emit - the queued insns before the jump. */ - if (JUMP_P (BB_END (bb))) - before = BB_END (bb); - else - { - /* We'd better be fallthru, or we've lost track of - what's what. */ - gcc_assert (e->flags & EDGE_FALLTHRU); - - after = BB_END (bb); - } - } - /* Otherwise we must split the edge. */ + We know this block has a single successor, so we can just emit + the queued insns before the jump. */ + if (JUMP_P (BB_END (bb))) + before = BB_END (bb); else { - bb = split_edge (e); - after = BB_END (bb); + /* We'd better be fallthru, or we've lost track of what's what. */ + gcc_assert (e->flags & EDGE_FALLTHRU); - if (flag_reorder_blocks_and_partition - && targetm.have_named_sections - && e->src != ENTRY_BLOCK_PTR - && BB_PARTITION (e->src) == BB_COLD_PARTITION - && !(e->flags & EDGE_CROSSING)) - { - rtx bb_note, cur_insn; - - bb_note = NULL_RTX; - for (cur_insn = BB_HEAD (bb); cur_insn != NEXT_INSN (BB_END (bb)); - cur_insn = NEXT_INSN (cur_insn)) - if (NOTE_INSN_BASIC_BLOCK_P (cur_insn)) - { - bb_note = cur_insn; - break; - } - - if (JUMP_P (BB_END (bb)) - && !any_condjump_p (BB_END (bb)) - && (single_succ_edge (bb)->flags & EDGE_CROSSING)) - REG_NOTES (BB_END (bb)) = gen_rtx_EXPR_LIST - (REG_CROSSING_JUMP, NULL_RTX, REG_NOTES (BB_END (bb))); - } + after = BB_END (bb); } } - /* Now that we've found the spot, do the insertion. */ + /* Otherwise we must split the edge. */ + else + { + bb = split_edge (e); + after = BB_END (bb); + + if (flag_reorder_blocks_and_partition + && targetm_common.have_named_sections + && e->src != ENTRY_BLOCK_PTR + && BB_PARTITION (e->src) == BB_COLD_PARTITION + && !(e->flags & EDGE_CROSSING) + && JUMP_P (after) + && !any_condjump_p (after) + && (single_succ_edge (bb)->flags & EDGE_CROSSING)) + add_reg_note (after, REG_CROSSING_JUMP, NULL_RTX); + } + /* Now that we've found the spot, do the insertion. */ if (before) { - emit_insn_before_noloc (insns, before); + emit_insn_before_noloc (insns, before, bb); last = prev_nonnote_insn (before); } else - last = emit_insn_after_noloc (insns, after); + last = emit_insn_after_noloc (insns, after, bb); if (returnjump_p (last)) { @@ -1452,10 +1661,6 @@ commit_one_edge_insertion (edge e) } else gcc_assert (!JUMP_P (last)); - - /* Mark the basic block for find_many_sub_basic_blocks. */ - if (current_ir_type () != IR_RTL_CFGLAYOUT) - bb->aux = &bb->aux; } /* Update the CFG for all queued instructions. */ @@ -1464,8 +1669,6 @@ void commit_edge_insertions (void) { basic_block bb; - sbitmap blocks; - bool changed = false; #ifdef ENABLE_CHECKING verify_flow_info (); @@ -1478,72 +1681,51 @@ commit_edge_insertions (void) FOR_EACH_EDGE (e, ei, bb->succs) if (e->insns.r) - { - changed = true; - commit_one_edge_insertion (e); - } + commit_one_edge_insertion (e); } - - if (!changed) - return; - - /* In the old rtl CFG API, it was OK to insert control flow on an - edge, apparently? In cfglayout mode, this will *not* work, and - the caller is responsible for making sure that control flow is - valid at all times. */ - if (current_ir_type () == IR_RTL_CFGLAYOUT) - return; - - blocks = sbitmap_alloc (last_basic_block); - sbitmap_zero (blocks); - FOR_EACH_BB (bb) - if (bb->aux) - { - SET_BIT (blocks, bb->index); - /* Check for forgotten bb->aux values before commit_edge_insertions - call. */ - gcc_assert (bb->aux == &bb->aux); - bb->aux = NULL; - } - find_many_sub_basic_blocks (blocks); - sbitmap_free (blocks); } + /* Print out RTL-specific basic block information (live information at start and end). */ static void -rtl_dump_bb (basic_block bb, FILE *outf, int indent) +rtl_dump_bb (basic_block bb, FILE *outf, int indent, int flags ATTRIBUTE_UNUSED) { rtx insn; rtx last; char *s_indent; - s_indent = alloca ((size_t) indent + 1); + s_indent = (char *) alloca ((size_t) indent + 1); memset (s_indent, ' ', (size_t) indent); s_indent[indent] = '\0'; - fprintf (outf, ";;%s Registers live at start: ", s_indent); - dump_regset (bb->il.rtl->global_live_at_start, outf); - putc ('\n', outf); + if (df) + { + df_dump_top (bb, outf); + putc ('\n', outf); + } + + if (bb->index != ENTRY_BLOCK && bb->index != EXIT_BLOCK) + for (insn = BB_HEAD (bb), last = NEXT_INSN (BB_END (bb)); insn != last; + insn = NEXT_INSN (insn)) + print_rtl_single (outf, insn); - for (insn = BB_HEAD (bb), last = NEXT_INSN (BB_END (bb)); insn != last; - insn = NEXT_INSN (insn)) - print_rtl_single (outf, insn); + if (df) + { + df_dump_bottom (bb, outf); + putc ('\n', outf); + } - fprintf (outf, ";;%s Registers live at end: ", s_indent); - dump_regset (bb->il.rtl->global_live_at_end, outf); - putc ('\n', outf); } /* Like print_rtl, but also print out live information for the start of each basic block. */ void -print_rtl_with_bb (FILE *outf, rtx rtx_first) +print_rtl_with_bb (FILE *outf, const_rtx rtx_first) { - rtx tmp_rtx; - + const_rtx tmp_rtx; if (rtx_first == 0) fprintf (outf, "(nil)\n"); else @@ -1556,6 +1738,9 @@ print_rtl_with_bb (FILE *outf, rtx rtx_first) basic_block bb; + if (df) + df_dump_start (outf); + FOR_EACH_BB_REVERSE (bb) { rtx x; @@ -1578,22 +1763,10 @@ print_rtl_with_bb (FILE *outf, rtx rtx_first) for (tmp_rtx = rtx_first; NULL != tmp_rtx; tmp_rtx = NEXT_INSN (tmp_rtx)) { int did_output; - edge_iterator ei; - edge e; - if ((bb = start[INSN_UID (tmp_rtx)]) != NULL) - { - fprintf (outf, ";; Start of basic block %d, registers live:", - bb->index); - dump_regset (bb->il.rtl->global_live_at_start, outf); - putc ('\n', outf); - FOR_EACH_EDGE (e, ei, bb->preds) - { - fputs (";; Pred edge ", outf); - dump_edge_info (outf, e, 0); - fputc ('\n', outf); - } - } + bb = start[INSN_UID (tmp_rtx)]; + if (bb != NULL) + dump_bb_info (bb, true, false, dump_flags, ";; ", outf); if (in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB && !NOTE_P (tmp_rtx) @@ -1604,20 +1777,9 @@ print_rtl_with_bb (FILE *outf, rtx rtx_first) did_output = print_rtl_single (outf, tmp_rtx); - if ((bb = end[INSN_UID (tmp_rtx)]) != NULL) - { - fprintf (outf, ";; End of basic block %d, registers live:", - bb->index); - dump_regset (bb->il.rtl->global_live_at_end, outf); - putc ('\n', outf); - FOR_EACH_EDGE (e, ei, bb->succs) - { - fputs (";; Succ edge ", outf); - dump_edge_info (outf, e, 1); - fputc ('\n', outf); - } - } - + bb = end[INSN_UID (tmp_rtx)]; + if (bb != NULL) + dump_bb_info (bb, false, true, dump_flags, ";; ", outf); if (did_output) putc ('\n', outf); } @@ -1627,10 +1789,10 @@ print_rtl_with_bb (FILE *outf, rtx rtx_first) free (in_bb_p); } - if (current_function_epilogue_delay_list != 0) + if (crtl->epilogue_delay_list != 0) { fprintf (outf, "\n;; Insns in epilogue delay list:\n\n"); - for (tmp_rtx = current_function_epilogue_delay_list; tmp_rtx != 0; + for (tmp_rtx = crtl->epilogue_delay_list; tmp_rtx != 0; tmp_rtx = XEXP (tmp_rtx, 1)) print_rtl_single (outf, XEXP (tmp_rtx, 0)); } @@ -1661,11 +1823,11 @@ get_last_bb_insn (basic_block bb) end = tmp; /* Include any barriers that may follow the basic block. */ - tmp = next_nonnote_insn (end); + tmp = next_nonnote_insn_bb (end); while (tmp && BARRIER_P (tmp)) { end = tmp; - tmp = next_nonnote_insn (end); + tmp = next_nonnote_insn_bb (end); } return end; @@ -1715,6 +1877,23 @@ rtl_verify_flow_info_1 (void) bb->index); err = 1; } + + for (insn = bb->il.rtl->header; insn; insn = NEXT_INSN (insn)) + if (!BARRIER_P (insn) + && BLOCK_FOR_INSN (insn) != NULL) + { + error ("insn %d in header of bb %d has non-NULL basic block", + INSN_UID (insn), bb->index); + err = 1; + } + for (insn = bb->il.rtl->footer; insn; insn = NEXT_INSN (insn)) + if (!BARRIER_P (insn) + && BLOCK_FOR_INSN (insn) != NULL) + { + error ("insn %d in footer of bb %d has non-NULL basic block", + INSN_UID (insn), bb->index); + err = 1; + } } /* Now check the basic blocks (boundaries etc.) */ @@ -1740,25 +1919,46 @@ rtl_verify_flow_info_1 (void) } FOR_EACH_EDGE (e, ei, bb->succs) { + bool is_crossing; + if (e->flags & EDGE_FALLTHRU) + n_fallthru++, fallthru = e; + + is_crossing = (BB_PARTITION (e->src) != BB_PARTITION (e->dest) + && e->src != ENTRY_BLOCK_PTR + && e->dest != EXIT_BLOCK_PTR); + if (e->flags & EDGE_CROSSING) { - n_fallthru++, fallthru = e; - if ((e->flags & EDGE_CROSSING) - || (BB_PARTITION (e->src) != BB_PARTITION (e->dest) - && e->src != ENTRY_BLOCK_PTR - && e->dest != EXIT_BLOCK_PTR)) - { + if (!is_crossing) + { + error ("EDGE_CROSSING incorrectly set across same section"); + err = 1; + } + if (e->flags & EDGE_FALLTHRU) + { error ("fallthru edge crosses section boundary (bb %i)", e->src->index); err = 1; } + if (e->flags & EDGE_EH) + { + error ("EH edge crosses section boundary (bb %i)", + e->src->index); + err = 1; + } + } + else if (is_crossing) + { + error ("EDGE_CROSSING missing across section boundary"); + err = 1; } if ((e->flags & ~(EDGE_DFS_BACK | EDGE_CAN_FALLTHRU | EDGE_IRREDUCIBLE_LOOP | EDGE_LOOP_EXIT - | EDGE_CROSSING)) == 0) + | EDGE_CROSSING + | EDGE_PRESERVE)) == 0) n_branch++; if (e->flags & EDGE_ABNORMAL_CALL) @@ -1770,12 +1970,16 @@ rtl_verify_flow_info_1 (void) n_abnormal++; } - if (n_eh && GET_CODE (PATTERN (BB_END (bb))) != RESX - && !find_reg_note (BB_END (bb), REG_EH_REGION, NULL_RTX)) + if (n_eh && !find_reg_note (BB_END (bb), REG_EH_REGION, NULL_RTX)) { error ("missing REG_EH_REGION note in the end of bb %i", bb->index); err = 1; } + if (n_eh > 1) + { + error ("too many eh edges %i", bb->index); + err = 1; + } if (n_branch && (!JUMP_P (BB_END (bb)) || (n_branch > 1 && (any_uncondjump_p (BB_END (bb)) @@ -1791,7 +1995,8 @@ rtl_verify_flow_info_1 (void) } if (n_branch != 1 && any_uncondjump_p (BB_END (bb))) { - error ("wrong amount of branch edges after unconditional jump %i", bb->index); + error ("wrong number of branch edges after unconditional jump %i", + bb->index); err = 1; } if (n_branch != 1 && any_condjump_p (BB_END (bb)) @@ -1914,14 +2119,24 @@ rtl_verify_flow_info (void) FOR_EACH_BB_REVERSE (bb) { edge e; - edge_iterator ei; rtx head = BB_HEAD (bb); rtx end = BB_END (bb); - /* Verify the end of the basic block is in the INSN chain. */ for (x = last_head; x != NULL_RTX; x = PREV_INSN (x)) - if (x == end) - break; + { + /* Verify the end of the basic block is in the INSN chain. */ + if (x == end) + break; + + /* And that the code outside of basic blocks has NULL bb field. */ + if (!BARRIER_P (x) + && BLOCK_FOR_INSN (x) != NULL) + { + error ("insn %d outside of basic blocks has non-NULL bb field", + INSN_UID (x)); + err = 1; + } + } if (!x) { @@ -1955,25 +2170,25 @@ rtl_verify_flow_info (void) err = 1; } - last_head = x; + last_head = PREV_INSN (x); - FOR_EACH_EDGE (e, ei, bb->succs) - if (e->flags & EDGE_FALLTHRU) - break; + e = find_fallthru_edge (bb->succs); if (!e) { rtx insn; /* Ensure existence of barrier in BB with no fallthru edges. */ - for (insn = BB_END (bb); !insn || !BARRIER_P (insn); - insn = NEXT_INSN (insn)) - if (!insn - || NOTE_INSN_BASIC_BLOCK_P (insn)) + for (insn = NEXT_INSN (BB_END (bb)); ; insn = NEXT_INSN (insn)) + { + if (!insn || NOTE_INSN_BASIC_BLOCK_P (insn)) { error ("missing barrier after block %i", bb->index); err = 1; break; } + if (BARRIER_P (insn)) + break; + } } else if (e->src != ENTRY_BLOCK_PTR && e->dest != EXIT_BLOCK_PTR) @@ -2000,6 +2215,18 @@ rtl_verify_flow_info (void) } } + for (x = last_head; x != NULL_RTX; x = PREV_INSN (x)) + { + /* Check that the code before the first basic block has NULL + bb field. */ + if (!BARRIER_P (x) + && BLOCK_FOR_INSN (x) != NULL) + { + error ("insn %d outside of basic blocks has non-NULL bb field", + INSN_UID (x)); + err = 1; + } + } free (bb_info); num_bb_notes = 0; @@ -2029,9 +2256,7 @@ rtl_verify_flow_info (void) case CODE_LABEL: /* An addr_vec is placed outside any basic block. */ if (NEXT_INSN (x) - && JUMP_P (NEXT_INSN (x)) - && (GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_DIFF_VEC - || GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_VEC)) + && JUMP_TABLE_DATA_P (NEXT_INSN (x))) x = NEXT_INSN (x); /* But in any case, non-deletable labels can appear anywhere. */ @@ -2071,6 +2296,11 @@ purge_dead_edges (basic_block bb) bool found; edge_iterator ei; + if (DEBUG_INSN_P (insn) && insn != BB_HEAD (bb)) + do + insn = PREV_INSN (insn); + while ((DEBUG_INSN_P (insn) || NOTE_P (insn)) && insn != BB_HEAD (bb)); + /* If this instruction cannot trap, remove REG_EH_REGION notes. */ if (NONJUMP_INSN_P (insn) && (note = find_reg_note (insn, REG_EH_REGION, NULL))) @@ -2086,39 +2316,35 @@ purge_dead_edges (basic_block bb) /* Cleanup abnormal edges caused by exceptions or non-local gotos. */ for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); ) { + bool remove = false; + /* There are three types of edges we need to handle correctly here: EH edges, abnormal call EH edges, and abnormal call non-EH edges. The latter can appear when nonlocal gotos are used. */ - if (e->flags & EDGE_EH) + if (e->flags & EDGE_ABNORMAL_CALL) { - if (can_throw_internal (BB_END (bb)) - /* If this is a call edge, verify that this is a call insn. */ - && (! (e->flags & EDGE_ABNORMAL_CALL) - || CALL_P (BB_END (bb)))) - { - ei_next (&ei); - continue; - } + if (!CALL_P (insn)) + remove = true; + else if (can_nonlocal_goto (insn)) + ; + else if ((e->flags & EDGE_EH) && can_throw_internal (insn)) + ; + else if (flag_tm && find_reg_note (insn, REG_TM, NULL)) + ; + else + remove = true; } - else if (e->flags & EDGE_ABNORMAL_CALL) + else if (e->flags & EDGE_EH) + remove = !can_throw_internal (insn); + + if (remove) { - if (CALL_P (BB_END (bb)) - && (! (note = find_reg_note (insn, REG_EH_REGION, NULL)) - || INTVAL (XEXP (note, 0)) >= 0)) - { - ei_next (&ei); - continue; - } + remove_edge (e); + df_set_bb_dirty (bb); + purged = true; } else - { - ei_next (&ei); - continue; - } - - remove_edge (e); - bb->flags |= BB_DIRTY; - purged = true; + ei_next (&ei); } if (JUMP_P (insn)) @@ -2185,7 +2411,7 @@ purge_dead_edges (basic_block bb) } /* We do not need this edge. */ - bb->flags |= BB_DIRTY; + df_set_bb_dirty (bb); purged = true; remove_edge (e); } @@ -2257,7 +2483,7 @@ purge_dead_edges (basic_block bb) { if (!(e->flags & (EDGE_FALLTHRU | EDGE_FAKE))) { - bb->flags |= BB_DIRTY; + df_set_bb_dirty (bb); remove_edge (e); purged = true; } @@ -2295,12 +2521,101 @@ purge_all_dead_edges (void) return purged; } +/* This is used by a few passes that emit some instructions after abnormal + calls, moving the basic block's end, while they in fact do want to emit + them on the fallthru edge. Look for abnormal call edges, find backward + the call in the block and insert the instructions on the edge instead. + + Similarly, handle instructions throwing exceptions internally. + + Return true when instructions have been found and inserted on edges. */ + +bool +fixup_abnormal_edges (void) +{ + bool inserted = false; + basic_block bb; + + FOR_EACH_BB (bb) + { + edge e; + edge_iterator ei; + + /* Look for cases we are interested in - calls or instructions causing + exceptions. */ + FOR_EACH_EDGE (e, ei, bb->succs) + if ((e->flags & EDGE_ABNORMAL_CALL) + || ((e->flags & (EDGE_ABNORMAL | EDGE_EH)) + == (EDGE_ABNORMAL | EDGE_EH))) + break; + + if (e && !CALL_P (BB_END (bb)) && !can_throw_internal (BB_END (bb))) + { + rtx insn; + + /* Get past the new insns generated. Allow notes, as the insns + may be already deleted. */ + insn = BB_END (bb); + while ((NONJUMP_INSN_P (insn) || NOTE_P (insn)) + && !can_throw_internal (insn) + && insn != BB_HEAD (bb)) + insn = PREV_INSN (insn); + + if (CALL_P (insn) || can_throw_internal (insn)) + { + rtx stop, next; + + e = find_fallthru_edge (bb->succs); + + stop = NEXT_INSN (BB_END (bb)); + BB_END (bb) = insn; + + for (insn = NEXT_INSN (insn); insn != stop; insn = next) + { + next = NEXT_INSN (insn); + if (INSN_P (insn)) + { + delete_insn (insn); + + /* Sometimes there's still the return value USE. + If it's placed after a trapping call (i.e. that + call is the last insn anyway), we have no fallthru + edge. Simply delete this use and don't try to insert + on the non-existent edge. */ + if (GET_CODE (PATTERN (insn)) != USE) + { + /* We're not deleting it, we're moving it. */ + INSN_DELETED_P (insn) = 0; + PREV_INSN (insn) = NULL_RTX; + NEXT_INSN (insn) = NULL_RTX; + + insert_insn_on_edge (insn, e); + inserted = true; + } + } + else if (!BARRIER_P (insn)) + set_block_for_insn (insn, NULL); + } + } + + /* It may be that we don't find any trapping insn. In this + case we discovered quite late that the insn that had been + marked as can_throw_internal in fact couldn't trap at all. + So we should in fact delete the EH edges out of the block. */ + else + purge_dead_edges (bb); + } + } + + return inserted; +} + /* Same as split_block but update cfg_layout structures. */ static basic_block cfg_layout_split_block (basic_block bb, void *insnp) { - rtx insn = insnp; + rtx insn = (rtx) insnp; basic_block new_bb = rtl_split_block (bb, insn); new_bb->il.rtl->footer = bb->il.rtl->footer; @@ -2309,7 +2624,6 @@ cfg_layout_split_block (basic_block bb, void *insnp) return new_bb; } - /* Redirect Edge to DEST. */ static edge cfg_layout_redirect_edge_and_branch (edge e, basic_block dest) @@ -2326,7 +2640,7 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest) if (e->src != ENTRY_BLOCK_PTR && (ret = try_redirect_by_replacing_jump (e, dest, true))) { - src->flags |= BB_DIRTY; + df_set_bb_dirty (src); return ret; } @@ -2337,7 +2651,7 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest) fprintf (dump_file, "Redirecting entry edge from bb %i to %i\n", e->src->index, dest->index); - e->src->flags |= BB_DIRTY; + df_set_bb_dirty (e->src); redirect_edge_succ (e, dest); return e; } @@ -2362,9 +2676,9 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest) e->flags &= ~EDGE_FALLTHRU; redirected = redirect_branch_edge (e, dest); gcc_assert (redirected); - e->flags |= EDGE_FALLTHRU; - e->src->flags |= BB_DIRTY; - return e; + redirected->flags |= EDGE_FALLTHRU; + df_set_bb_dirty (redirected->src); + return redirected; } /* In case we are redirecting fallthru edge to the branch edge of conditional jump, remove it. */ @@ -2378,10 +2692,10 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest) && onlyjump_p (BB_END (src))) delete_insn (BB_END (src)); } - ret = redirect_edge_succ_nodup (e, dest); if (dump_file) - fprintf (dump_file, "Fallthru edge %i->%i redirected to %i\n", + fprintf (dump_file, "Redirecting fallthru edge %i->%i to %i\n", e->src->index, e->dest->index, dest->index); + ret = redirect_edge_succ_nodup (e, dest); } else ret = redirect_branch_edge (e, dest); @@ -2389,7 +2703,7 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest) /* We don't want simplejumps in the insn stream during cfglayout. */ gcc_assert (!simplejump_p (BB_END (src))); - src->flags |= BB_DIRTY; + df_set_bb_dirty (src); return ret; } @@ -2487,6 +2801,7 @@ cfg_layout_delete_block (basic_block bb) } /* Return true when blocks A and B can be safely merged. */ + static bool cfg_layout_can_merge_blocks_p (basic_block a, basic_block b) { @@ -2503,6 +2818,16 @@ cfg_layout_can_merge_blocks_p (basic_block a, basic_block b) if (BB_PARTITION (a) != BB_PARTITION (b)) return false; + /* If we would end up moving B's instructions, make sure it doesn't fall + through into the exit block, since we cannot recover from a fallthrough + edge into the exit block occurring in the middle of a function. */ + if (NEXT_INSN (BB_END (a)) != BB_HEAD (b)) + { + edge e = find_fallthru_edge (b->succs); + if (e && e->dest == EXIT_BLOCK_PTR) + return false; + } + /* There must be exactly one edge in between the blocks. */ return (single_succ_p (a) && single_succ (a) == b @@ -2524,17 +2849,17 @@ cfg_layout_can_merge_blocks_p (basic_block a, basic_block b) static void cfg_layout_merge_blocks (basic_block a, basic_block b) { -#ifdef ENABLE_CHECKING - gcc_assert (cfg_layout_can_merge_blocks_p (a, b)); -#endif + bool forwarder_p = (b->flags & BB_FORWARDER_BLOCK) != 0; + + gcc_checking_assert (cfg_layout_can_merge_blocks_p (a, b)); + + if (dump_file) + fprintf (dump_file, "Merging block %d into block %d...\n", b->index, + a->index); /* If there was a CODE_LABEL beginning B, delete it. */ if (LABEL_P (BB_HEAD (b))) { - /* This might have been an EH label that no longer has incoming - EH edges. Update data structures to match. */ - maybe_remove_eh_handler (BB_HEAD (b)); - delete_insn (BB_HEAD (b)); } @@ -2544,13 +2869,46 @@ cfg_layout_merge_blocks (basic_block a, basic_block b) try_redirect_by_replacing_jump (EDGE_SUCC (a, 0), b, true); gcc_assert (!JUMP_P (BB_END (a))); + /* When not optimizing and the edge is the only place in RTL which holds + some unique locus, emit a nop with that locus in between. */ + if (!optimize && EDGE_SUCC (a, 0)->goto_locus) + { + rtx insn = BB_END (a), end = PREV_INSN (BB_HEAD (a)); + int goto_locus = EDGE_SUCC (a, 0)->goto_locus; + + while (insn != end && (!INSN_P (insn) || INSN_LOCATOR (insn) == 0)) + insn = PREV_INSN (insn); + if (insn != end && locator_eq (INSN_LOCATOR (insn), goto_locus)) + goto_locus = 0; + else + { + insn = BB_HEAD (b); + end = NEXT_INSN (BB_END (b)); + while (insn != end && !INSN_P (insn)) + insn = NEXT_INSN (insn); + if (insn != end && INSN_LOCATOR (insn) != 0 + && locator_eq (INSN_LOCATOR (insn), goto_locus)) + goto_locus = 0; + } + if (goto_locus) + { + BB_END (a) = emit_insn_after_noloc (gen_nop (), BB_END (a), a); + INSN_LOCATOR (BB_END (a)) = goto_locus; + } + } + /* Possible line number notes should appear in between. */ if (b->il.rtl->header) { rtx first = BB_END (a), last; - last = emit_insn_after_noloc (b->il.rtl->header, BB_END (a)); - delete_insn_chain (NEXT_INSN (first), last); + last = emit_insn_after_noloc (b->il.rtl->header, BB_END (a), a); + /* The above might add a BARRIER as BB_END, but as barriers + aren't valid parts of a bb, remove_insn doesn't update + BB_END if it is a barrier. So adjust BB_END here. */ + while (BB_END (a) != first && BARRIER_P (BB_END (a))) + BB_END (a) = PREV_INSN (BB_END (a)); + delete_insn_chain (NEXT_INSN (first), last, false); b->il.rtl->header = NULL; } @@ -2559,12 +2917,19 @@ cfg_layout_merge_blocks (basic_block a, basic_block b) { rtx first = unlink_insn_chain (BB_HEAD (b), BB_END (b)); - emit_insn_after_noloc (first, BB_END (a)); + emit_insn_after_noloc (first, BB_END (a), a); /* Skip possible DELETED_LABEL insn. */ if (!NOTE_INSN_BASIC_BLOCK_P (first)) first = NEXT_INSN (first); gcc_assert (NOTE_INSN_BASIC_BLOCK_P (first)); BB_HEAD (b) = NULL; + + /* emit_insn_after_noloc doesn't call df_insn_change_bb. + We need to explicitly call. */ + update_bb_for_insn_chain (NEXT_INSN (first), + BB_END (b), + a); + delete_insn (first); } /* Otherwise just re-associate the instructions. */ @@ -2572,10 +2937,8 @@ cfg_layout_merge_blocks (basic_block a, basic_block b) { rtx insn; - for (insn = BB_HEAD (b); - insn != NEXT_INSN (BB_END (b)); - insn = NEXT_INSN (insn)) - set_block_for_insn (insn, a); + update_bb_for_insn_chain (BB_HEAD (b), BB_END (b), a); + insn = BB_HEAD (b); /* Skip possible DELETED_LABEL insn. */ if (!NOTE_INSN_BASIC_BLOCK_P (insn)) @@ -2586,6 +2949,8 @@ cfg_layout_merge_blocks (basic_block a, basic_block b) delete_insn (insn); } + df_bb_delete (b->index); + /* Possible tablejumps and barriers should appear after the block. */ if (b->il.rtl->footer) { @@ -2602,11 +2967,13 @@ cfg_layout_merge_blocks (basic_block a, basic_block b) } b->il.rtl->footer = NULL; } - a->il.rtl->global_live_at_end = b->il.rtl->global_live_at_end; + + /* If B was a forwarder block, propagate the locus on the edge. */ + if (forwarder_p && !EDGE_SUCC (b, 0)->goto_locus) + EDGE_SUCC (b, 0)->goto_locus = EDGE_SUCC (a, 0)->goto_locus; if (dump_file) - fprintf (dump_file, "Merged blocks %d and %d.\n", - a->index, b->index); + fprintf (dump_file, "Merged blocks %d and %d.\n", a->index, b->index); } /* Split edge E. */ @@ -2619,18 +2986,10 @@ cfg_layout_split_edge (edge e) ? NEXT_INSN (BB_END (e->src)) : get_insns (), NULL_RTX, e->src); - /* ??? This info is likely going to be out of date very soon, but we must - create it to avoid getting an ICE later. */ - if (e->dest->il.rtl->global_live_at_start) - { - new_bb->il.rtl->global_live_at_start = ALLOC_REG_SET (®_obstack); - new_bb->il.rtl->global_live_at_end = ALLOC_REG_SET (®_obstack); - COPY_REG_SET (new_bb->il.rtl->global_live_at_start, - e->dest->il.rtl->global_live_at_start); - COPY_REG_SET (new_bb->il.rtl->global_live_at_end, - e->dest->il.rtl->global_live_at_start); - } - + if (e->dest == EXIT_BLOCK_PTR) + BB_COPY_PARTITION (new_bb, e->src); + else + BB_COPY_PARTITION (new_bb, e->dest); make_edge (new_bb, e->dest, EDGE_FALLTHRU); redirect_edge_and_branch_force (e, new_bb); @@ -2654,7 +3013,9 @@ rtl_block_ends_with_call_p (basic_block bb) while (!CALL_P (insn) && insn != BB_HEAD (bb) - && keep_with_call_p (insn)) + && (keep_with_call_p (insn) + || NOTE_P (insn) + || DEBUG_INSN_P (insn))) insn = PREV_INSN (insn); return (CALL_P (insn)); } @@ -2662,7 +3023,7 @@ rtl_block_ends_with_call_p (basic_block bb) /* Return 1 if BB ends with a conditional branch, 0 otherwise. */ static bool -rtl_block_ends_with_condjump_p (basic_block bb) +rtl_block_ends_with_condjump_p (const_basic_block bb) { return any_condjump_p (BB_END (bb)); } @@ -2671,7 +3032,7 @@ rtl_block_ends_with_condjump_p (basic_block bb) Helper function for rtl_flow_call_edges_add. */ static bool -need_fake_edge_p (rtx insn) +need_fake_edge_p (const_rtx insn) { if (!INSN_P (insn)) return false; @@ -2679,7 +3040,7 @@ need_fake_edge_p (rtx insn) if ((CALL_P (insn) && !SIBLING_CALL_P (insn) && !find_reg_note (insn, REG_NORETURN, NULL) - && !CONST_OR_PURE_CALL_P (insn))) + && !(RTL_CONST_OR_PURE_CALL_P (insn)))) return true; return ((GET_CODE (PATTERN (insn)) == ASM_OPERANDS @@ -2743,7 +3104,7 @@ rtl_flow_call_edges_add (sbitmap blocks) e = find_edge (bb, EXIT_BLOCK_PTR); if (e) { - insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e); + insert_insn_on_edge (gen_use (const0_rtx), e); commit_edge_insertions (); } } @@ -2842,7 +3203,7 @@ rtl_lv_add_condition_to_bb (basic_block first_head , op0 = force_operand (op0, NULL_RTX); op1 = force_operand (op1, NULL_RTX); do_compare_rtx_and_jump (op0, op1, comp, 0, - mode, NULL_RTX, NULL_RTX, label); + mode, NULL_RTX, NULL_RTX, label, -1); jump = get_last_insn (); JUMP_LABEL (jump) = label; LABEL_NUSES (label)++; @@ -2879,106 +3240,18 @@ void init_rtl_bb_info (basic_block bb) { gcc_assert (!bb->il.rtl); - bb->il.rtl = ggc_alloc_cleared (sizeof (struct rtl_bb_info)); -} - - -/* Add EXPR to the end of basic block BB. */ - -rtx -insert_insn_end_bb_new (rtx pat, basic_block bb) -{ - rtx insn = BB_END (bb); - rtx new_insn; - rtx pat_end = pat; - - while (NEXT_INSN (pat_end) != NULL_RTX) - pat_end = NEXT_INSN (pat_end); - - /* If the last insn is a jump, insert EXPR in front [taking care to - handle cc0, etc. properly]. Similarly we need to care trapping - instructions in presence of non-call exceptions. */ - - if (JUMP_P (insn) - || (NONJUMP_INSN_P (insn) - && (!single_succ_p (bb) - || single_succ_edge (bb)->flags & EDGE_ABNORMAL))) - { -#ifdef HAVE_cc0 - rtx note; -#endif - /* If this is a jump table, then we can't insert stuff here. Since - we know the previous real insn must be the tablejump, we insert - the new instruction just before the tablejump. */ - if (GET_CODE (PATTERN (insn)) == ADDR_VEC - || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC) - insn = prev_real_insn (insn); - -#ifdef HAVE_cc0 - /* FIXME: 'twould be nice to call prev_cc0_setter here but it aborts - if cc0 isn't set. */ - note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX); - if (note) - insn = XEXP (note, 0); - else - { - rtx maybe_cc0_setter = prev_nonnote_insn (insn); - if (maybe_cc0_setter - && INSN_P (maybe_cc0_setter) - && sets_cc0_p (PATTERN (maybe_cc0_setter))) - insn = maybe_cc0_setter; - } -#endif - /* FIXME: What if something in cc0/jump uses value set in new - insn? */ - new_insn = emit_insn_before_noloc (pat, insn); - } - - /* Likewise if the last insn is a call, as will happen in the presence - of exception handling. */ - else if (CALL_P (insn) - && (!single_succ_p (bb) - || single_succ_edge (bb)->flags & EDGE_ABNORMAL)) - { - /* Keeping in mind SMALL_REGISTER_CLASSES and parameters in registers, - we search backward and place the instructions before the first - parameter is loaded. Do this for everyone for consistency and a - presumption that we'll get better code elsewhere as well. */ - - /* Since different machines initialize their parameter registers - in different orders, assume nothing. Collect the set of all - parameter registers. */ - insn = find_first_parameter_load (insn, BB_HEAD (bb)); - - /* If we found all the parameter loads, then we want to insert - before the first parameter load. - - If we did not find all the parameter loads, then we might have - stopped on the head of the block, which could be a CODE_LABEL. - If we inserted before the CODE_LABEL, then we would be putting - the insn in the wrong basic block. In that case, put the insn - after the CODE_LABEL. Also, respect NOTE_INSN_BASIC_BLOCK. */ - while (LABEL_P (insn) - || NOTE_INSN_BASIC_BLOCK_P (insn)) - insn = NEXT_INSN (insn); - - new_insn = emit_insn_before_noloc (pat, insn); - } - else - new_insn = emit_insn_after_noloc (pat, insn); - - return new_insn; + bb->il.rtl = ggc_alloc_cleared_rtl_bb_info (); } /* Returns true if it is possible to remove edge E by redirecting it to the destination of the other edge from E->src. */ static bool -rtl_can_remove_branch_p (edge e) +rtl_can_remove_branch_p (const_edge e) { - basic_block src = e->src; - basic_block target = EDGE_SUCC (src, EDGE_SUCC (src, 0) == e)->dest; - rtx insn = BB_END (src), set; + const_basic_block src = e->src; + const_basic_block target = EDGE_SUCC (src, EDGE_SUCC (src, 0) == e)->dest; + const_rtx insn = BB_END (src), set; /* The conditions are taken from try_redirect_by_replacing_jump. */ if (target == EXIT_BLOCK_PTR) @@ -3002,6 +3275,21 @@ rtl_can_remove_branch_p (edge e) return true; } +/* We do not want to declare these functions in a header file, since they + should only be used through the cfghooks interface, and we do not want to + move them here since it would require also moving quite a lot of related + code. They are in cfglayout.c. */ +extern bool cfg_layout_can_duplicate_bb_p (const_basic_block); +extern basic_block cfg_layout_duplicate_bb (basic_block); + +static basic_block +rtl_duplicate_bb (basic_block bb) +{ + bb = cfg_layout_duplicate_bb (bb); + bb->aux = NULL; + return bb; +} + /* Implementation of CFG manipulation for linearized RTL. */ struct cfg_hooks rtl_cfg_hooks = { "rtl", @@ -3018,11 +3306,12 @@ struct cfg_hooks rtl_cfg_hooks = { rtl_merge_blocks, rtl_predict_edge, rtl_predicted_by_p, - NULL, /* can_duplicate_block_p */ - NULL, /* duplicate_block */ + cfg_layout_can_duplicate_bb_p, + rtl_duplicate_bb, rtl_split_edge, rtl_make_forwarder_block, rtl_tidy_fallthru_edge, + rtl_force_nonfallthru, rtl_block_ends_with_call_p, rtl_block_ends_with_condjump_p, rtl_flow_call_edges_add, @@ -3040,13 +3329,6 @@ struct cfg_hooks rtl_cfg_hooks = { This representation will hopefully become the default one in future version of the compiler. */ -/* We do not want to declare these functions in a header file, since they - should only be used through the cfghooks interface, and we do not want to - move them here since it would require also moving quite a lot of related - code. */ -extern bool cfg_layout_can_duplicate_bb_p (basic_block); -extern basic_block cfg_layout_duplicate_bb (basic_block); - struct cfg_hooks cfg_layout_rtl_cfg_hooks = { "cfglayout mode", rtl_verify_flow_info_1, @@ -3066,7 +3348,8 @@ struct cfg_hooks cfg_layout_rtl_cfg_hooks = { cfg_layout_duplicate_bb, cfg_layout_split_edge, rtl_make_forwarder_block, - NULL, + NULL, /* tidy_fallthru_edge */ + rtl_force_nonfallthru, rtl_block_ends_with_call_p, rtl_block_ends_with_condjump_p, rtl_flow_call_edges_add,