X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fbb-reorder.c;h=a35b8e62942be478dfea5f9d79921578f3b7be83;hp=81369eaf38e6fcdff421df93a2261c1cd8c0875a;hb=191678c8b9e88275c70a7d172f9234496fed359f;hpb=2a8e5eebabdfc6f67341798aa343f74d92be9155 diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c index 81369eaf38e..a35b8e62942 100644 --- a/gcc/bb-reorder.c +++ b/gcc/bb-reorder.c @@ -1,6 +1,6 @@ /* Basic block reordering routines for the GNU compiler. - Copyright (C) 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010 - Free Software Foundation, Inc. + Copyright (C) 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011, + 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -87,6 +87,7 @@ #include "tree-pass.h" #include "df.h" #include "bb-reorder.h" +#include "except.h" /* The number of rounds. In most cases there will only be 4 rounds, but when partitioning hot and cold basic blocks into separate sections of @@ -180,7 +181,6 @@ static fibheapkey_t bb_to_key (basic_block); static bool better_edge_p (const_basic_block, const_edge, int, int, int, int, const_edge); static void connect_traces (int, struct trace *); static bool copy_bb_p (const_basic_block, int); -static int get_uncond_jump_length (void); static bool push_to_next_round_p (const_basic_block, int, int, int, gcov_type); /* Check to see if bb should be pushed into the next round of trace @@ -1192,7 +1192,7 @@ copy_bb_p (const_basic_block bb, int code_may_grow) /* Return the length of unconditional jump instruction. */ -static int +int get_uncond_jump_length (void) { rtx label, jump; @@ -1208,6 +1208,79 @@ get_uncond_jump_length (void) return length; } +/* Emit a barrier into the footer of BB. */ + +static void +emit_barrier_after_bb (basic_block bb) +{ + rtx barrier = emit_barrier_after (BB_END (bb)); + bb->il.rtl->footer = unlink_insn_chain (barrier, barrier); +} + +/* The landing pad OLD_LP, in block OLD_BB, has edges from both partitions. + Duplicate the landing pad and split the edges so that no EH edge + crosses partitions. */ + +static void +fix_up_crossing_landing_pad (eh_landing_pad old_lp, basic_block old_bb) +{ + eh_landing_pad new_lp; + basic_block new_bb, last_bb, post_bb; + rtx new_label, jump, post_label; + unsigned new_partition; + edge_iterator ei; + edge e; + + /* Generate the new landing-pad structure. */ + new_lp = gen_eh_landing_pad (old_lp->region); + new_lp->post_landing_pad = old_lp->post_landing_pad; + new_lp->landing_pad = gen_label_rtx (); + LABEL_PRESERVE_P (new_lp->landing_pad) = 1; + + /* Put appropriate instructions in new bb. */ + new_label = emit_label (new_lp->landing_pad); + + expand_dw2_landing_pad_for_region (old_lp->region); + + post_bb = BLOCK_FOR_INSN (old_lp->landing_pad); + post_bb = single_succ (post_bb); + post_label = block_label (post_bb); + jump = emit_jump_insn (gen_jump (post_label)); + JUMP_LABEL (jump) = post_label; + + /* Create new basic block to be dest for lp. */ + last_bb = EXIT_BLOCK_PTR->prev_bb; + new_bb = create_basic_block (new_label, jump, last_bb); + new_bb->aux = last_bb->aux; + last_bb->aux = new_bb; + + emit_barrier_after_bb (new_bb); + + make_edge (new_bb, post_bb, 0); + + /* Make sure new bb is in the other partition. */ + new_partition = BB_PARTITION (old_bb); + new_partition ^= BB_HOT_PARTITION | BB_COLD_PARTITION; + BB_SET_PARTITION (new_bb, new_partition); + + /* Fix up the edges. */ + for (ei = ei_start (old_bb->preds); (e = ei_safe_edge (ei)) != NULL; ) + if (BB_PARTITION (e->src) == new_partition) + { + rtx insn = BB_END (e->src); + rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); + + gcc_assert (note != NULL); + gcc_checking_assert (INTVAL (XEXP (note, 0)) == old_lp->index); + XEXP (note, 0) = GEN_INT (new_lp->index); + + /* Adjust the edge to the new destination. */ + redirect_edge_succ (e, new_bb); + } + else + ei_next (&ei); +} + /* Find the basic blocks that are rarely executed and need to be moved to a separate section of the .o file (to cut down on paging and improve cache locality). Return a vector of all edges that cross. */ @@ -1221,7 +1294,6 @@ find_rarely_executed_basic_blocks_and_crossing_edges (void) edge_iterator ei; /* Mark which partition (hot/cold) each basic block belongs in. */ - FOR_EACH_BB (bb) { if (probably_never_executed_bb_p (bb)) @@ -1230,22 +1302,72 @@ find_rarely_executed_basic_blocks_and_crossing_edges (void) BB_SET_PARTITION (bb, BB_HOT_PARTITION); } - /* Mark every edge that crosses between sections. */ - - FOR_EACH_BB (bb) - FOR_EACH_EDGE (e, ei, bb->succs) + /* The format of .gcc_except_table does not allow landing pads to + be in a different partition as the throw. Fix this by either + moving or duplicating the landing pads. */ + if (cfun->eh->lp_array) { - if (e->src != ENTRY_BLOCK_PTR - && e->dest != EXIT_BLOCK_PTR - && BB_PARTITION (e->src) != BB_PARTITION (e->dest)) + unsigned i; + eh_landing_pad lp; + + FOR_EACH_VEC_ELT (eh_landing_pad, cfun->eh->lp_array, i, lp) { - e->flags |= EDGE_CROSSING; - VEC_safe_push (edge, heap, crossing_edges, e); + bool all_same, all_diff; + + if (lp == NULL + || lp->landing_pad == NULL_RTX + || !LABEL_P (lp->landing_pad)) + continue; + + all_same = all_diff = true; + bb = BLOCK_FOR_INSN (lp->landing_pad); + FOR_EACH_EDGE (e, ei, bb->preds) + { + gcc_assert (e->flags & EDGE_EH); + if (BB_PARTITION (bb) == BB_PARTITION (e->src)) + all_diff = false; + else + all_same = false; + } + + if (all_same) + ; + else if (all_diff) + { + int which = BB_PARTITION (bb); + which ^= BB_HOT_PARTITION | BB_COLD_PARTITION; + BB_SET_PARTITION (bb, which); + } + else + fix_up_crossing_landing_pad (lp, bb); } - else - e->flags &= ~EDGE_CROSSING; } + /* Mark every edge that crosses between sections. */ + + FOR_EACH_BB (bb) + FOR_EACH_EDGE (e, ei, bb->succs) + { + unsigned int flags = e->flags; + + /* We should never have EDGE_CROSSING set yet. */ + gcc_checking_assert ((flags & EDGE_CROSSING) == 0); + + if (e->src != ENTRY_BLOCK_PTR + && e->dest != EXIT_BLOCK_PTR + && BB_PARTITION (e->src) != BB_PARTITION (e->dest)) + { + VEC_safe_push (edge, heap, crossing_edges, e); + flags |= EDGE_CROSSING; + } + + /* Now that we've split eh edges as appropriate, allow landing pads + to be merged with the post-landing pads. */ + flags &= ~EDGE_PRESERVE; + + e->flags = flags; + } + return crossing_edges; } @@ -1262,7 +1384,7 @@ add_labels_and_missing_jumps (VEC(edge, heap) *crossing_edges) { basic_block src = e->src; basic_block dest = e->dest; - rtx label, barrier, new_jump; + rtx label, new_jump; if (dest == EXIT_BLOCK_PTR) continue; @@ -1288,10 +1410,10 @@ add_labels_and_missing_jumps (VEC(edge, heap) *crossing_edges) new_jump = emit_jump_insn_after (gen_jump (label), BB_END (src)); BB_END (src) = new_jump; - barrier = emit_barrier_after (new_jump); JUMP_LABEL (new_jump) = label; LABEL_NUSES (label) += 1; - src->il.rtl->footer = unlink_insn_chain (barrier, barrier); + + emit_barrier_after_bb (src); /* Mark edge as non-fallthru. */ e->flags &= ~EDGE_FALLTHRU; @@ -1321,7 +1443,6 @@ fix_up_fall_thru_edges (void) int invert_worked; rtx old_jump; rtx fall_thru_label; - rtx barrier; FOR_EACH_BB (cur_bb) { @@ -1451,19 +1572,7 @@ fix_up_fall_thru_edges (void) } /* Add barrier after new jump */ - - if (new_bb) - { - barrier = emit_barrier_after (BB_END (new_bb)); - new_bb->il.rtl->footer = unlink_insn_chain (barrier, - barrier); - } - else - { - barrier = emit_barrier_after (BB_END (cur_bb)); - cur_bb->il.rtl->footer = unlink_insn_chain (barrier, - barrier); - } + emit_barrier_after_bb (new_bb ? new_bb : cur_bb); } } } @@ -1526,7 +1635,6 @@ fix_crossing_conditional_branches (void) { basic_block cur_bb; basic_block new_bb; - basic_block last_bb; basic_block dest; edge succ1; edge succ2; @@ -1536,10 +1644,6 @@ fix_crossing_conditional_branches (void) rtx set_src; rtx old_label = NULL_RTX; rtx new_label; - rtx new_jump; - rtx barrier; - - last_bb = EXIT_BLOCK_PTR->prev_bb; FOR_EACH_BB (cur_bb) { @@ -1602,38 +1706,28 @@ fix_crossing_conditional_branches (void) new_label = block_label (new_bb); else { + basic_block last_bb; + rtx new_jump; + /* Create new basic block to be dest for conditional jump. */ - new_bb = create_basic_block (NULL, NULL, last_bb); - new_bb->aux = last_bb->aux; - last_bb->aux = new_bb; - last_bb = new_bb; /* Put appropriate instructions in new bb. */ new_label = gen_label_rtx (); - emit_label_before (new_label, BB_HEAD (new_bb)); - BB_HEAD (new_bb) = new_label; + emit_label (new_label); - if (GET_CODE (old_label) == LABEL_REF) - { - old_label = JUMP_LABEL (old_jump); - new_jump = emit_jump_insn_after (gen_jump - (old_label), - BB_END (new_bb)); - } - else - { - gcc_assert (HAVE_return - && GET_CODE (old_label) == RETURN); - new_jump = emit_jump_insn_after (gen_return (), - BB_END (new_bb)); - } - - barrier = emit_barrier_after (new_jump); + gcc_assert (GET_CODE (old_label) == LABEL_REF); + old_label = JUMP_LABEL (old_jump); + new_jump = emit_jump_insn (gen_jump (old_label)); JUMP_LABEL (new_jump) = old_label; - new_bb->il.rtl->footer = unlink_insn_chain (barrier, - barrier); + + last_bb = EXIT_BLOCK_PTR->prev_bb; + new_bb = create_basic_block (new_label, new_jump, last_bb); + new_bb->aux = last_bb->aux; + last_bb->aux = new_bb; + + emit_barrier_after_bb (new_bb); /* Make sure new bb is in same partition as source of conditional branch. */ @@ -1872,8 +1966,10 @@ insert_section_boundary_note (void) rtx new_note; int first_partition = 0; - if (flag_reorder_blocks_and_partition) - FOR_EACH_BB (bb) + if (!flag_reorder_blocks_and_partition) + return; + + FOR_EACH_BB (bb) { if (!first_partition) first_partition = BB_PARTITION (bb); @@ -2127,6 +2223,8 @@ partition_hot_cold_basic_blocks (void) if (n_basic_blocks <= NUM_FIXED_BLOCKS + 1) return 0; + df_set_flags (DF_DEFER_INSN_RESCAN); + crossing_edges = find_rarely_executed_basic_blocks_and_crossing_edges (); if (crossing_edges == NULL) return 0; @@ -2156,8 +2254,43 @@ partition_hot_cold_basic_blocks (void) add_reg_crossing_jump_notes (); + /* Clear bb->aux fields that the above routines were using. */ + clear_aux_for_blocks (); + VEC_free (edge, heap, crossing_edges); + /* ??? FIXME: DF generates the bb info for a block immediately. + And by immediately, I mean *during* creation of the block. + + #0 df_bb_refs_collect + #1 in df_bb_refs_record + #2 in create_basic_block_structure + + Which means that the bb_has_eh_pred test in df_bb_refs_collect + will *always* fail, because no edges can have been added to the + block yet. Which of course means we don't add the right + artificial refs, which means we fail df_verify (much) later. + + Cleanest solution would seem to make DF_DEFER_INSN_RESCAN imply + that we also shouldn't grab data from the new blocks those new + insns are in either. In this way one can create the block, link + it up properly, and have everything Just Work later, when deferred + insns are processed. + + In the meantime, we have no other option but to throw away all + of the DF data and recompute it all. */ + if (cfun->eh->lp_array) + { + df_finish_pass (true); + df_scan_alloc (NULL); + df_scan_blocks (); + /* Not all post-landing pads use all of the EH_RETURN_DATA_REGNO + data. We blindly generated all of them when creating the new + landing pad. Delete those assignments we don't use. */ + df_set_flags (DF_LR_RUN_DCE); + df_analyze (); + } + return TODO_verify_flow | TODO_verify_rtl_sharing; } @@ -2166,7 +2299,17 @@ gate_handle_reorder_blocks (void) { if (targetm.cannot_modify_jumps_p ()) return false; - return (optimize > 0); + /* Don't reorder blocks when optimizing for size because extra jump insns may + be created; also barrier may create extra padding. + + More correctly we should have a block reordering mode that tried to + minimize the combined size of all the jumps. This would more or less + automatically remove extra jumps, but would also try to use more short + jumps instead of long jumps. */ + if (!optimize_function_for_speed_p (cfun)) + return false; + return (optimize > 0 + && (flag_reorder_blocks || flag_reorder_blocks_and_partition)); } @@ -2180,19 +2323,8 @@ rest_of_handle_reorder_blocks (void) splitting possibly introduced more crossjumping opportunities. */ cfg_layout_initialize (CLEANUP_EXPENSIVE); - if ((flag_reorder_blocks || flag_reorder_blocks_and_partition) - /* Don't reorder blocks when optimizing for size because extra jump insns may - be created; also barrier may create extra padding. - - More correctly we should have a block reordering mode that tried to - minimize the combined size of all the jumps. This would more or less - automatically remove extra jumps, but would also try to use more short - jumps instead of long jumps. */ - && optimize_function_for_speed_p (cfun)) - { - reorder_basic_blocks (); - cleanup_cfg (CLEANUP_EXPENSIVE); - } + reorder_basic_blocks (); + cleanup_cfg (CLEANUP_EXPENSIVE); FOR_EACH_BB (bb) if (bb->next_bb != EXIT_BLOCK_PTR) @@ -2231,6 +2363,10 @@ gate_handle_partition_blocks (void) user defined section attributes. Don't call it if either case arises. */ return (flag_reorder_blocks_and_partition + && optimize + /* See gate_handle_reorder_blocks. We should not partition if + we are going to omit the reordering. */ + && optimize_function_for_speed_p (cfun) && !DECL_ONE_ONLY (current_function_decl) && !user_defined_section_attribute); }