+ success = get_invariant_pred(loop_condition, &loop_info.end_val, &iteration_path);
+ DB((dbg, LEVEL_4, "pred invar %d\n", success));
+
+ if (! success)
+ return 0;
+
+ DB((dbg, LEVEL_4, "Invariant End_val %N, other %N\n", loop_info.end_val, iteration_path));
+
+ /* We may find the add or the phi first.
+ * Until now we only have end_val. */
+ if (is_Add(iteration_path) || is_Sub(iteration_path)) {
+
+ loop_info.add = iteration_path;
+ DB((dbg, LEVEL_4, "Case 1: Got add %N (maybe not sane)\n", loop_info.add));
+
+ /* Preds of the add should be step and the iteration_phi */
+ success = get_const_pred(loop_info.add, &loop_info.step, &loop_info.iteration_phi);
+ if (! success)
+ return 0;
+
+ DB((dbg, LEVEL_4, "Got step %N\n", loop_info.step));
+
+ if (! is_Phi(loop_info.iteration_phi))
+ return 0;
+
+ DB((dbg, LEVEL_4, "Got phi %N\n", loop_info.iteration_phi));
+
+ /* Find start_val.
+ * Does necessary sanity check of add, if it is already set. */
+ success = get_start_and_add(loop_info.iteration_phi, invariant);
+ if (! success)
+ return 0;
+
+ DB((dbg, LEVEL_4, "Got start A %N\n", loop_info.start_val));
+
+ } else if (is_Phi(iteration_path)) {
+ ir_node *new_iteration_phi;
+
+ loop_info.iteration_phi = iteration_path;
+ DB((dbg, LEVEL_4, "Case 2: Got phi %N\n", loop_info.iteration_phi));
+
+ /* Find start_val and add-node.
+ * Does necessary sanity check of add, if it is already set. */
+ success = get_start_and_add(loop_info.iteration_phi, invariant);
+ if (! success)
+ return 0;
+
+ DB((dbg, LEVEL_4, "Got start B %N\n", loop_info.start_val));
+ DB((dbg, LEVEL_4, "Got add or sub %N\n", loop_info.add));
+
+ success = get_const_pred(loop_info.add, &loop_info.step, &new_iteration_phi);
+ if (! success)
+ return 0;
+
+ DB((dbg, LEVEL_4, "Got step (B) %N\n", loop_info.step));
+
+ if (loop_info.iteration_phi != new_iteration_phi)
+ return 0;
+
+ } else {
+ 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"));
+
+ 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"));
+
+ create_duffs_block();
+
+ return loop_info.max_unroll;
+}
+
+/* Returns unroll factor,
+ * given maximum unroll factor and number of loop passes. */
+static unsigned get_preferred_factor_constant(ir_tarval *count_tar)
+{
+ ir_tarval *tar_6, *tar_5, *tar_4, *tar_3, *tar_2;
+ unsigned prefer;
+ ir_mode *mode = get_irn_mode(loop_info.end_val);
+
+ tar_6 = new_tarval_from_long(6, mode);
+ tar_5 = new_tarval_from_long(5, mode);
+ tar_4 = new_tarval_from_long(4, mode);
+ tar_3 = new_tarval_from_long(3, mode);
+ tar_2 = new_tarval_from_long(2, mode);
+
+ /* loop passes % {6, 5, 4, 3, 2} == 0 */
+ if (tarval_is_null(tarval_mod(count_tar, tar_6)))
+ prefer = 6;
+ else if (tarval_is_null(tarval_mod(count_tar, tar_5)))
+ prefer = 5;
+ else if (tarval_is_null(tarval_mod(count_tar, tar_4)))
+ prefer = 4;
+ else if (tarval_is_null(tarval_mod(count_tar, tar_3)))
+ prefer = 3;
+ else if (tarval_is_null(tarval_mod(count_tar, tar_2)))
+ prefer = 2;
+ else {
+ /* gcd(max_unroll, count_tar) */
+ int a = loop_info.max_unroll;
+ int b = (int)get_tarval_long(count_tar);
+ int c;
+
+ DB((dbg, LEVEL_4, "gcd of max_unroll %d and count_tar %d: ", a, b));
+
+ do {
+ c = a % b;
+ a = b; b = c;
+ } while( c != 0);
+
+ DB((dbg, LEVEL_4, "%d\n", a));
+ return a;
+ }
+
+ DB((dbg, LEVEL_4, "preferred unroll factor %d\n", prefer));
+
+ /*
+ * If our preference is greater than the allowed unroll factor
+ * we either might reduce the preferred factor and prevent a duffs device block,
+ * or create a duffs device block, from which in this case (constants only)
+ * we know the startloop at compiletime.
+ * The latter yields the following graphs.
+ * but for code generation we would want to use graph A.
+ * The graphs are equivalent. So, we can only reduce the preferred factor.
+ * A) B)
+ * PreHead PreHead
+ * | ,--. | ,--.
+ * \ Loop1 \ Loop2 \
+ * \ | | / | |
+ * Loop2 / / Loop1 /
+ * | `--' | `--'
+ */
+
+ if (prefer <= loop_info.max_unroll)
+ return prefer;
+ else {
+ switch(prefer) {
+ case 6:
+ if (loop_info.max_unroll >= 3)
+ return 3;
+ else if (loop_info.max_unroll >= 2)
+ return 2;
+ else
+ return 0;
+
+ case 4:
+ if (loop_info.max_unroll >= 2)
+ return 2;
+ else
+ return 0;
+
+ default:
+ return 0;
+ }
+ }
+}
+
+/* Check if cur_loop is a simple counting loop.
+ * Start, step and end are constants.
+ * TODO The whole constant case should use procedures similar to
+ * the invariant case, as they are more versatile. */
+/* TODO split. */
+static unsigned get_unroll_decision_constant(void)
+{
+ ir_node *cmp, *iteration_path;
+ unsigned success, is_latest_val;
+ ir_tarval *start_tar, *end_tar, *step_tar, *diff_tar, *count_tar;
+ ir_tarval *stepped;
+ ir_relation proj_proj, norm_proj;
+ ir_mode *mode;
+
+ /* RETURN if loop is not 'simple' */
+ cmp = is_simple_loop();
+ if (cmp == NULL)
+ return 0;