aboutsummaryrefslogtreecommitdiff
path: root/gcc/cfgrtl.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cfgrtl.c')
-rw-r--r--gcc/cfgrtl.c212
1 files changed, 168 insertions, 44 deletions
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index 0ea297e..36438b8 100644
--- a/gcc/cfgrtl.c
+++ b/gcc/cfgrtl.c
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree.h"
#include "hard-reg-set.h"
#include "basic-block.h"
+#include "bb-reorder.h"
#include "regs.h"
#include "flags.h"
#include "function.h"
@@ -451,6 +452,9 @@ rest_of_pass_free_cfg (void)
}
#endif
+ if (crtl->has_bb_partition)
+ insert_section_boundary_note ();
+
free_bb_for_insn ();
return 0;
}
@@ -981,8 +985,7 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
partition boundaries). See the comments at the top of
bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */
- if (find_reg_note (insn, REG_CROSSING_JUMP, NULL_RTX)
- || BB_PARTITION (src) != BB_PARTITION (target))
+ if (BB_PARTITION (src) != BB_PARTITION (target))
return NULL;
/* We can replace or remove a complex jump only when we have exactly
@@ -1291,6 +1294,53 @@ redirect_branch_edge (edge e, basic_block target)
return e;
}
+/* Called when edge E has been redirected to a new destination,
+ in order to update the region crossing flag on the edge and
+ jump. */
+
+static void
+fixup_partition_crossing (edge e)
+{
+ rtx note;
+
+ if (e->src == ENTRY_BLOCK_PTR || e->dest == EXIT_BLOCK_PTR)
+ return;
+ /* If we redirected an existing edge, it may already be marked
+ crossing, even though the new src is missing a reg crossing note.
+ But make sure reg crossing note doesn't already exist before
+ inserting. */
+ if (BB_PARTITION (e->src) != BB_PARTITION (e->dest))
+ {
+ e->flags |= EDGE_CROSSING;
+ note = find_reg_note (BB_END (e->src), REG_CROSSING_JUMP, NULL_RTX);
+ if (JUMP_P (BB_END (e->src))
+ && !note)
+ add_reg_note (BB_END (e->src), REG_CROSSING_JUMP, NULL_RTX);
+ }
+ else if (BB_PARTITION (e->src) == BB_PARTITION (e->dest))
+ {
+ e->flags &= ~EDGE_CROSSING;
+ /* Remove the section crossing note from jump at end of
+ src if it exists, and if no other successors are
+ still crossing. */
+ note = find_reg_note (BB_END (e->src), REG_CROSSING_JUMP, NULL_RTX);
+ if (note)
+ {
+ bool has_crossing_succ = false;
+ edge e2;
+ edge_iterator ei;
+ FOR_EACH_EDGE (e2, ei, e->src->succs)
+ {
+ has_crossing_succ |= (e2->flags & EDGE_CROSSING);
+ if (has_crossing_succ)
+ break;
+ }
+ if (!has_crossing_succ)
+ remove_note (BB_END (e->src), note);
+ }
+ }
+}
+
/* Attempt to change code to redirect edge E to TARGET. Don't do that on
expense of adding new instructions or reordering basic blocks.
@@ -1307,16 +1357,18 @@ rtl_redirect_edge_and_branch (edge e, basic_block target)
{
edge ret;
basic_block src = e->src;
+ basic_block dest = e->dest;
if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))
return NULL;
- if (e->dest == target)
+ if (dest == target)
return e;
if ((ret = try_redirect_by_replacing_jump (e, target, false)) != NULL)
{
df_set_bb_dirty (src);
+ fixup_partition_crossing (ret);
return ret;
}
@@ -1325,9 +1377,22 @@ rtl_redirect_edge_and_branch (edge e, basic_block target)
return NULL;
df_set_bb_dirty (src);
+ fixup_partition_crossing (ret);
return ret;
}
+/* Emit a barrier after BB, into the footer if we are in CFGLAYOUT mode. */
+
+void
+emit_barrier_after_bb (basic_block bb)
+{
+ rtx barrier = emit_barrier_after (BB_END (bb));
+ gcc_assert (current_ir_type() == IR_RTL_CFGRTL
+ || current_ir_type () == IR_RTL_CFGLAYOUT);
+ if (current_ir_type () == IR_RTL_CFGLAYOUT)
+ BB_FOOTER (bb) = unlink_insn_chain (barrier, barrier);
+}
+
/* Like force_nonfallthru below, but additionally performs redirection
Used by redirect_edge_and_branch_force. JUMP_LABEL is used only
when redirecting to the EXIT_BLOCK, it is either ret_rtx or
@@ -1492,12 +1557,6 @@ force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label)
/* 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_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))
- 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);
@@ -1508,6 +1567,10 @@ force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label)
redirect_edge_pred (e, jump_block);
e->probability = REG_BR_PROB_BASE;
+ /* If e->src was previously region crossing, it no longer is
+ and the reg crossing note should be removed. */
+ fixup_partition_crossing (new_edge);
+
/* If asm goto has any label refs to target's label,
add also edge from asm goto bb to target. */
if (asm_goto_edge)
@@ -1559,13 +1622,16 @@ force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label)
LABEL_NUSES (label)++;
}
- emit_barrier_after (BB_END (jump_block));
+ /* We might be in cfg layout mode, and if so, the following routine will
+ insert the barrier correctly. */
+ emit_barrier_after_bb (jump_block);
redirect_edge_succ_nodup (e, target);
if (abnormal_edge_flags)
make_edge (src, target, abnormal_edge_flags);
df_mark_solutions_dirty ();
+ fixup_partition_crossing (e);
return new_bb;
}
@@ -1654,6 +1720,21 @@ rtl_move_block_after (basic_block bb ATTRIBUTE_UNUSED,
return false;
}
+/* Locate the last bb in the same partition as START_BB. */
+
+static basic_block
+last_bb_in_partition (basic_block start_bb)
+{
+ basic_block bb;
+ FOR_BB_BETWEEN (bb, start_bb, EXIT_BLOCK_PTR, next_bb)
+ {
+ if (BB_PARTITION (start_bb) != BB_PARTITION (bb->next_bb))
+ return bb;
+ }
+ /* Return bb before EXIT_BLOCK_PTR. */
+ return bb->prev_bb;
+}
+
/* Split a (typically critical) edge. Return the new block.
The edge must not be abnormal.
@@ -1664,7 +1745,7 @@ rtl_move_block_after (basic_block bb ATTRIBUTE_UNUSED,
static basic_block
rtl_split_edge (edge edge_in)
{
- basic_block bb;
+ basic_block bb, new_bb;
rtx before;
/* Abnormal edges cannot be split. */
@@ -1696,13 +1777,50 @@ rtl_split_edge (edge edge_in)
}
else
{
- bb = create_basic_block (before, NULL, edge_in->dest->prev_bb);
- /* ??? Why not edge_in->dest->prev_bb here? */
- BB_COPY_PARTITION (bb, edge_in->dest);
+ if (edge_in->src == ENTRY_BLOCK_PTR)
+ {
+ bb = create_basic_block (before, NULL, edge_in->dest->prev_bb);
+ BB_COPY_PARTITION (bb, edge_in->dest);
+ }
+ else
+ {
+ basic_block after = edge_in->dest->prev_bb;
+ /* If this is post-bb reordering, and the edge crosses a partition
+ boundary, the new block needs to be inserted in the bb chain
+ at the end of the src partition (since we put the new bb into
+ that partition, see below). Otherwise we may end up creating
+ an extra partition crossing in the chain, which is illegal.
+ It can't go after the src, because src may have a fall-through
+ to a different block. */
+ if (crtl->bb_reorder_complete
+ && (edge_in->flags & EDGE_CROSSING))
+ {
+ after = last_bb_in_partition (edge_in->src);
+ before = NEXT_INSN (BB_END (after));
+ /* The instruction following the last bb in partition should
+ be a barrier, since it cannot end in a fall-through. */
+ gcc_checking_assert (BARRIER_P (before));
+ before = NEXT_INSN (before);
+ }
+ bb = create_basic_block (before, NULL, after);
+ /* Put the split bb into the src partition, to avoid creating
+ a situation where a cold bb dominates a hot bb, in the case
+ where src is cold and dest is hot. The src will dominate
+ the new bb (whereas it might not have dominated dest). */
+ BB_COPY_PARTITION (bb, edge_in->src);
+ }
}
make_single_succ_edge (bb, edge_in->dest, EDGE_FALLTHRU);
+ /* Can't allow a region crossing edge to be fallthrough. */
+ if (BB_PARTITION (bb) != BB_PARTITION (edge_in->dest)
+ && edge_in->dest != EXIT_BLOCK_PTR)
+ {
+ new_bb = force_nonfallthru (single_succ_edge (bb));
+ gcc_assert (!new_bb);
+ }
+
/* For non-fallthru edges, we must adjust the predecessor's
jump instruction to target our new block. */
if ((edge_in->flags & EDGE_FALLTHRU) == 0)
@@ -1815,17 +1933,13 @@ commit_one_edge_insertion (edge e)
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);
+
+ /* If E crossed a partition boundary, we needed to make bb end in
+ a region-crossing jump, even though it was originally fallthru. */
+ if (JUMP_P (BB_END (bb)))
+ before = BB_END (bb);
+ else
+ after = BB_END (bb);
}
/* Now that we've found the spot, do the insertion. */
@@ -2071,7 +2185,11 @@ verify_hot_cold_block_grouping (void)
bool switched_sections = false;
int current_partition = BB_UNPARTITIONED;
- if (!crtl->bb_reorder_complete)
+ /* Even after bb reordering is complete, we go into cfglayout mode
+ again (in compgoto). Ensure we don't call this before going back
+ into linearized RTL when any layout fixes would have been committed. */
+ if (!crtl->bb_reorder_complete
+ || current_ir_type() != IR_RTL_CFGRTL)
return err;
FOR_EACH_BB (bb)
@@ -2116,6 +2234,7 @@ rtl_verify_edges (void)
edge e, fallthru = NULL;
edge_iterator ei;
rtx note;
+ bool has_crossing_edge = false;
if (JUMP_P (BB_END (bb))
&& (note = find_reg_note (BB_END (bb), REG_BR_PROB, NULL_RTX))
@@ -2141,6 +2260,7 @@ rtl_verify_edges (void)
is_crossing = (BB_PARTITION (e->src) != BB_PARTITION (e->dest)
&& e->src != ENTRY_BLOCK_PTR
&& e->dest != EXIT_BLOCK_PTR);
+ has_crossing_edge |= is_crossing;
if (e->flags & EDGE_CROSSING)
{
if (!is_crossing)
@@ -2160,6 +2280,13 @@ rtl_verify_edges (void)
e->src->index);
err = 1;
}
+ if (JUMP_P (BB_END (bb))
+ && !find_reg_note (BB_END (bb), REG_CROSSING_JUMP, NULL_RTX))
+ {
+ error ("No region crossing jump at section boundary in bb %i",
+ bb->index);
+ err = 1;
+ }
}
else if (is_crossing)
{
@@ -2188,6 +2315,15 @@ rtl_verify_edges (void)
n_abnormal++;
}
+ if (!has_crossing_edge
+ && find_reg_note (BB_END (bb), REG_CROSSING_JUMP, NULL_RTX))
+ {
+ print_rtl_with_bb (stderr, get_insns (), TDF_RTL | TDF_BLOCKS | TDF_DETAILS);
+ error ("Region crossing jump across same section in bb %i",
+ bb->index);
+ err = 1;
+ }
+
if (n_eh && !find_reg_note (BB_END (bb), REG_EH_REGION, NULL_RTX))
{
error ("missing REG_EH_REGION note at the end of bb %i", bb->index);
@@ -2395,8 +2531,6 @@ rtl_verify_flow_info_1 (void)
err |= rtl_verify_edges ();
- err |= verify_hot_cold_block_grouping();
-
return err;
}
@@ -2642,6 +2776,8 @@ rtl_verify_flow_info (void)
err |= rtl_verify_bb_layout ();
+ err |= verify_hot_cold_block_grouping ();
+
return err;
}
@@ -3343,7 +3479,7 @@ fixup_reorder_chain (void)
edge e_fall, e_taken, e;
rtx bb_end_insn;
rtx ret_label = NULL_RTX;
- basic_block nb, src_bb;
+ basic_block nb;
edge_iterator ei;
if (EDGE_COUNT (bb->succs) == 0)
@@ -3478,7 +3614,6 @@ fixup_reorder_chain (void)
/* We got here if we need to add a new jump insn.
Note force_nonfallthru can delete E_FALL and thus we have to
save E_FALL->src prior to the call to force_nonfallthru. */
- src_bb = e_fall->src;
nb = force_nonfallthru_and_redirect (e_fall, e_fall->dest, ret_label);
if (nb)
{
@@ -3486,17 +3621,6 @@ fixup_reorder_chain (void)
bb->aux = nb;
/* Don't process this new block. */
bb = nb;
-
- /* Make sure new bb is tagged for correct section (same as
- fall-thru source, since you cannot fall-thru across
- section boundaries). */
- BB_COPY_PARTITION (src_bb, single_pred (bb));
- if (flag_reorder_blocks_and_partition
- && targetm_common.have_named_sections
- && JUMP_P (BB_END (bb))
- && !any_condjump_p (BB_END (bb))
- && (EDGE_SUCC (bb, 0)->flags & EDGE_CROSSING))
- add_reg_note (BB_END (bb), REG_CROSSING_JUMP, NULL_RTX);
}
}
@@ -3796,10 +3920,11 @@ duplicate_insn_chain (rtx from, rtx to)
case NOTE_INSN_FUNCTION_BEG:
/* There is always just single entry to function. */
case NOTE_INSN_BASIC_BLOCK:
+ /* We should only switch text sections once. */
+ case NOTE_INSN_SWITCH_TEXT_SECTIONS:
break;
case NOTE_INSN_EPILOGUE_BEG:
- case NOTE_INSN_SWITCH_TEXT_SECTIONS:
emit_note_copy (insn);
break;
@@ -4611,8 +4736,7 @@ rtl_can_remove_branch_p (const_edge e)
if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))
return false;
- if (find_reg_note (insn, REG_CROSSING_JUMP, NULL_RTX)
- || BB_PARTITION (src) != BB_PARTITION (target))
+ if (BB_PARTITION (src) != BB_PARTITION (target))
return false;
if (!onlyjump_p (insn)