--- gcc/bb-reorder.c (revision 259642) +++ gcc/bb-reorder.c (working copy) @@ -117,6 +117,7 @@ #include "fibonacci_heap.h" #include "stringpool.h" #include "attribs.h" +#include "common/common-target.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 @@ -1408,17 +1409,95 @@ get_uncond_jump_length (void) return length; } +/* Create a forwarder block to OLD_BB starting with NEW_LABEL and in the + other partition wrt OLD_BB. */ + +static basic_block +create_forwarder_block (rtx_code_label *new_label, basic_block old_bb) +{ + /* Put the new label and a jump in the new basic block. */ + rtx_insn *label = emit_label (new_label); + rtx_code_label *old_label = block_label (old_bb); + rtx_insn *jump = emit_jump_insn (targetm.gen_jump (old_label)); + JUMP_LABEL (jump) = old_label; + + /* Create the new basic block and put it in last position. */ + basic_block last_bb = EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb; + basic_block new_bb = create_basic_block (label, jump, last_bb); + new_bb->aux = last_bb->aux; + new_bb->count = old_bb->count; + last_bb->aux = new_bb; + + emit_barrier_after_bb (new_bb); + + make_single_succ_edge (new_bb, old_bb, 0); + + /* Make sure the new basic block is in the other partition. */ + unsigned new_partition = BB_PARTITION (old_bb); + new_partition ^= BB_HOT_PARTITION | BB_COLD_PARTITION; + BB_SET_PARTITION (new_bb, new_partition); + + return new_bb; +} + +/* The common landing pad in block OLD_BB has edges from both partitions. + Add a new landing pad that will just jump to the old one and split the + edges so that no EH edge crosses partitions. */ + +static void +sjlj_fix_up_crossing_landing_pad (basic_block old_bb) +{ + const unsigned lp_len = cfun->eh->lp_array->length (); + edge_iterator ei; + edge e; + + /* Generate the new common landing-pad label. */ + rtx_code_label *new_label = gen_label_rtx (); + LABEL_PRESERVE_P (new_label) = 1; + + /* Create the forwarder block. */ + basic_block new_bb = create_forwarder_block (new_label, old_bb); + + /* Create the map from old to new lp index and initialize it. */ + unsigned *index_map = (unsigned *) alloca (lp_len * sizeof (unsigned)); + memset (index_map, 0, lp_len * sizeof (unsigned)); + + /* Fix up the edges. */ + for (ei = ei_start (old_bb->preds); (e = ei_safe_edge (ei)) != NULL; ) + if (e->src != new_bb && BB_PARTITION (e->src) == BB_PARTITION (new_bb)) + { + rtx_insn *insn = BB_END (e->src); + rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); + + gcc_assert (note != NULL); + const unsigned old_index = INTVAL (XEXP (note, 0)); + + /* Generate the new landing-pad structure. */ + if (index_map[old_index] == 0) + { + eh_landing_pad old_lp = (*cfun->eh->lp_array)[old_index]; + eh_landing_pad new_lp = gen_eh_landing_pad (old_lp->region); + new_lp->post_landing_pad = old_lp->post_landing_pad; + new_lp->landing_pad = new_label; + index_map[old_index] = new_lp->index; + } + XEXP (note, 0) = GEN_INT (index_map[old_index]); + + /* Adjust the edge to the new destination. */ + redirect_edge_succ (e, new_bb); + } + else + ei_next (&ei); +} + /* The landing pad OLD_LP, in block OLD_BB, has edges from both partitions. Add a new landing pad that will just jump to the old one 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) +dw2_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; - rtx_insn *jump; - unsigned new_partition; edge_iterator ei; edge e; @@ -1428,32 +1507,12 @@ fix_up_crossing_landing_pad (eh_landing_ new_lp->landing_pad = gen_label_rtx (); LABEL_PRESERVE_P (new_lp->landing_pad) = 1; - /* Put appropriate instructions in new bb. */ - rtx_code_label *new_label = emit_label (new_lp->landing_pad); - - rtx_code_label *old_label = block_label (old_bb); - jump = emit_jump_insn (targetm.gen_jump (old_label)); - JUMP_LABEL (jump) = old_label; - - /* Create new basic block to be dest for lp. */ - last_bb = EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb; - new_bb = create_basic_block (new_label, jump, last_bb); - new_bb->aux = last_bb->aux; - new_bb->count = old_bb->count; - last_bb->aux = new_bb; - - emit_barrier_after_bb (new_bb); - - make_single_succ_edge (new_bb, old_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); + /* Create the forwarder block. */ + basic_block new_bb = create_forwarder_block (new_lp->landing_pad, old_bb); /* Fix up the edges. */ for (ei = ei_start (old_bb->preds); (e = ei_safe_edge (ei)) != NULL; ) - if (e->src != new_bb && BB_PARTITION (e->src) == new_partition) + if (e->src != new_bb && BB_PARTITION (e->src) == BB_PARTITION (new_bb)) { rtx_insn *insn = BB_END (e->src); rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); @@ -1651,9 +1710,11 @@ find_rarely_executed_basic_blocks_and_cr /* 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. */ + moving the landing pads or inserting forwarder landing pads. */ if (cfun->eh->lp_array) { + const bool sjlj + = (targetm_common.except_unwind_info (&global_options) == UI_SJLJ); unsigned i; eh_landing_pad lp; @@ -1685,13 +1746,18 @@ find_rarely_executed_basic_blocks_and_cr which ^= BB_HOT_PARTITION | BB_COLD_PARTITION; BB_SET_PARTITION (bb, which); } + else if (sjlj) + sjlj_fix_up_crossing_landing_pad (bb); else - fix_up_crossing_landing_pad (lp, bb); + dw2_fix_up_crossing_landing_pad (lp, bb); + + /* There is a single, common landing pad in SJLJ mode. */ + if (sjlj) + break; } } /* Mark every edge that crosses between sections. */ - FOR_EACH_BB_FN (bb, cfun) FOR_EACH_EDGE (e, ei, bb->succs) {