X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fopt%2Floop.c;h=39df5e583a2ed10d72f4c522af7844626f34196e;hb=a619ce99e40de4eb4481a590970a881e9f24627a;hp=4bc38d2e3bbf443ddf1371a20ed53b9b18601457;hpb=e3a9f433c6fcc0710e7e1a19234cfe5b2e3f2831;p=libfirm diff --git a/ir/opt/loop.c b/ir/opt/loop.c index 4bc38d2e3..39df5e583 100644 --- a/ir/opt/loop.c +++ b/ir/opt/loop.c @@ -20,16 +20,14 @@ /** * @file * @author Christian Helmer - * @brief - * Loop peeling, loop inversion and loop unrolling - * NOTE: Inversion creates abnormal looking loops because there is probably - * no head as single loop entry point. Therefore peeling - * will do nothing as it relies on the head as single loop entry point. + * @brief loop inversion and loop unrolling, loop peeling * * @version $Id$ */ #include "config.h" +#include "iroptimize.h" +#include "opt_init.h" #include "irnode.h" #include "debug.h" @@ -40,12 +38,10 @@ #include "irouts.h" #include "iredges.h" #include "irtools.h" -#include "array_t.h" /* automatic array */ -#include "beutil.h" /* get_block */ -#include "irloop_t.h" /*set_irn_loop*/ - -/* TODO during DBG */ -/*#include "irdump.h"*/ +#include "array_t.h" +#include "beutil.h" +#include "irloop_t.h" +#include "irpass.h" DEBUG_ONLY(static firm_dbg_module_t *dbg); @@ -59,13 +55,13 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg); /* current loop */ static ir_loop *cur_loop; -/* The loop walker should be possible to abort if nothing can be done anymore */ +/* abortable walker function */ typedef unsigned irg_walk_func_abortable(ir_node *, void *); -/* condition for breaking a copy_walk */ +/* condition for walking a node during a copy_walk */ typedef unsigned walker_condition(ir_node *); -/* stores node and position of a predecessor */ +/* node and position of a predecessor */ typedef struct out_edges { ir_node *node; int pred_irn_n; @@ -98,14 +94,16 @@ static ir_node *loop_peeled_head = NULL; /* Loop analysis informations */ typedef struct loop_info_t { + unsigned blocks; /* number of blocks in the loop */ unsigned calls; /* number of calls */ unsigned loads; /* number of load nodes */ + unsigned outs; /* outs without keepalives */ +#if 0 unsigned invariant_loads; unsigned stores; /* number of store nodes */ - unsigned blocks; /* number of blocks in the loop */ unsigned opnodes_n; /* nodes that probably result in an instruction */ - /* unsigned opnodes_head; */ - unsigned outs; /* outs without keepalives */ + unsigned do_invariant_opt; +#endif } loop_info_t; /* Information about the current loop */ @@ -114,12 +112,16 @@ static loop_info_t loop_info; /* A walker may start visiting a condition chain with these nodes. */ static out_edge *cond_chain_entries; +/* Number of unrolling */ +int unroll_times; + static unsigned head_inversion_node_count; -static unsigned head_inversion_node_limit; +static unsigned inversion_head_node_limit; static unsigned head_inversion_block_count; static unsigned enable_peeling; static unsigned enable_inversion; +static unsigned enable_unrolling; /** * @@ -130,7 +132,8 @@ static unsigned enable_inversion; /** * Creates object on the heap, and adds it to a linked list to free it later. */ -static node_info *new_node_info(void) { +static node_info *new_node_info(void) +{ node_info *l = XMALLOCZ(node_info); l->freelistnext = link_node_state_list; link_node_state_list = l; @@ -158,7 +161,7 @@ static void free_node_info(void) int a = 0; node_info *n; n = link_node_state_list; - while(n) { + while (n) { node_info *next = n->freelistnext; ++a; xfree(n); @@ -175,7 +178,7 @@ static void reset_node_infos(void) { node_info *next; next = link_node_state_list; - while(next->freelistnext) { + while (next->freelistnext) { node_info *cur = next; next = cur->freelistnext; cur->copy = NULL; @@ -184,29 +187,50 @@ static void reset_node_infos(void) } } +/* Returns the nodes node_info link. */ +static ir_node *get_link(ir_node *n) +{ + return ((node_info *)get_irn_link(n))->link; +} +/* Sets the nodes node_info link. */ +static void set_link(ir_node *n, ir_node *link) +{ + ((node_info *)get_irn_link(n))->link = link; +} -/* Returns the */ +/* Returns a nodes copy. */ static ir_node *get_copy(ir_node *n) { return ((node_info *)get_irn_link(n))->copy; } -/* Links the node to its copy */ +/* Sets a nodes copy. */ static void set_copy(ir_node *n, ir_node *copy) { ((node_info *)get_irn_link(n) )->copy = copy; } -/* Returns 0 if the node or block is not in cur_loop - * NOTE: get_irn_loop returns the ir_node loop attribute. - * But it seems only to be set correctly to blocks! - * Thus, without get_block this function does not work. +/** + * Convenience macro for iterating over every copy in a linked list + * of copies. + */ +#define for_each_copy(node) \ + for ( ; (node) ; (node) = get_copy(node)) + +/** + * Convenience macro for iterating over every copy in 2 linked lists + * of copies in parallel. + */ +#define for_each_copy2(high1, low1, high2, low2) \ + for ( ; (low1) && (low2); (high1) = (low1), (low1) = get_copy(low1), \ + (high2) = (low2), (low2) = get_copy(low2)) + +/* + * Returns 0 if the node or block is not in cur_loop. */ static unsigned is_in_loop(ir_node *node) { - /*DB((dbg, LEVEL_5, "node %ld inloop %d\n", node->node_nr, get_irn_loop(get_block(node)) == cur_loop));*/ - /*DB((dbg, LEVEL_5, "node %ld loop of node %d loop %d\n", node->node_nr, get_irn_loop(get_block(node)), cur_loop)); */ return (get_irn_loop(get_block(node)) == cur_loop); } @@ -220,10 +244,7 @@ static unsigned is_alien_edge(ir_node *n, int i) static void reset_block_mark(ir_node *node, void * env) { (void) env; - /* - DB((dbg, LEVEL_5, "UNMARK ...")); - DB((dbg, LEVEL_5, " UNMARK %ld\n", get_irn_node_nr(node))); - */ + if (is_Block(node)) set_Block_mark(node, 0); } @@ -234,17 +255,16 @@ static unsigned is_nodesblock_marked(ir_node* node) } /* Returns the number of blocks in a loop. */ -int get_loop_n_blocks(ir_loop *loop) { +static int get_loop_n_blocks(ir_loop *loop) +{ int elements, e; int blocks = 0; elements = get_loop_n_elements(loop); - for(e=0; enode_nr));*/ + if (is_ir_node(elem.kind) && is_Block(elem.node)) ++blocks; - } } return blocks; } @@ -253,54 +273,56 @@ int get_loop_n_blocks(ir_loop *loop) { * Add newpred at position pos to node and also add the corresponding value to the phis. * Requires block phi list. */ -static int duplicate_preds(ir_node* node, unsigned pos, ir_node* newpred) +static int duplicate_preds(ir_node* block, unsigned pos, ir_node* newpred) { - ir_node** ins; + ir_node **ins; + /*int *is_be;*/ ir_node *phi; int block_arity; int i; - assert(is_Block(node) && "duplicate_preds is only allowed for blocks"); + assert(is_Block(block) && "duplicate_preds may be called for blocks only"); - DB((dbg, LEVEL_5, "duplicate_preds(node %ld, pos %d, newpred %ld)\n", - get_irn_node_nr(node), pos, get_irn_node_nr(newpred))); + DB((dbg, LEVEL_5, "duplicate_preds(node %N, pos %d, newpred %N)\n", block, pos, newpred)); - block_arity = get_irn_arity(node); + block_arity = get_irn_arity(block); NEW_ARR_A(ir_node*, ins, block_arity + 1); - for (i = 0; i < block_arity; ++i) - ins[i] = get_irn_n(node, i); + + for (i = 0; i < block_arity; ++i) { + ins[i] = get_irn_n(block, i); + } ins[block_arity] = newpred; - set_irn_in(node, block_arity + 1, ins); + set_irn_in(block, block_arity + 1, ins); - for_each_phi(node, phi) { + /* LDBG 1 */ +#if 1 + for_each_phi(block, phi) { int phi_arity = get_irn_arity(phi); - DB((dbg, LEVEL_5, "duplicate_preds: fixing phi %ld\n", get_irn_node_nr(phi))); + DB((dbg, LEVEL_5, "duplicate_preds: fixing phi %N\n", phi)); NEW_ARR_A(ir_node *, ins, block_arity + 1); - for (i=0; i < phi_arity; ++i) { - DB((dbg, LEVEL_5, "in %ld\n", get_irn_node_nr(get_irn_n(phi, i)))); + for (i = 0; i < phi_arity; ++i) { + DB((dbg, LEVEL_5, "pos %N\n", get_irn_n(phi, i))); ins[i] = get_irn_n(phi, i); } - ins[block_arity] = get_irn_n(phi, pos); + ins[block_arity] = get_copy(get_irn_n(phi, pos)); set_irn_in(phi, block_arity + 1, ins); } - /* return new position */ +#endif return block_arity; } -/* Finds loop head and loop_info */ +/** + * Finds loop head and loop_info. + */ static void get_loop_info(ir_node *node, void *env) { unsigned node_in_loop, pred_in_loop; int i, arity; (void) env; - /*DB((dbg, LEVEL_5, "node %+F\n", node));*/ - - get_node_info(node)->done = 1; - arity = get_irn_arity(node); for (i = 0; i < arity; i++) { ir_node *pred = get_irn_n(node, i); @@ -310,15 +332,8 @@ static void get_loop_info(ir_node *node, void *env) /* collect some loop information */ if (node_in_loop) { - /*DB((dbg, LEVEL_1, "--------------------------------- inloop %+F\n", node));*/ - if (is_Store(node)) - ++loop_info.stores; - if (is_Load(node)) - ++loop_info.loads; if (is_Call(node)) ++loop_info.calls; - if (!is_Block(node) && !is_Proj(node) && !is_Phi(node)) - ++loop_info.opnodes_n; } /* Find the loops head/the blocks with cfpred outside of the loop */ @@ -326,7 +341,7 @@ static void get_loop_info(ir_node *node, void *env) ir_node *cfgpred = get_Block_cfgpred(node, i); if (!is_in_loop(cfgpred)) { - DB((dbg, LEVEL_1, "potential head %+F because inloop and pred %+F not inloop\n", node, pred)); + DB((dbg, LEVEL_5, "potential head %+F because inloop and pred %+F not inloop\n", node, pred)); /* another head? We do not touch this. */ if (loop_cf_head && loop_cf_head != node) { loop_cf_head_valid = 0; @@ -346,7 +361,7 @@ static void get_loop_outs(ir_node *node, void *env) (void) env; arity = get_irn_arity(node); - for (i = 0; i < arity; i++) { + for (i = 0; i < arity; ++i) { ir_node *pred = get_irn_n(node, i); pred_in_loop = is_in_loop(pred); @@ -357,69 +372,15 @@ static void get_loop_outs(ir_node *node, void *env) entry.node = node; entry.pred_irn_n = i; ARR_APP1(out_edge, cur_loop_outs, entry); - if (node != get_irg_end(current_ir_graph)) - ++loop_info.outs; } } } -/** - * Finds invariant loads and marks them as invariant. - * (has to be post walk) - */ -static unsigned get_invariants(ir_node *node, void *env) -{ - unsigned invar = 1; - int arity = get_irn_arity(node); - (void) env; - - /* RETURN, no preds to visit */ - if (arity == 0) return 0; - - if (is_Load(node)) { - ir_node *pred = get_Load_ptr(node); - if ( (get_Load_volatility(node) == volatility_non_volatile) & - (!is_in_loop(pred) - || is_Const(pred) - || is_SymConst(pred) - || get_node_info(node)->invariant ) ) { - get_node_info(node)->invariant = 1; - ++loop_info.invariant_loads; - } else - { - get_node_info(node)->invariant = 0; - } - } else { - int i; - invar = 1; - /* find loop variant preds */ - for(i = 0; i < arity; ++i) { - ir_node *pred = get_irn_n(node, i); - - if ( is_in_loop(pred) /* outside loop is loop invariant */ - && !is_Const(pred) /* constants */ - && !is_SymConst(pred) /* SymConst */ - && !get_node_info(node)->invariant ) { /* pred is marked as invariant */ - invar = 0; - } - } - - if (invar) { - get_node_info(node)->invariant = 1; - } else { - get_node_info(node)->invariant = 0; - } - } - return 0; -} - static ir_node *ssa_second_def; static ir_node *ssa_second_def_block; /** - * Walks the graph bottom up, searching for definitions and create phis. - * (Does not handle the special case where the second definition is in the block of the user - * of the original definition because it is not necessary here.) + * Walks the graph bottom up, searching for definitions and creates phis. */ static ir_node *search_def_and_create_phis(ir_node *block, ir_mode *mode) { @@ -429,7 +390,7 @@ static ir_node *search_def_and_create_phis(ir_node *block, ir_mode *mode) ir_node *phi; ir_node **in; - DB((dbg, LEVEL_5, "ssa search_def_and_create_phis: block %ld\n", get_irn_node_nr(block))); + DB((dbg, LEVEL_5, "ssa search_def_and_create_phis: block %N\n", block)); /* Prevents creation of phi that would be bad anyway. * Dead and bad blocks. */ @@ -437,14 +398,14 @@ static ir_node *search_def_and_create_phis(ir_node *block, ir_mode *mode) return new_Bad(); if (block == ssa_second_def_block) { - DB((dbg, LEVEL_5, "ssa found second definition: use second def %ld\n", get_irn_node_nr(ssa_second_def))); + DB((dbg, LEVEL_5, "ssa found second definition: use second def %N\n", ssa_second_def)); return ssa_second_def; } /* already processed this block? */ if (irn_visited(block)) { - ir_node *value = get_node_info(block)->link; - DB((dbg, LEVEL_5, "ssa already visited: use linked %ld\n", get_irn_node_nr(value))); + ir_node *value = get_link(block); + DB((dbg, LEVEL_5, "ssa already visited: use linked %N\n", value)); return value; } @@ -457,10 +418,10 @@ static ir_node *search_def_and_create_phis(ir_node *block, ir_mode *mode) ir_node *pred_block = get_Block_cfgpred_block(block, 0); ir_node *value; - DB((dbg, LEVEL_5, "ssa 1 pred: walk pred %ld\n", get_irn_node_nr(pred_block))); + DB((dbg, LEVEL_5, "ssa 1 pred: walk pred %N\n", pred_block)); value = search_def_and_create_phis(pred_block, mode); - get_node_info(block)->link = value; + set_link(block, value); mark_irn_visited(block); return value; @@ -468,7 +429,7 @@ static ir_node *search_def_and_create_phis(ir_node *block, ir_mode *mode) /* create a new Phi */ NEW_ARR_A(ir_node*, in, n_cfgpreds); - for(i = 0; i < n_cfgpreds; ++i) + for (i = 0; i < n_cfgpreds; ++i) in[i] = new_Unknown(mode); phi = new_r_Phi(block, n_cfgpreds, in, mode); @@ -478,16 +439,20 @@ static ir_node *search_def_and_create_phis(ir_node *block, ir_mode *mode) /* EVERY node is assumed to have a node_info linked. */ alloc_node_info(phi, NULL); - DB((dbg, LEVEL_5, "ssa phi creation: link new phi %ld to block %ld\n", get_irn_node_nr(phi), get_irn_node_nr(block))); + DB((dbg, LEVEL_5, "ssa phi creation: link new phi %N to block %N\n", phi, block)); - get_node_info(block)->link = phi; + set_link(block, phi); mark_irn_visited(block); /* set Phi predecessors */ - for(i = 0; i < n_cfgpreds; ++i) { + for (i = 0; i < n_cfgpreds; ++i) { + ir_node *pred_val; ir_node *pred_block = get_Block_cfgpred_block(block, i); - ir_node *pred_val = search_def_and_create_phis(pred_block, mode); - DB((dbg, LEVEL_5, "ssa phi pred:phi %ld, pred %ld\n", get_irn_node_nr(phi), get_irn_node_nr(pred_val))); + assert(pred_block != NULL); + pred_val = search_def_and_create_phis(pred_block, mode); + assert(pred_val != NULL); + + DB((dbg, LEVEL_5, "ssa phi pred:phi %N, pred %N\n", phi, pred_val)); set_irn_n(phi, i, pred_val); } return phi; @@ -496,7 +461,7 @@ static ir_node *search_def_and_create_phis(ir_node *block, ir_mode *mode) /** * Given a set of values this function constructs SSA-form for the users of the * first value (the users are determined through the out-edges of the value). - * Uses the irn_visited flags. Works without using the dominance tree. + * Works without using the dominance tree. */ static void construct_ssa(ir_node *orig_block, ir_node *orig_val, ir_node *second_block, ir_node *second_val) @@ -519,7 +484,7 @@ static void construct_ssa(ir_node *orig_block, ir_node *orig_val, inc_irg_visited(irg); mode = get_irn_mode(orig_val); - get_node_info(orig_block)->link = orig_val; + set_link(orig_block, orig_val); mark_irn_visited(orig_block); ssa_second_def_block = second_block; @@ -536,7 +501,7 @@ static void construct_ssa(ir_node *orig_block, ir_node *orig_val, if (is_End(user)) continue; - DB((dbg, LEVEL_5, "original user %ld\n", get_irn_node_nr(user))); + DB((dbg, LEVEL_5, "original user %N\n", user)); if (is_Phi(user)) { ir_node *pred_block = get_Block_cfgpred_block(user_block, j); @@ -553,6 +518,72 @@ static void construct_ssa(ir_node *orig_block, ir_node *orig_val, ir_free_resources(irg, IR_RESOURCE_IRN_VISITED); } +/* + * Construct SSA for def and all of its copies. + */ +static void construct_ssa_n(ir_node *def, ir_node *user) +{ + ir_graph *irg; + ir_mode *mode; + ir_node *iter = def; + const ir_edge_t *edge; + const ir_edge_t *next; + irg = get_irn_irg(def); + + ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED); + inc_irg_visited(irg); + + mode = get_irn_mode(def); + + for_each_copy(iter) { + set_link(get_nodes_block(iter), iter); + mark_irn_visited(get_nodes_block(iter)); + + DB((dbg, LEVEL_5, "ssa_n: Link def %N to block %N\n", + iter, get_nodes_block(iter))); + } + + /* Need to search the outs, because we need the in-pos on the user node. */ + foreach_out_edge_safe(def, edge, next) { + ir_node *edge_user = get_edge_src_irn(edge); + int edge_src = get_edge_src_pos(edge); + ir_node *user_block = get_nodes_block(user); + ir_node *newval; + + if (edge_user != user) + continue; + + if (is_Phi(user)) { + ir_node *pred_block = get_Block_cfgpred_block(user_block, edge_src); + newval = search_def_and_create_phis(pred_block, mode); + } else { + newval = search_def_and_create_phis(user_block, mode); + } + + if (newval != user && !is_Bad(newval)) + set_irn_n(user, edge_src, newval); + } + + ir_free_resources(irg, IR_RESOURCE_IRN_VISITED); +} + +/** + * Construct SSA for all definitions in arr. + */ +static void construct_ssa_foreach(ir_node **arr, int arr_n) +{ + int i; + for (i = 0; i < arr_n ; ++i) { + ir_node *cppred, *block, *cpblock, *pred; + + pred = arr[i]; + cppred = get_copy(pred); + block = get_nodes_block(pred); + cpblock = get_nodes_block(cppred); + construct_ssa(block, pred, cpblock, cppred); + } +} + /* get the number of backedges without alien bes */ static int get_backedge_n(ir_node *loophead, unsigned with_alien) { @@ -561,39 +592,12 @@ static int get_backedge_n(ir_node *loophead, unsigned with_alien) int arity = get_irn_arity(loophead); for (i = 0; i < arity; ++i) { ir_node *pred = get_irn_n(loophead, i); - if (is_backedge(loophead, i) && ( with_alien || is_in_loop(pred)) ) + if (is_backedge(loophead, i) && (with_alien || is_in_loop(pred))) ++be_n; } return be_n; } -/** - * Sets the nodes backedges, according to its predecessors link. - */ -static void fix_backedge_info(ir_node *node) -{ - int i; - for (i = 0; i < get_irn_arity(node); ++i) { - ir_node *pred = get_irn_n(node, i); - if (get_node_info(pred)->link != NULL) { - set_backedge(node, i); - get_node_info(pred)->link = NULL; - DB((dbg, LEVEL_5, "fix backedge: node %ld pred %ld is backedge\n", - get_irn_node_nr(node), get_irn_node_nr(pred))); - } else { - set_not_backedge(node, i); - DB((dbg, LEVEL_5, "fix backedge: node %ld pred %ld is not backedge\n", - get_irn_node_nr(node), get_irn_node_nr(pred))); - } - } -} - -/** - * - * ============= PEELING ===================================== - * - */ - /** * Rewires the heads after peeling. */ @@ -637,17 +641,15 @@ static void peel_fix_heads(void) */ if (is_backedge(loophead, i) && !is_alien_edge(loophead, i)) { loopheadnins[lheadin_c] = orgjmp; - /* marks out edge as backedge */ - get_node_info(orgjmp)->link = orgjmp; for_each_phi(loophead, phi) { get_node_info( phi )->ins[lheadin_c] = get_irn_n( phi, i) ; } ++lheadin_c; - loopheadnins[lheadin_c] = copyjmp; /* former bes of the peeled code origin now from the loophead */ - /* marks out edge as normal edge */ - get_node_info(copyjmp)->link = NULL; - /* get_irn_n( get_copy_of(phi), i) get_copy_of(get_irn_n( phi, i)) + /* former bes of the peeled code origin now from the loophead */ + loopheadnins[lheadin_c] = copyjmp; + + /* get_irn_n( get_copy_of(phi), i ) get_copy_of( get_irn_n( phi, i) ) * Order is crucial! Predecessors outside of the loop are non existent. * The copy (cloned with its ins!) has pred i, * but phis pred i might not have a copy of itself. @@ -658,8 +660,6 @@ static void peel_fix_heads(void) ++lheadin_c; } else { peelheadnins[pheadin_c] = orgjmp; - /* marks out edge as normal edge */ - get_node_info(orgjmp)->link = NULL; for_each_phi(peelhead, phi) { get_node_info( phi )->ins[pheadin_c] = get_irn_n(phi, i); } @@ -671,17 +671,10 @@ static void peel_fix_heads(void) lheadin_c == ARR_LEN(loopheadnins) && "the constructed head arities do not match the predefined arities"); - /** - * assign the ins to the nodes - */ + /* assign the ins to the nodes */ set_irn_in(loophead, ARR_LEN(loopheadnins), loopheadnins); set_irn_in(peelhead, ARR_LEN(peelheadnins), peelheadnins); - /* Fixes the backedge information according to the link. - * Following loop optimizations might depend on it. */ - fix_backedge_info(loophead); - fix_backedge_info(peelhead); - for_each_phi(loophead, phi) { ir_node **ins = get_node_info( phi )->ins; set_irn_in(phi, lhead_arity, ins); @@ -695,24 +688,42 @@ static void peel_fix_heads(void) /** * Create a raw copy (ins are still the old ones) of the given node. + * We rely on copies to be NOT visited. */ static ir_node *rawcopy_node(ir_node *node) { + int i, arity; ir_node *cp; node_info *cpstate; cp = exact_copy(node); + + arity = get_irn_arity(node); + + for (i = 0; i < arity; ++i) { + if (is_backedge(node, i)) + set_backedge(cp, i); + } + set_copy(node, cp); cpstate = new_node_info(); set_irn_link(cp, cpstate); - mark_irn_visited(cp); + + + if (is_Block(cp)) { + /* TODO + * exact_copy already sets Macroblock. + * Why should we do this anyway? */ + set_Block_MacroBlock(cp, cp); + } + return cp; } /** * This walker copies all walked nodes. * If the walk_condition is true for a node, it is walked. - * All nodes node_info->copy attributes has to be NULL prior to every to every walk. + * All nodes node_info->copy attributes have to be NULL prior to every walk. */ static void copy_walk(ir_node *node, walker_condition *walk_condition, ir_loop *set_loop) { @@ -728,15 +739,10 @@ static void copy_walk(ir_node *node, walker_condition *walk_condition, ir_loop * */ if (get_irn_visited(node) >= get_irg_visited(irg)) { /* Here we rely on nodestate's copy being initialized with NULL */ - DB((dbg, LEVEL_5, "copy_walk: We have already visited %ld\n", get_irn_node_nr(node))); + DB((dbg, LEVEL_5, "copy_walk: We have already visited %N\n", node)); if (node_info->copy == NULL) { -/* if (!is_Const(node) && !is_SymConst(node)) { */ - cp = rawcopy_node(node); -/* } else { - cp = node; - node_info->copy = cp; - }*/ - DB((dbg, LEVEL_5, "The TEMP copy of %ld is created %ld\n", get_irn_node_nr(node), get_irn_node_nr(cp))); + cp = rawcopy_node(node); + DB((dbg, LEVEL_5, "The TEMP copy of %N is created %N\n", node, cp)); } return; } @@ -747,7 +753,7 @@ static void copy_walk(ir_node *node, walker_condition *walk_condition, ir_loop * if (!is_Block(node)) { ir_node *pred = get_nodes_block(node); if (walk_condition(pred)) - DB((dbg, LEVEL_5, "walk block %ld\n", get_irn_node_nr(pred))); + DB((dbg, LEVEL_5, "walk block %N\n", pred)); copy_walk(pred, walk_condition, set_loop); } @@ -755,15 +761,15 @@ static void copy_walk(ir_node *node, walker_condition *walk_condition, ir_loop * NEW_ARR_A(ir_node *, cpin, arity); - for (i = get_irn_arity(node) - 1; i >= 0; --i) { + for (i = 0; i < arity; ++i) { ir_node *pred = get_irn_n(node, i); if (walk_condition(pred)) { - DB((dbg, LEVEL_5, "walk node %ld\n", get_irn_node_nr(pred))); + DB((dbg, LEVEL_5, "walk node %N\n", pred)); copy_walk(pred, walk_condition, set_loop); cpin[i] = get_copy(pred); - DB((dbg, LEVEL_5, "copy of %ld gets new in %ld which is copy of %ld\n", - get_irn_node_nr(node), get_irn_node_nr(get_copy(pred)), get_irn_node_nr(pred))); + DB((dbg, LEVEL_5, "copy of %N gets new in %N which is copy of %N\n", + node, get_copy(pred), pred)); } else { cpin[i] = pred; } @@ -772,38 +778,29 @@ static void copy_walk(ir_node *node, walker_condition *walk_condition, ir_loop * /* copy node / finalize temp node */ if (node_info->copy == NULL) { /* No temporary copy existent */ - - /* Do not copy constants TODO right? */ -/* if (!is_Const(node) && !is_SymConst(node)) { */ - cp = rawcopy_node(node); -/* } else { - cp = node; - node_info->copy = cp; - }*/ - DB((dbg, LEVEL_5, "The FINAL copy of %ld is CREATED %ld\n", get_irn_node_nr(node), get_irn_node_nr(cp))); + cp = rawcopy_node(node); + DB((dbg, LEVEL_5, "The FINAL copy of %N is CREATED %N\n", node, cp)); } else { /* temporary copy is existent but without correct ins */ cp = get_copy(node); - DB((dbg, LEVEL_5, "The FINAL copy of %ld is EXISTENT %ld\n", get_irn_node_nr(node), get_irn_node_nr(cp))); + DB((dbg, LEVEL_5, "The FINAL copy of %N is EXISTENT %N\n", node, cp)); } if (!is_Block(node)) { ir_node *cpblock = get_copy(get_nodes_block(node)); set_nodes_block(cp, cpblock ); - /* fix the phi information in attr.phis */ - if( is_Phi(cp) ) + if (is_Phi(cp)) add_Block_phi(cpblock, cp); - } else { - /* macroblock info has not been copied */ - set_Block_MacroBlock(cp, cp); } set_irn_loop(cp, set_loop); set_irn_in(cp, ARR_LEN(cpin), cpin); } -/* Loop peeling, and fix the cf for the loop entry nodes, which have now more preds */ +/** + * Loop peeling, and fix the cf for the loop entry nodes, which have now more preds + */ static void peel(out_edge *loop_outs) { int i; @@ -817,7 +814,7 @@ static void peel(out_edge *loop_outs) /* duplicate loop walk */ inc_irg_visited(current_ir_graph); - for(i = 0; i < ARR_LEN(loop_outs); i++) { + for (i = 0; i < ARR_LEN(loop_outs); i++) { out_edge entry = loop_outs[i]; ir_node *node = entry.node; ir_node *pred = get_irn_n(entry.node, entry.pred_irn_n); @@ -827,11 +824,14 @@ static void peel(out_edge *loop_outs) duplicate_preds(node, entry.pred_irn_n, get_copy(pred) ); } else { copy_walk(pred, is_in_loop, NULL); - if (!is_End(node)) /* leave out keepalives */ + /* leave out keepalives */ + if (!is_End(node)) { /* Node is user of a value defined inside the loop. * We'll need a phi since we duplicated the loop. */ - /* cannot construct_ssa here, because it needs another walker */ - entry_buffer[entry_c++] = pred; + /* Cannot construct_ssa here, because it needs another walker. */ + entry_buffer[entry_c] = pred; + ++entry_c; + } } } @@ -841,23 +841,20 @@ static void peel(out_edge *loop_outs) peel_fix_heads(); /* Generate phis for values from peeled code and original loop */ - for(i = 0; i < entry_c; i++) + construct_ssa_foreach(entry_buffer, entry_c); + /*for (i = 0; i < entry_c; i++) { ir_node *cppred, *block, *cpblock, *pred; - /* It is not possible to use - * pred = get_irn_n(entry.node, entry.pred_irn_n); - * because we might have changed the nodes predecessors in construct_ssa - */ pred = entry_buffer[i]; cppred = get_copy(pred); block = get_nodes_block(pred); cpblock = get_nodes_block(cppred); construct_ssa(block, pred, cpblock, cppred); - } + }*/ } -/* +/** * Populates head_entries with (node, pred_pos) tuple * whereas the node's pred at pred_pos is in the head but not the node itself. * Head and condition chain blocks must be marked. @@ -868,25 +865,23 @@ static void get_head_outs(ir_node *node, void *env) int arity = get_irn_arity(node); (void) env; - DB((dbg, LEVEL_5, "get head entries %ld \n", get_irn_node_nr(node))); + DB((dbg, LEVEL_5, "get head entries %N \n", node)); - for(i = 0; i < arity; ++i) { + for (i = 0; i < arity; ++i) { /* node is not in the head, but the predecessor is. * (head or loop chain nodes are marked) */ - DB((dbg, LEVEL_5, "... ")); - DB((dbg, LEVEL_5, "node %ld marked %d (0) pred %d marked %d (1) \n", + DB((dbg, LEVEL_5, "node %N marked %d (0) pred %d marked %d (1) \n", node->node_nr, is_nodesblock_marked(node),i, is_nodesblock_marked(get_irn_n(node, i)))); - if (!is_nodesblock_marked(node) && is_nodesblock_marked(get_irn_n(node, i))) { out_edge entry; entry.node = node; entry.pred_irn_n = i; DB((dbg, LEVEL_5, - "Found head chain entry %ld @%d because !inloop %ld and inloop %ld\n", - get_irn_node_nr(node), i, get_irn_node_nr(node), get_irn_node_nr(get_irn_n(node, i)))); + "Found head chain entry %N @%d because !inloop %N and inloop %N\n", + node, i, node, get_irn_n(node, i))); ARR_APP1(out_edge, cur_head_outs, entry); } } @@ -895,28 +890,28 @@ static void get_head_outs(ir_node *node, void *env) /** * Find condition chains, and add them to be inverted, until the node count exceeds the limit. * A block belongs to the chain if a condition branches out of the loop. - * Returns if the given block belongs to the condition chain. - * TODO do not (or do?) invert, if all blocks have loop outs. + * Returns 1 if the given block belongs to the condition chain. */ -static unsigned find_condition_chains(ir_node *block) { +static unsigned find_condition_chains(ir_node *block) +{ const ir_edge_t *edge; unsigned mark = 0; int nodes_n = 0; - DB((dbg, LEVEL_1, "condition_chains for block %ld\n", get_irn_node_nr(block))); + DB((dbg, LEVEL_5, "condition_chains for block %N\n", block)); - /* we need all outs, including keeps (TODO firm function for that??) */ + /* Collect all outs, including keeps. + * (TODO firm function for number of out edges?) */ foreach_out_edge_kind(block, edge, EDGE_KIND_NORMAL) { ++nodes_n; } /* We do not want to collect more nodes from condition chains, than the limit allows us to. * Also, leave at least one block as body. */ - if (head_inversion_node_count + nodes_n > head_inversion_node_limit + if (head_inversion_node_count + nodes_n > inversion_head_node_limit || head_inversion_block_count + 1 == loop_info.blocks) { set_Block_mark(block, 0); - DB((dbg, LEVEL_1, "block %ld over limit or no blocks to invert\n", - get_irn_node_nr(block))); + return 0; } @@ -927,7 +922,6 @@ static unsigned find_condition_chains(ir_node *block) { if (!is_in_loop(src)) { out_edge entry; - /*printf(" src %ld @ %d into block %ld \n", src->node_nr, pos, block->node_nr);*/ mark = 1; entry.node = src; @@ -937,15 +931,16 @@ static unsigned find_condition_chains(ir_node *block) { } } - /* this block is not part of the chain, - * because the chain would become too big or we have no succ outside of the loop */ if (mark == 0) { + /* this block is not part of the chain, + * because the chain would become too long or we have no successor outside of the loop */ + set_Block_mark(block, 0); return 0; } else { set_Block_mark(block, 1); ++head_inversion_block_count; - DB((dbg, LEVEL_1, "block %ld is part of condition chain\n", get_irn_node_nr(block))); + DB((dbg, LEVEL_5, "block %N is part of condition chain\n", block)); head_inversion_node_count += nodes_n; } @@ -961,11 +956,11 @@ static unsigned find_condition_chains(ir_node *block) { } mark_irn_visited(src); - DB((dbg, LEVEL_5, "condition chain walk %ld\n", get_irn_node_nr(src))); - inchain = find_condition_chains( src ); + DB((dbg, LEVEL_5, "condition chain walk %N\n", src)); + inchain = find_condition_chains(src); /* if successor is not part of chain we need to collect its outs */ - if ( !inchain ) { + if (!inchain) { out_edge entry; entry.node = src; entry.pred_irn_n = pos; @@ -976,8 +971,7 @@ static unsigned find_condition_chains(ir_node *block) { } /** - * Loop optimization. - * Loop inversion, peeling, unrolling. + * Rewire the loop head and inverted head for loop inversion. */ static void inversion_fix_heads(void) { @@ -996,6 +990,9 @@ static void inversion_fix_heads(void) int lhead_arity = backedges_n; int ihead_arity = headarity - backedges_n; + assert(lhead_arity != 0 && "Loophead has arity 0. Probably wrong backedge informations."); + assert(ihead_arity != 0 && "Inversionhead has arity 0. Probably wrong backedge informations."); + /* new in arrays for all phis in the head blocks */ NEW_ARR_A(ir_node *, loopheadnins, lhead_arity); NEW_ARR_A(ir_node *, invheadnins, ihead_arity); @@ -1017,14 +1014,12 @@ static void inversion_fix_heads(void) if (is_backedge(loophead, i) && !is_alien_edge(loophead, i)) { /* just copy these edges */ loopheadnins[lheadin_c] = pred; - get_node_info(pred)->link = NULL; /*(void *)is_backedge(loophead, i);*/ for_each_phi(loophead, phi) { get_node_info(phi)->ins[lheadin_c] = get_irn_n(phi, i); } ++lheadin_c; } else { invheadnins[iheadin_c] = pred; - get_node_info(pred)->link = (void *)1; for_each_phi(invhead, phi) { get_node_info(phi)->ins[iheadin_c] = get_irn_n(phi, i) ; } @@ -1036,10 +1031,6 @@ static void inversion_fix_heads(void) set_irn_in(loophead, ARR_LEN(loopheadnins), loopheadnins); set_irn_in(invhead, ARR_LEN(invheadnins), invheadnins); - /* FIX and set former be to normal edges */ - fix_backedge_info(loophead); - fix_backedge_info(invhead); - /* assign the ins for the phis */ for_each_phi(loophead, phi) { ir_node **ins = get_node_info(phi)->ins; @@ -1064,9 +1055,11 @@ static void inversion_walk(out_edge *head_entries) head_phi_assign = NEW_ARR_F(ir_node *, 0); - /* Find assignments in the condition chain, to construct_ssa for them after the loop inversion. */ + /* Find assignments in the condition chain, + * to construct_ssa for them after the loop inversion. */ for_each_phi(loop_cf_head , phi) { - for(i=0; i 0) - do_peel = 1; -#endif - peel(cur_loop_outs); - /* DEBUG_ONLY(dump_ir_block_graph(current_ir_graph, "-peeled1"));*/ - /* clean up */ reset_node_infos(); set_irg_doms_inconsistent(current_ir_graph); - /* TODO needed? */ set_irg_loopinfo_inconsistent(current_ir_graph); - /* TODO Are they really inconsistent (ins set with firm functions)? */ set_irg_outs_inconsistent(current_ir_graph); DEL_ARR_F(cur_loop_outs); } /* Loop inversion */ -void loop_inversion(void) +static void loop_inversion(void) { unsigned do_inversion = 1; - head_inversion_node_limit = 13371337; - -#if 0 - /* unsigned max_loop_opnodes = 2000000; */ - /*unsigned max_opnodes = 1337;*/ - - /* Loop complexity too high */ - if (loop_info.opnodes_n > max_opnodes) - return; -#endif - + inversion_head_node_limit = INT_MAX; /* Search for condition chains. */ ir_reserve_resources(current_ir_graph, IR_RESOURCE_BLOCK_MARK); - /* Did not work as expected */ - /* irg_block_walk_graph(current_ir_graph, reset_block_mark, NULL, NULL); */ - irg_walk_graph(current_ir_graph, reset_block_mark, NULL, NULL); loop_info.blocks = get_loop_n_blocks(cur_loop); @@ -1218,43 +1156,230 @@ void loop_inversion(void) find_condition_chains(loop_cf_head); - /* TODO assume number of phis to be created. prevent inversion in case ...*/ - - DB((dbg, LEVEL_1, "Loop contains %d blocks.\n", loop_info.blocks)); + DB((dbg, LEVEL_3, "Loop contains %d blocks.\n", loop_info.blocks)); if (loop_info.blocks < 2) { do_inversion = 0; - DB((dbg, LEVEL_1, "Loop contains %d (less than 2) blocks => No Inversion done.\n", loop_info.blocks)); + DB((dbg, LEVEL_3, "Loop contains %d (less than 2) blocks => No Inversion done.\n", loop_info.blocks)); } - /* We catch endless loops here too, + /* We also catch endless loops here, * because they do not have a condition chain. */ if (head_inversion_block_count < 1) { do_inversion = 0; - DB((dbg, LEVEL_1, "Loop contains %d (less than 1) invertible blocks => No Inversion done.\n", head_inversion_block_count)); + DB((dbg, LEVEL_3, "Loop contains %d (less than 1) invertible blocks => No Inversion done.\n", head_inversion_block_count)); } if (do_inversion) { cur_head_outs = NEW_ARR_F(out_edge, 0); - /* get all edges pointing into the head or condition chain */ + /* Get all edges pointing into the head or condition chain (outs). */ irg_walk_graph(current_ir_graph, get_head_outs, NULL, NULL); inversion_walk(cur_head_outs); DEL_ARR_F(cur_head_outs); set_irg_doms_inconsistent(current_ir_graph); - /* TODO needed? */ set_irg_loopinfo_inconsistent(current_ir_graph); - /* TODO Are they really inconsistent (ins set with firm functions)? */ set_irg_outs_inconsistent(current_ir_graph); } - /* FREE */ + /* free */ DEL_ARR_F(cond_chain_entries); ir_free_resources(current_ir_graph, IR_RESOURCE_BLOCK_MARK); } -/* */ +/** + * 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 */ static void init_analyze(ir_loop *loop) { /* Init new for every loop */ @@ -1265,39 +1390,36 @@ static void init_analyze(ir_loop *loop) loop_inv_head = NULL; loop_peeled_head = NULL; + loop_info.outs = 0; loop_info.calls = 0; - loop_info.invariant_loads = 0; loop_info.loads = 0; - loop_info.stores = 0; - loop_info.opnodes_n = 0; loop_info.blocks = 0; - loop_info.outs = 0; - DB((dbg, LEVEL_1, " >>>> current loop includes node %ld <<<\n", get_irn_node_nr(get_loop_node(loop, 0)))); + DB((dbg, LEVEL_2, " >>>> current loop includes node %N <<<\n", get_loop_node(loop, 0))); irg_walk_graph(current_ir_graph, get_loop_info, NULL, NULL); /* RETURN if there is no valid head */ if (!loop_cf_head || !loop_cf_head_valid) { - DB((dbg, LEVEL_1, "\n**************************************************\n")); - DB((dbg, LEVEL_1, "* No valid loop head. Nothing done. *\n")); - DB((dbg, LEVEL_1, "**************************************************\n")); + DB((dbg, LEVEL_2, "No valid loop head. Nothing done.\n")); return; } if (enable_peeling) loop_peeling(); + if (enable_inversion) loop_inversion(); + if (enable_unrolling) + loop_unrolling(); - /* TODO uncomment lat0r */ #if 0 /* RETURN if there is a call in the loop */ if (loop_info.calls) return; #endif - DB((dbg, LEVEL_1, " <<<< end of loop with node %ld >>>>\n", get_irn_node_nr(get_loop_node(loop, 0)))); + DB((dbg, LEVEL_2, " <<<< end of loop with node %N >>>>\n", get_loop_node(loop, 0))); } /* Find most inner loops and send them to analyze_loop */ @@ -1306,39 +1428,32 @@ static void find_most_inner_loop(ir_loop *loop) /* descend into sons */ int sons = get_loop_n_sons(loop); - /*DBG((dbg, LEVEL_5, "current loop head %ld is done %d\n", - * get_loop_node(loop, 0)->node_nr, get_node_info(get_loop_node(loop, 0))->done );*/ - if (sons == 0) { loop_element elem; int el_n, i; el_n = get_loop_n_elements(loop); - for (i=0; i < el_n; ++i) - { + for (i=0; i < el_n; ++i) { elem = get_loop_element(loop, i); /* We can only rely on the blocks, * as the loop attribute of the nodes seems not to be set. */ if (is_ir_node(elem.kind) && is_Block(elem.node)) { ARR_APP1(ir_node *, loops, elem.node); - DB((dbg, LEVEL_1, "Found most inner loop (contains block %+F)\n", elem.node)); + DB((dbg, LEVEL_5, "Found most inner loop (contains block %+F)\n", elem.node)); break; } } - /*init_analyze(loop); - return loop;*/ } else { int s; - for(s=0; s>> unrolling (Startnode %N) <<<\n", + get_irg_start(irg))); + + loop_optimization(irg); + + DB((dbg, LEVEL_2, " >>> unrolling done (Startnode %N) <<<\n", + get_irg_start(irg))); +} + void do_loop_inversion(ir_graph *irg) { + enable_unrolling = 0; enable_peeling = 0; enable_inversion = 1; - DB((dbg, LEVEL_1, " >>> inversion (Startnode %ld) <<<\n", - get_irn_node_nr(get_irg_start(irg)))); + DB((dbg, LEVEL_2, " >>> inversion (Startnode %N) <<<\n", + get_irg_start(irg))); loop_optimization(irg); - DB((dbg, LEVEL_1, " >>> inversion done (Startnode %ld) <<<\n", - get_irn_node_nr(get_irg_start(irg)))); + DB((dbg, LEVEL_2, " >>> inversion done (Startnode %N) <<<\n", + get_irg_start(irg))); } void do_loop_peeling(ir_graph *irg) { + enable_unrolling = 0; enable_peeling = 1; enable_inversion = 0; - (void)irg; + DB((dbg, LEVEL_2, " >>> peeling (Startnode %N) <<<\n", + get_irg_start(irg))); - DB((dbg, LEVEL_1, " >>> peeling is disabled atm. <<<\n")); + loop_optimization(irg); - /* - DB((dbg, LEVEL_1, " >>> peeling (Startnode %ld) <<<\n", - get_irn_node_nr(get_irg_start(irg)))); + DB((dbg, LEVEL_2, " >>> peeling done (Startnode %N) <<<\n", + get_irg_start(irg))); - loop_optimization(irg); +} + +ir_graph_pass_t *loop_inversion_pass(const char *name) +{ + return def_graph_pass(name ? name : "loop_inversion", do_loop_inversion); +} - DB((dbg, LEVEL_1, " >>> peeling done (Startnode %ld) <<<\n", - get_irn_node_nr(get_irg_start(irg)))); - */ +ir_graph_pass_t *loop_unroll_pass(const char *name) +{ + return def_graph_pass(name ? name : "loop_unroll", do_loop_unrolling); +} + +ir_graph_pass_t *loop_peeling_pass(const char *name) +{ + return def_graph_pass(name ? name : "loop_peeling", do_loop_peeling); } void firm_init_loop_opt(void)