commit_edge_insertions contains this kludge:
/* 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);
At least on x86/x86-64, there is apparently only one case where control flow
insns are inserted on edges: when the prologue is inserted on the entry edge.
Once this is accounted for, the above kludge can be removed, provided that the
force_nonfallthru RTL routine is enhanced to preserve the loop nest structure.
The result is the attached patch, bootstrapped/regtested on x86 and x86-64.
I'll be testing it on IA-64 and SPARC over the next few days if there is an
agreement that this is a progress.
* basic-block.h (force_nonfallthru): Move to...
* cfghooks.h (struct cfg_hooks): Add force_nonfallthru hook.
(force_nonfallthru): ...here.
* cfghooks.c (force_nonfallthru): New function.
* cfgrtl.c (force_nonfallthru): Rename into...
(rtl_force_nonfallthru): ...this.
(commit_one_edge_insertion): Do not set AUX field.
(commit_edge_insertions): Do not discover new basic blocks.
(rtl_cfg_hooks): Add rtl_force_nonfallthru.
(cfg_layout_rtl_cfg_hooks): Likewise.
* function.c (thread_prologue_and_epilogue_insns): Remove bogus
ATTRIBUTE_UNUSED. Discover new basic blocks in the prologue insns.
* tree-cfg.c (gimple_cfg_hooks): Add NULL for force_nonfallthru.
--
Eric Botcazou
Index: cfghooks.c
===================================================================
--- cfghooks.c (revision 171942)
+++ cfghooks.c (working copy)
@@ -398,8 +398,7 @@ redirect_edge_and_branch_force (edge e,
rescan_loop_exit (e, false, true);
ret = cfg_hooks->redirect_edge_and_branch_force (e, dest);
- if (ret != NULL
- && dom_info_available_p (CDI_DOMINATORS))
+ if (ret != NULL && dom_info_available_p (CDI_DOMINATORS))
set_immediate_dominator (CDI_DOMINATORS, ret, src);
if (current_loops != NULL)
@@ -820,6 +819,8 @@ make_forwarder_block (basic_block bb, bo
return fallthru;
}
+/* Try to make the edge fallthru. */
+
void
tidy_fallthru_edge (edge e)
{
@@ -874,6 +875,42 @@ tidy_fallthru_edges (void)
}
}
+/* Edge E is assumed to be fallthru edge. Emit needed jump instruction
+ (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)
+{
+ basic_block ret, src = e->src, dest = e->dest;
+ struct loop *loop;
+
+ if (!cfg_hooks->force_nonfallthru)
+ internal_error ("%s does not support force_nonfallthru",
+ cfg_hooks->name);
+
+ if (current_loops != NULL)
+ rescan_loop_exit (e, false, true);
+
+ ret = cfg_hooks->force_nonfallthru (e);
+ if (ret != NULL && dom_info_available_p (CDI_DOMINATORS))
+ set_immediate_dominator (CDI_DOMINATORS, ret, src);
+
+ if (current_loops != NULL)
+ {
+ if (ret != NULL)
+ {
+ loop = find_common_loop (single_pred (ret)->loop_father,
+ single_succ (ret)->loop_father);
+ add_bb_to_loop (ret, loop);
+ }
+ else if (find_edge (src, dest) == e)
+ rescan_loop_exit (e, true, false);
+ }
+
+ return ret;
+}
+
/* Returns true if we can duplicate basic block BB. */
bool
Index: cfghooks.h
===================================================================
--- cfghooks.h (revision 171942)
+++ cfghooks.h (working copy)
@@ -85,9 +85,12 @@ struct cfg_hooks
basic_block (*split_edge) (edge);
void (*make_forwarder_block) (edge);
- /* Tries to make the edge fallthru. */
+ /* Try to make the edge fallthru. */
void (*tidy_fallthru_edge) (edge);
+ /* Make the edge non-fallthru. */
+ basic_block (*force_nonfallthru) (edge);
+
/* Say whether a block ends with a call, possibly followed by some
other code that must stay with the call. */
bool (*block_ends_with_call_p) (basic_block);
@@ -156,6 +159,7 @@ extern bool can_merge_blocks_p (basic_bl
extern void merge_blocks (basic_block, basic_block);
extern edge make_forwarder_block (basic_block, bool (*)(edge),
void (*) (basic_block));
+extern basic_block force_nonfallthru (edge);
extern void tidy_fallthru_edge (edge);
extern void tidy_fallthru_edges (void);
extern void predict_edge (edge e, enum br_predictor predictor, int probability);
Index: function.c
===================================================================
--- function.c (revision 171942)
+++ function.c (working copy)
@@ -5282,8 +5282,7 @@ thread_prologue_and_epilogue_insns (void
{
bool inserted;
rtx seq ATTRIBUTE_UNUSED, epilogue_end ATTRIBUTE_UNUSED;
- edge entry_edge ATTRIBUTE_UNUSED;
- edge e;
+ edge entry_edge, e;
edge_iterator ei;
rtl_profile_for_bb (ENTRY_BLOCK_PTR);
@@ -5315,10 +5314,6 @@ thread_prologue_and_epilogue_insns (void
record_insns (seq, NULL, &prologue_insn_hash);
set_insn_locators (seq, prologue_locator);
- /* This relies on the fact that committing the edge insertion
- will look for basic blocks within the inserted instructions,
- which in turn relies on the fact that we are not in CFG
- layout mode here. */
insert_insn_on_edge (seq, entry_edge);
inserted = true;
#endif
@@ -5541,13 +5536,23 @@ thread_prologue_and_epilogue_insns (void
cur_bb->aux = cur_bb->next_bb;
cfg_layout_finalize ();
}
+
epilogue_done:
default_rtl_profile ();
if (inserted)
{
+ sbitmap blocks;
+
commit_edge_insertions ();
+ /* Look for basic blocks within the prologue insns. */
+ blocks = sbitmap_alloc (last_basic_block);
+ sbitmap_zero (blocks);
+ SET_BIT (blocks, entry_edge->dest->index);
+ find_many_sub_basic_blocks (blocks);
+ sbitmap_free (blocks);
+
/* The epilogue insns we inserted may cause the exit edge to no longer
be fallthru. */
FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
Index: basic-block.h
===================================================================
--- basic-block.h (revision 171942)
+++ basic-block.h (working copy)
@@ -794,7 +794,6 @@ extern void flow_nodes_print (const char
extern void flow_edge_list_print (const char *, const edge *, int, FILE *);
/* In cfgrtl.c */
-extern basic_block force_nonfallthru (edge);
extern rtx block_label (basic_block);
extern bool purge_all_dead_edges (void);
extern bool purge_dead_edges (basic_block);
Index: tree-cfg.c
===================================================================
--- tree-cfg.c (revision 171942)
+++ tree-cfg.c (working copy)
@@ -7135,6 +7135,7 @@ struct cfg_hooks gimple_cfg_hooks = {
gimple_split_edge, /* split_edge */
gimple_make_forwarder_block, /* make_forward_block */
NULL, /* tidy_fallthru_edge */
+ NULL, /* force_nonfallthru */
gimple_block_ends_with_call_p,/* block_ends_with_call_p */
gimple_block_ends_with_condjump_p, /* block_ends_with_condjump_p */
gimple_flow_call_edges_add, /* flow_call_edges_add */
Index: cfgrtl.c
===================================================================
--- cfgrtl.c (revision 171942)
+++ cfgrtl.c (working copy)
@@ -1279,8 +1279,8 @@ force_nonfallthru_and_redirect (edge e,
(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);
}
@@ -1566,10 +1566,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. */
@@ -1578,8 +1574,6 @@ void
commit_edge_insertions (void)
{
basic_block bb;
- sbitmap blocks;
- bool changed = false;
#ifdef ENABLE_CHECKING
verify_flow_info ();
@@ -1592,35 +1586,8 @@ 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);
}
@@ -3233,6 +3200,7 @@ struct cfg_hooks rtl_cfg_hooks = {
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,
@@ -3276,7 +3244,8 @@ struct cfg_hooks cfg_layout_rtl_cfg_hook
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,