+/* Ratio of frequencies of edges so that one of more latch edges is
+ considered to belong to inner loop with same header. */
+#define HEAVY_EDGE_RATIO 8
+
+/* Minimum number of samples for that we apply
+ find_subloop_latch_edge_by_profile heuristics. */
+#define HEAVY_EDGE_MIN_SAMPLES 10
+
+/* If the profile info is available, finds an edge in LATCHES that much more
+ frequent than the remaining edges. Returns such an edge, or NULL if we do
+ not find one.
+
+ We do not use guessed profile here, only the measured one. The guessed
+ profile is usually too flat and unreliable for this (and it is mostly based
+ on the loop structure of the program, so it does not make much sense to
+ derive the loop structure from it). */
+
+static edge
+find_subloop_latch_edge_by_profile (VEC (edge, heap) *latches)
+{
+ unsigned i;
+ edge e, me = NULL;
+ gcov_type mcount = 0, tcount = 0;
+
+ for (i = 0; VEC_iterate (edge, latches, i, e); i++)
+ {
+ if (e->count > mcount)
+ {
+ me = e;
+ mcount = e->count;
+ }
+ tcount += e->count;
+ }
+
+ if (tcount < HEAVY_EDGE_MIN_SAMPLES
+ || (tcount - mcount) * HEAVY_EDGE_RATIO > tcount)
+ return NULL;
+
+ if (dump_file)
+ fprintf (dump_file,
+ "Found latch edge %d -> %d using profile information.\n",
+ me->src->index, me->dest->index);
+ return me;
+}
+
+/* Among LATCHES, guesses a latch edge of LOOP corresponding to subloop, based
+ on the structure of induction variables. Returns this edge, or NULL if we
+ do not find any.
+
+ We are quite conservative, and look just for an obvious simple innermost
+ loop (which is the case where we would lose the most performance by not
+ disambiguating the loop). More precisely, we look for the following
+ situation: The source of the chosen latch edge dominates sources of all
+ the other latch edges. Additionally, the header does not contain a phi node
+ such that the argument from the chosen edge is equal to the argument from
+ another edge. */
+
+static edge
+find_subloop_latch_edge_by_ivs (struct loop *loop ATTRIBUTE_UNUSED, VEC (edge, heap) *latches)
+{
+ edge e, latch = VEC_index (edge, latches, 0);
+ unsigned i;
+ gimple phi;
+ gimple_stmt_iterator psi;
+ tree lop;
+ basic_block bb;
+
+ /* Find the candidate for the latch edge. */
+ for (i = 1; VEC_iterate (edge, latches, i, e); i++)
+ if (dominated_by_p (CDI_DOMINATORS, latch->src, e->src))
+ latch = e;
+
+ /* Verify that it dominates all the latch edges. */
+ for (i = 0; VEC_iterate (edge, latches, i, e); i++)
+ if (!dominated_by_p (CDI_DOMINATORS, e->src, latch->src))
+ return NULL;
+
+ /* Check for a phi node that would deny that this is a latch edge of
+ a subloop. */
+ for (psi = gsi_start_phis (loop->header); !gsi_end_p (psi); gsi_next (&psi))
+ {
+ phi = gsi_stmt (psi);
+ lop = PHI_ARG_DEF_FROM_EDGE (phi, latch);
+
+ /* Ignore the values that are not changed inside the subloop. */
+ if (TREE_CODE (lop) != SSA_NAME
+ || SSA_NAME_DEF_STMT (lop) == phi)
+ continue;
+ bb = gimple_bb (SSA_NAME_DEF_STMT (lop));
+ if (!bb || !flow_bb_inside_loop_p (loop, bb))
+ continue;
+
+ for (i = 0; VEC_iterate (edge, latches, i, e); i++)
+ if (e != latch
+ && PHI_ARG_DEF_FROM_EDGE (phi, e) == lop)
+ return NULL;
+ }
+
+ if (dump_file)
+ fprintf (dump_file,
+ "Found latch edge %d -> %d using iv structure.\n",
+ latch->src->index, latch->dest->index);
+ return latch;
+}
+
+/* If we can determine that one of the several latch edges of LOOP behaves
+ as a latch edge of a separate subloop, returns this edge. Otherwise
+ returns NULL. */
+
+static edge
+find_subloop_latch_edge (struct loop *loop)
+{
+ VEC (edge, heap) *latches = get_loop_latch_edges (loop);
+ edge latch = NULL;
+
+ if (VEC_length (edge, latches) > 1)
+ {
+ latch = find_subloop_latch_edge_by_profile (latches);
+
+ if (!latch
+ /* We consider ivs to guess the latch edge only in SSA. Perhaps we
+ should use cfghook for this, but it is hard to imagine it would
+ be useful elsewhere. */
+ && current_ir_type () == IR_GIMPLE)
+ latch = find_subloop_latch_edge_by_ivs (loop, latches);
+ }
+
+ VEC_free (edge, heap, latches);
+ return latch;
+}
+
+/* Callback for make_forwarder_block. Returns true if the edge E is marked
+ in the set MFB_REIS_SET. */
+
+static struct pointer_set_t *mfb_reis_set;
+static bool
+mfb_redirect_edges_in_set (edge e)
+{
+ return pointer_set_contains (mfb_reis_set, e);
+}
+
+/* Creates a subloop of LOOP with latch edge LATCH. */