/**
* Fill in loop control fields
*
- * Based on analysis of loop variables, this function tries to remove sequences
- * in the loop of the form
+ * Based on analysis of loop variables, this function tries to remove
+ * redundant sequences in the loop of the form
*
* (if (expression bool ...) (break))
*
- * and fill in the \c normative_bound field of the \c ir_loop.
- *
- * In this process, some conditional break-statements may be eliminated
- * altogether. For example, if it is provable that one loop exit condition will
+ * For example, if it is provable that one loop exit condition will
* always be satisfied before another, the unnecessary exit condition will be
* removed.
*/
}
/* If the limiting terminator has a lower iteration count than the
- * normative loop bound (if any), then make this a normatively bounded
- * loop with the new iteration count.
+ * normative loop bound (if any), then the loop doesn't need a normative
+ * bound anymore.
*/
- if (ir->normative_bound < 0 || iterations < ir->normative_bound)
- ir->normative_bound = iterations;
+ if (ir->normative_bound >= 0 && iterations < ir->normative_bound)
+ ir->normative_bound = -1;
}
/* Remove the conditional break statements associated with all terminators
- * that are associated with a fixed iteration count; the normative bound
- * will take care of terminating the loop.
+ * that are associated with a fixed iteration count, except for the one
+ * associated with the limiting terminator--that one needs to stay, since
+ * it terminates the loop. Exception: if the loop still has a normative
+ * bound, then that terminates the loop, so we don't even need the limiting
+ * terminator.
*/
foreach_list(node, &ls->terminators) {
loop_terminator *t = (loop_terminator *) node;
if (t->iterations < 0)
continue;
- t->ir->remove();
+ if (ir->normative_bound >= 0 || t != ls->limiting_terminator) {
+ t->ir->remove();
- assert(ls->num_loop_jumps > 0);
- ls->num_loop_jumps--;
+ assert(ls->num_loop_jumps > 0);
+ ls->num_loop_jumps--;
- this->progress = true;
+ this->progress = true;
+ }
}
return visit_continue;
loop_variable_state *const ls = this->state->get(ir);
int iterations;
+ /* Note: normatively-bounded loops aren't created anymore. */
+ assert(ir->normative_bound < 0);
+
/* If we've entered a loop that hasn't been analyzed, something really,
* really bad has happened.
*/
/* Don't try to unroll loops where the number of iterations is not known
* at compile-time.
*/
- if (ir->normative_bound < 0)
+ if (ls->limiting_terminator == NULL)
return visit_continue;
- iterations = ir->normative_bound;
+ iterations = ls->limiting_terminator->iterations;
/* Don't try to unroll loops that have zillions of iterations either.
*/
if (count.fail || count.nodes * iterations > (int)max_iterations * 5)
return visit_continue;
- if (ls->num_loop_jumps > 1)
+ /* Note: the limiting terminator contributes 1 to ls->num_loop_jumps.
+ * We'll be removing the limiting terminator before we unroll.
+ */
+ assert(ls->num_loop_jumps > 0);
+ unsigned predicted_num_loop_jumps = ls->num_loop_jumps - 1;
+
+ if (predicted_num_loop_jumps > 1)
return visit_continue;
- if (ls->num_loop_jumps == 0) {
+ if (predicted_num_loop_jumps == 0) {
+ ls->limiting_terminator->ir->remove();
simple_unroll(ir, iterations);
return visit_continue;
}
*/
last_ir->remove();
+ ls->limiting_terminator->ir->remove();
simple_unroll(ir, 1);
return visit_continue;
}
/* recognize loops in the form produced by ir_lower_jumps */
ir_instruction *cur_ir = (ir_instruction *) node;
+ /* Skip the limiting terminator, since it will go away when we
+ * unroll.
+ */
+ if (cur_ir == ls->limiting_terminator->ir)
+ continue;
+
ir_if *ir_if = cur_ir->as_if();
if (ir_if != NULL) {
/* Determine which if-statement branch, if any, ends with a
(ir_instruction *) ir_if->then_instructions.get_tail();
if (is_break(ir_if_last)) {
+ ls->limiting_terminator->ir->remove();
splice_post_if_instructions(ir_if, &ir_if->else_instructions);
ir_if_last->remove();
complex_unroll(ir, iterations, false);
(ir_instruction *) ir_if->else_instructions.get_tail();
if (is_break(ir_if_last)) {
+ ls->limiting_terminator->ir->remove();
splice_post_if_instructions(ir_if, &ir_if->then_instructions);
ir_if_last->remove();
complex_unroll(ir, iterations, true);