+/**
+ * Returns last element of linked list of copies by
+ * walking the linked list.
+ */
+static ir_node *get_last_copy(ir_node *node)
+{
+ ir_node *copy, *cur;
+ cur = node;
+ while ((copy = get_copy(cur))) {
+ cur = copy;
+ }
+ return cur;
+}
+
+/**
+ * Rewire floating copies of the current loop.
+ */
+static void unrolling_fix_cf(void)
+{
+ ir_node *loophead = loop_cf_head;
+ int headarity = get_irn_arity(loophead);
+ ir_node *phi, *headnode;
+ /*ir_node *high, *low;*/
+ int i;
+
+ int uhead_in_n = 0;
+ int backedges_n = get_backedge_n(loophead, 0);
+ int unroll_arity = backedges_n;
+
+ /* Create ins for all heads and their phis */
+ headnode = get_copy(loophead);
+ for_each_copy(headnode) {
+ NEW_ARR_A(ir_node *, get_node_info(headnode)->ins, unroll_arity);
+ for_each_phi(headnode, phi) {
+ NEW_ARR_A(ir_node *, get_node_info(phi)->ins, unroll_arity);
+ }
+ }
+
+ /* Append the copies to the existing loop. */
+ for (i = 0; i < headarity; i++) {
+ ir_node *upper_head = loophead;
+ ir_node *lower_head = get_copy(loophead);
+
+ ir_node *upper_pred = get_irn_n(loophead, i);
+ ir_node *lower_pred = get_copy(get_irn_n(loophead, i));
+
+ ir_node *last_pred;
+
+ /**
+ * Build unrolled loop top down
+ */
+ if (is_backedge(loophead, i) && !is_alien_edge(loophead, i)) {
+ for_each_copy2(upper_head, lower_head, upper_pred, lower_pred) {
+ get_node_info(lower_head)->ins[uhead_in_n] = upper_pred;
+
+ for_each_phi(upper_head, phi) {
+ ir_node *phi_copy = get_copy(phi);
+ get_node_info(phi_copy)->ins[uhead_in_n] = get_irn_n(phi, i);
+ }
+ }
+
+ last_pred = upper_pred;
+ ++uhead_in_n;
+
+ /* Fix the topmost loop heads backedges. */
+ set_irn_n(loophead, i, last_pred);
+ for_each_phi(loophead, phi) {
+ ir_node *last_phi = get_last_copy(phi);
+ ir_node *pred = get_irn_n(last_phi, i);
+ set_irn_n(phi, i, pred);
+ }
+ }
+ }
+
+ headnode = get_copy(loophead);
+ for_each_copy(headnode) {
+ set_irn_in(headnode, unroll_arity, get_node_info(headnode)->ins);
+ for_each_phi(headnode, phi) {
+ set_irn_in(phi, unroll_arity, get_node_info(phi)->ins);
+ }
+ }
+}
+
+#if 0
+static ir_node *add_phi(ir_node *node, int phi_pos)
+{
+ ir_mode *mode;
+ ir_node *phi;
+ ir_node **in;
+ mode = get_irn_mode(get_irn_n(node, phi_pos));
+ ir_node *block = get_nodes_block(node);
+ int n_cfgpreds = get_irn_arity(block);
+ ir_node *pred = get_irn_n(node, phi_pos);
+ int i;
+
+ /* create a new Phi */
+ NEW_ARR_A(ir_node*, in, n_cfgpreds);
+ for (i = 0; i < n_cfgpreds; ++i)
+ in[i] = new_Unknown(mode); /*pred;*/
+
+ phi = new_r_Phi(block, n_cfgpreds, in, mode);
+
+ assert(phi && "phi null");
+ assert(is_Bad(phi) && "phi bad");
+
+ /* Important: always keep block phi list up to date. */
+ add_Block_phi(block, phi);
+ /* EVERY node is assumed to have a node_info linked. */
+ alloc_node_info(phi, NULL);
+
+ set_irn_n(node, phi_pos, phi);
+ return phi;
+}
+#endif
+
+
+/**
+ * Loop unrolling
+ * Could be improved with variable range informations.
+ */
+static void loop_unrolling(void)
+{
+ int i, j;
+
+ unroll_times = 7;
+
+ cur_loop_outs = NEW_ARR_F(out_edge, 0);
+ irg_walk_graph( current_ir_graph, get_loop_outs, NULL, NULL );
+
+ ir_reserve_resources(current_ir_graph, IR_RESOURCE_IRN_VISITED);
+
+ /* duplicate whole loop content */
+ inc_irg_visited(current_ir_graph);
+
+ for (i = 0; i < ARR_LEN(cur_loop_outs); ++i) {
+ out_edge entry = cur_loop_outs[i];
+ ir_node *node = entry.node;
+ ir_node *pred = get_irn_n(entry.node, entry.pred_irn_n);
+ if (!is_Block(node)) {
+ for (j = 0; j < unroll_times - 1; ++j) {
+ copy_walk(pred, is_in_loop, cur_loop);
+ pred = get_copy(pred);
+ }
+ }
+ }
+
+ for (i = 0; i < ARR_LEN(cur_loop_outs); ++i) {
+ out_edge entry = cur_loop_outs[i];
+ ir_node *node = entry.node;
+ ir_node *pred = get_irn_n(entry.node, entry.pred_irn_n);
+
+ if (is_Block(node)) {
+ for (j = 0; j < unroll_times - 1; ++j) {
+ copy_walk(pred, is_in_loop, cur_loop);
+ duplicate_preds(node, entry.pred_irn_n, get_copy(pred));
+
+ pred = get_copy(pred);
+ }
+ }
+ }
+
+ ir_free_resources(current_ir_graph, IR_RESOURCE_IRN_VISITED);
+
+ /*dump_ir_graph(current_ir_graph, "-raw");*/
+
+ /* LDBG 2 */
+#if 1
+ /* Line up the floating copies. */
+ unrolling_fix_cf();
+
+ /* Generate phis for all loop outs */
+ for (i = 0; i < ARR_LEN(cur_loop_outs); ++i) {
+ out_edge entry = cur_loop_outs[i];
+ ir_node *node = entry.node;
+ ir_node *pred = get_irn_n(entry.node, entry.pred_irn_n);
+
+ if (!is_Block(node) && !is_End(node)) {
+ DB((dbg, LEVEL_5, " construct_ssa_n def %N node %N pos %d\n",
+ pred, node, entry.pred_irn_n));
+ construct_ssa_n(pred, node);
+ }
+ }
+#endif
+
+ DEL_ARR_F(cur_loop_outs);
+
+ set_irg_doms_inconsistent(current_ir_graph);
+ set_irg_loopinfo_inconsistent(current_ir_graph);
+ set_irg_outs_inconsistent(current_ir_graph);
+}
+
+/* Initialization and */