ch_base::copy_headers (function *fun)
{
basic_block header;
- edge exit, entry;
+ edge exit, nonexit, entry;
basic_block *bbs, *copied_bbs;
unsigned n_bbs;
unsigned bbs_size;
the header to have just a single successor and copying up to
postdominator. */
- exit = NULL;
+ nonexit = NULL;
n_bbs = 0;
+ int nexits = 0;
+ profile_count exit_count = profile_count::zero ();
+ profile_count entry_count = profile_count::zero ();
+ edge e;
+ edge_iterator ei;
+ FOR_EACH_EDGE (e, ei, loop->header->preds)
+ if (e->src != loop->latch)
+ entry_count += e->count ();
while (should_duplicate_loop_header_p (header, loop, &remaining_limit))
{
if (dump_file && (dump_flags & TDF_DETAILS))
/* Find a successor of header that is inside a loop; i.e. the new
header after the condition is copied. */
if (flow_bb_inside_loop_p (loop, EDGE_SUCC (header, 0)->dest))
- exit = EDGE_SUCC (header, 0);
+ {
+ nonexit = EDGE_SUCC (header, 0);
+ exit = EDGE_SUCC (header, 1);
+ }
else
- exit = EDGE_SUCC (header, 1);
+ {
+ nonexit = EDGE_SUCC (header, 1);
+ exit = EDGE_SUCC (header, 0);
+ }
+ exit_count += exit->count ();
+ nexits++;
bbs[n_bbs++] = header;
gcc_assert (bbs_size > n_bbs);
- header = exit->dest;
+ header = nonexit->dest;
}
- if (!exit)
+ if (!nonexit)
continue;
if (dump_file && (dump_flags & TDF_DETAILS))
/* Ensure that the header will have just the latch as a predecessor
inside the loop. */
- if (!single_pred_p (exit->dest))
+ if (!single_pred_p (nonexit->dest))
{
- header = split_edge (exit);
+ header = split_edge (nonexit);
exit = single_pred_edge (header);
}
/* Find correct latch. We only duplicate chain of conditionals so
there should be precisely two edges to the new header. One entry
edge and one to latch. */
- edge_iterator ei;
- edge e;
FOR_EACH_EDGE (e, ei, loop->header->preds)
if (header != e->src)
{
else
fprintf (dump_file, "Loop %d is still not do-while loop.\n",
loop->num);
+ fprintf (dump_file, "Exit count: ");
+ exit_count.dump (dump_file);
+ fprintf (dump_file, "\nEntry count: ");
+ entry_count.dump (dump_file);
+ fprintf (dump_file, "\n");
+ }
+
+ /* We possibly decreased number of itrations by 1. */
+ auto_vec<edge> exits = get_loop_exit_edges (loop);
+ bool precise = (nexits == (int) exits.length ());
+ if (!get_max_loop_iterations_int (loop))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Loop %d no longer loops.\n", loop->num);
+ /* TODO: We can unloop like in tree-ssa-loop-ivcanon. */
+ precise = false;
+ }
+ /* Check that loop may not terminate in other way than via
+ basic blocks we duplicated. */
+ if (precise)
+ {
+ basic_block *bbs = get_loop_body (loop);
+ for (unsigned i = 0; i < loop->num_nodes && precise; ++i)
+ {
+ basic_block bb = bbs[i];
+ bool found_exit = false;
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if (!flow_bb_inside_loop_p (loop, e->dest))
+ {
+ found_exit = true;
+ break;
+ }
+ /* If BB has exit, it was duplicated. */
+ if (found_exit)
+ continue;
+ /* Give up on irreducible loops. */
+ if (bb->flags & BB_IRREDUCIBLE_LOOP)
+ {
+ precise = false;
+ break;
+ }
+ /* Check that inner loops are finite. */
+ for (class loop *l = bb->loop_father; l != loop && precise;
+ l = loop_outer (l))
+ if (!l->finite_p)
+ {
+ precise = false;
+ break;
+ }
+ /* Verify that there is no statement that may be terminate
+ execution in a way not visible to CFG. */
+ for (gimple_stmt_iterator bsi = gsi_start_bb (bb);
+ !gsi_end_p (bsi); gsi_next (&bsi))
+ if (stmt_can_terminate_bb_p (gsi_stmt (bsi)))
+ precise = false;
+ }
+ }
+ if (precise)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file,
+ "Peeled all exits:"
+ " decreased number of iterations of loop %d by 1.\n",
+ loop->num);
+ adjust_loop_info_after_peeling (loop, 1, true);
}
+ else if (exit_count >= entry_count.apply_scale (9, 10))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file,
+ "Peeled likely exits: likely decreased number "
+ "of iterations of loop %d by 1.\n", loop->num);
+ adjust_loop_info_after_peeling (loop, 1, false);
+ }
+ else if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file,
+ "Not decreased number"
+ " of iterations of loop %d; likely exits remains.\n",
+ loop->num);
changed = true;
}
- size->eliminated_by_peeling), 1);
}
+/* Update loop estimates after peeling LOOP by NPEEL.
+ If PRECISE is false only likely exists were duplicated and thus
+ do not update any estimates that are supposed to be always reliable. */
+void
+adjust_loop_info_after_peeling (class loop *loop, int npeel, bool precise)
+{
+ if (loop->any_estimate)
+ {
+ /* Since peeling is mostly about loops where first few
+ iterations are special, it is not quite correct to
+ assume that the remaining iterations will behave
+ the same way. However we do not have better info
+ so update the esitmate, since it is likely better
+ than keeping it as it is.
+
+ Remove it if it looks wrong.
+
+ TODO: We likely want to special case the situation where
+ peeling is optimizing out exit edges and only update
+ estimates here. */
+ if (wi::leu_p (npeel, loop->nb_iterations_estimate))
+ loop->nb_iterations_estimate -= npeel;
+ else
+ loop->any_estimate = false;
+ }
+ if (loop->any_upper_bound && precise)
+ {
+ if (wi::leu_p (npeel, loop->nb_iterations_upper_bound))
+ loop->nb_iterations_upper_bound -= npeel;
+ else
+ {
+ /* Peeling maximal number of iterations or more
+ makes no sense and is a bug.
+ We should peel completely. */
+ gcc_unreachable ();
+ }
+ }
+ if (loop->any_likely_upper_bound)
+ {
+ if (wi::leu_p (npeel, loop->nb_iterations_likely_upper_bound))
+ loop->nb_iterations_likely_upper_bound -= npeel;
+ else
+ {
+ loop->any_estimate = true;
+ loop->nb_iterations_estimate = 0;
+ loop->nb_iterations_likely_upper_bound = 0;
+ }
+ }
+}
+
/* If the loop is expected to iterate N times and is
small enough, duplicate the loop body N+1 times before
the loop itself. This way the hot path will never
fprintf (dump_file, "Peeled loop %d, %i times.\n",
loop->num, (int) npeel);
}
- if (loop->any_estimate)
- {
- if (wi::ltu_p (npeel, loop->nb_iterations_estimate))
- loop->nb_iterations_estimate -= npeel;
- else
- loop->nb_iterations_estimate = 0;
- }
- if (loop->any_upper_bound)
- {
- if (wi::ltu_p (npeel, loop->nb_iterations_upper_bound))
- loop->nb_iterations_upper_bound -= npeel;
- else
- loop->nb_iterations_upper_bound = 0;
- }
- if (loop->any_likely_upper_bound)
- {
- if (wi::ltu_p (npeel, loop->nb_iterations_likely_upper_bound))
- loop->nb_iterations_likely_upper_bound -= npeel;
- else
- {
- loop->any_estimate = true;
- loop->nb_iterations_estimate = 0;
- loop->nb_iterations_likely_upper_bound = 0;
- }
- }
+ adjust_loop_info_after_peeling (loop, npeel, true);
profile_count entry_count = profile_count::zero ();
edge e;