+ DB((dbg, LEVEL_4, "Got step %N\n", loop_info.step));
+
+ if (loop_info.iteration_phi != new_iteration_phi)
+ return 0;
+
+ } else {
+ /* RETURN */
+ return 0;
+ }
+
+ mode = get_irn_mode(loop_info.end_val);
+
+ DB((dbg, LEVEL_4, "start %N, end %N, step %N\n",
+ loop_info.start_val, loop_info.end_val, loop_info.step));
+
+ if (mode != mode_Is && mode != mode_Iu)
+ return 0;
+
+ /* TODO necessary? */
+ if (!are_mode_I(loop_info.start_val, loop_info.step, loop_info.end_val))
+ return 0;
+
+ DB((dbg, LEVEL_4, "mode integer\n"));
+
+ end_tar = get_Const_tarval(loop_info.end_val);
+ start_tar = get_Const_tarval(loop_info.start_val);
+ step_tar = get_Const_tarval(loop_info.step);
+
+ if (tarval_is_null(step_tar))
+ /* TODO Might be worth a warning. */
+ return 0;
+
+ DB((dbg, LEVEL_4, "step is not 0\n"));
+
+ if ((!tarval_is_negative(step_tar)) ^ (!is_Sub(loop_info.add)))
+ loop_info.decreasing = 1;
+
+ diff_tar = tarval_sub(end_tar, start_tar, mode);
+
+ /* We need at least count_tar steps to be close to end_val, maybe more.
+ * No way, that we have gone too many steps.
+ * This represents the 'latest value'.
+ * (If condition checks against latest value, is checked later) */
+ count_tar = tarval_div(diff_tar, step_tar);
+
+ /* Iv will not pass end_val (except overflows).
+ * Nothing done, as it would yield to no advantage. */
+ if (tarval_is_negative(count_tar)) {
+ DB((dbg, LEVEL_4, "Loop is endless or never taken."));
+ /* TODO Might be worth a warning. */
+ return 0;
+ }
+
+ ++stats.u_simple_counting_loop;
+
+ loop_info.latest_value = is_latest_val;
+
+ /* TODO split here
+ if (! is_simple_counting_loop(&count_tar))
+ return 0;
+ */
+
+ /* stepped can be negative, if step < 0 */
+ stepped = tarval_mul(count_tar, step_tar);
+
+ /* step as close to end_val as possible, */
+ /* |stepped| <= |end_tar|, and dist(stepped, end_tar) is smaller than a step. */
+ if (is_Sub(loop_info.add))
+ stepped = tarval_sub(start_tar, stepped, mode_Is);
+ else
+ stepped = tarval_add(start_tar, stepped);
+
+ DB((dbg, LEVEL_4, "stepped to %ld\n", get_tarval_long(stepped)));
+
+ proj_proj = get_Cmp_relation(cmp);
+ /* Assure that norm_proj is the stay-in-loop case. */
+ if (loop_info.exit_cond == 1)
+ norm_proj = get_negated_relation(proj_proj);
+ else
+ norm_proj = proj_proj;
+
+ DB((dbg, LEVEL_4, "normalized projection %s\n", get_relation_string(norm_proj)));
+ /* Executed at most once (stay in counting loop if a Eq b) */
+ if (norm_proj == ir_relation_equal)
+ /* TODO Might be worth a warning. */
+ return 0;
+
+ /* calculates next values and increases count_tar according to it */
+ success = simulate_next(&count_tar, stepped, step_tar, end_tar, norm_proj);
+ if (! success)
+ return 0;
+
+ /* We run loop once more, if we compare to the
+ * not yet in-/decreased iv. */
+ if (is_latest_val == 0) {
+ DB((dbg, LEVEL_4, "condition uses not latest iv value\n"));
+ count_tar = tarval_add(count_tar, get_tarval_one(mode));
+ }
+
+ DB((dbg, LEVEL_4, "loop taken %ld times\n", get_tarval_long(count_tar)));
+
+ /* Assure the loop is taken at least 1 time. */
+ if (tarval_is_null(count_tar)) {
+ /* TODO Might be worth a warning. */
+ return 0;
+ }
+
+ loop_info.count_tar = count_tar;
+ return get_preferred_factor_constant(count_tar);
+}
+
+/**
+ * Loop unrolling
+ */
+static void unroll_loop(void)
+{
+
+ if (! (loop_info.nodes > 0))
+ return;
+
+ if (loop_info.nodes > opt_params.max_unrolled_loop_size) {
+ DB((dbg, LEVEL_2, "Nodes %d > allowed nodes %d\n",
+ loop_info.nodes, opt_params.max_unrolled_loop_size));
+ ++stats.too_large;
+ return;
+ }
+
+ if (loop_info.calls > 0) {
+ DB((dbg, LEVEL_2, "Calls %d > allowed calls 0\n",
+ loop_info.calls));
+ ++stats.calls_limit;
+ return;
+ }
+
+ unroll_nr = 0;
+
+ /* get_unroll_decision_constant and invariant are completely
+ * independent for flexibility.
+ * Some checks may be performed twice. */
+
+ /* constant case? */
+ if (opt_params.allow_const_unrolling)
+ unroll_nr = get_unroll_decision_constant();
+ if (unroll_nr > 1) {
+ loop_info.unroll_kind = constant;
+
+ } else {
+ /* invariant case? */
+ if (opt_params.allow_invar_unrolling)
+ unroll_nr = get_unroll_decision_invariant();
+ if (unroll_nr > 1)
+ loop_info.unroll_kind = invariant;
+ }
+
+ DB((dbg, LEVEL_2, " *** Unrolling %d times ***\n", unroll_nr));
+
+ if (unroll_nr > 1) {
+ loop_entries = NEW_ARR_F(entry_edge, 0);
+
+ /* Get loop outs */
+ irg_walk_graph(current_ir_graph, get_loop_entries, NULL, NULL);
+
+ if (loop_info.unroll_kind == constant) {
+ if ((int)get_tarval_long(loop_info.count_tar) == unroll_nr)
+ loop_info.needs_backedge = 0;
+ else
+ loop_info.needs_backedge = 1;
+ } else {
+ loop_info.needs_backedge = 1;
+ }
+
+ /* Use phase to keep copy of nodes from the condition chain. */
+ phase = new_phase(current_ir_graph, phase_irn_init_default);
+
+ /* Copies the loop */
+ copy_loop(loop_entries, unroll_nr - 1);
+
+ /* Line up the floating copies. */
+ place_copies(unroll_nr - 1);
+
+ /* Remove phis with 1 in
+ * If there were no nested phis, this would not be necessary.
+ * Avoiding the creation in the first place
+ * leads to complex special cases. */
+ irg_walk_graph(current_ir_graph, correct_phis, NULL, NULL);
+
+ if (loop_info.unroll_kind == constant)
+ ++stats.constant_unroll;
+ else
+ ++stats.invariant_unroll;
+
+ set_irg_doms_inconsistent(current_ir_graph);
+
+ DEL_ARR_F(loop_entries);
+ }