summaryrefslogtreecommitdiff
path: root/gcc/cfgloopmanip.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cfgloopmanip.c')
-rw-r--r--gcc/cfgloopmanip.c47
1 files changed, 41 insertions, 6 deletions
diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c
index d5bd216e08c..025b5be1052 100644
--- a/gcc/cfgloopmanip.c
+++ b/gcc/cfgloopmanip.c
@@ -1102,9 +1102,26 @@ mfb_keep_just (edge e)
return e != mfb_kj_edge;
}
+/* True when a candidate preheader BLOCK has predecessors from LOOP. */
+
+static bool
+has_preds_from_loop (basic_block block, struct loop *loop)
+{
+ edge e;
+ edge_iterator ei;
+
+ FOR_EACH_EDGE (e, ei, block->preds)
+ if (e->src->loop_father == loop)
+ return true;
+ return false;
+}
+
/* Creates a pre-header for a LOOP. Returns newly created block. Unless
CP_SIMPLE_PREHEADERS is set in FLAGS, we only force LOOP to have single
entry; otherwise we also force preheader block to have only one successor.
+ When CP_FALLTHRU_PREHEADERS is set in FLAGS, we force the preheader block
+ to be a fallthru predecessor to the loop header and to have only
+ predecessors from outside of the loop.
The function also updates dominators. */
basic_block
@@ -1131,13 +1148,27 @@ create_preheader (struct loop *loop, int flags)
gcc_assert (nentry);
if (nentry == 1)
{
- if (/* We do not allow entry block to be the loop preheader, since we
+ bool need_forwarder_block = false;
+
+ /* We do not allow entry block to be the loop preheader, since we
cannot emit code there. */
- single_entry->src != ENTRY_BLOCK_PTR
- /* If we want simple preheaders, also force the preheader to have
- just a single successor. */
- && !((flags & CP_SIMPLE_PREHEADERS)
- && !single_succ_p (single_entry->src)))
+ if (single_entry->src == ENTRY_BLOCK_PTR)
+ need_forwarder_block = true;
+ else
+ {
+ /* If we want simple preheaders, also force the preheader to have
+ just a single successor. */
+ if ((flags & CP_SIMPLE_PREHEADERS)
+ && !single_succ_p (single_entry->src))
+ need_forwarder_block = true;
+ /* If we want fallthru preheaders, also create forwarder block when
+ preheader ends with a jump or has predecessors from loop. */
+ else if ((flags & CP_FALLTHRU_PREHEADERS)
+ && (JUMP_P (BB_END (single_entry->src))
+ || has_preds_from_loop (single_entry->src, loop)))
+ need_forwarder_block = true;
+ }
+ if (! need_forwarder_block)
return NULL;
}
@@ -1174,6 +1205,10 @@ create_preheader (struct loop *loop, int flags)
if (dump_file)
fprintf (dump_file, "Created preheader block for loop %i\n",
loop->num);
+
+ if (flags & CP_FALLTHRU_PREHEADERS)
+ gcc_assert ((single_succ_edge (dummy)->flags & EDGE_FALLTHRU)
+ && !JUMP_P (BB_END (dummy)));
return dummy;
}