Add a rule to transform x .op. (x .op. y) into y .op. (x .op. x) for commutative...
[libfirm] / ir / opt / opt_osr.c
index a7701cd..79cd9a3 100644 (file)
@@ -23,7 +23,7 @@
  * @date    12.5.2006
  * @author  Michael Beck
  * @version $Id$
- * @summary
+ * @brief
  *  Implementation of the Operator Strength Reduction algorithm
  *  by Keith D. Cooper, L. Taylor Simpson, Christopher A. Vick.
  *  Extended version.
@@ -51,6 +51,7 @@
 #include "array.h"
 #include "firmstat.h"
 #include "error.h"
+#include "irpass_t.h"
 
 /** The debug handle. */
 DEBUG_ONLY(static firm_dbg_module_t *dbg;)
@@ -174,8 +175,7 @@ static node_entry *get_irn_ne(ir_node *irn, iv_env *env) {
        node_entry *e = get_irn_link(irn);
 
        if (e == NULL) {
-               e = obstack_alloc(&env->obst, sizeof(*e));
-               memset(e, 0, sizeof(*e));
+               e = OALLOCZ(&env->obst, node_entry);
                set_irn_link(irn, e);
        }
        return e;
@@ -303,19 +303,18 @@ static ir_node *find_location(ir_node *block1, ir_node *block2) {
  * @return the newly created node
  */
 static ir_node *do_apply(ir_opcode code, dbg_info *db, ir_node *op1, ir_node *op2, ir_mode *mode) {
-       ir_graph *irg = current_ir_graph;
        ir_node *result;
        ir_node *block = find_location(get_nodes_block(op1), get_nodes_block(op2));
 
        switch (code) {
        case iro_Mul:
-               result = new_rd_Mul(db, irg, block, op1, op2, mode);
+               result = new_rd_Mul(db, block, op1, op2, mode);
                break;
        case iro_Add:
-               result = new_rd_Add(db, irg, block, op1, op2, mode);
+               result = new_rd_Add(db, block, op1, op2, mode);
                break;
        case iro_Sub:
-               result = new_rd_Sub(db, irg, block, op1, op2, mode);
+               result = new_rd_Sub(db, block, op1, op2, mode);
                break;
        default:
                panic("Unsupported opcode");
@@ -480,8 +479,7 @@ static int replace(ir_node *irn, ir_node *iv, ir_node *rc, iv_env *env) {
                exchange(irn, result);
                e = get_irn_ne(result, env);
                if (e->pscc == NULL) {
-                       e->pscc = obstack_alloc(&env->obst, sizeof(*e->pscc));
-                       memset(e->pscc, 0, sizeof(*e->pscc));
+                       e->pscc = OALLOCZ(&env->obst, scc);
                        update_scc(result, e, env);
                }
                ++env->replaced;
@@ -997,10 +995,9 @@ static void dfs(ir_node *irn, iv_env *env) {
                                node->low = MIN(o->DFSnum, node->low);
                }
                if (node->low == node->DFSnum) {
-                       scc *pscc = obstack_alloc(&env->obst, sizeof(*pscc));
+                       scc *pscc = OALLOCZ(&env->obst, scc);
                        ir_node *x;
 
-                       memset(pscc, 0, sizeof(*pscc));
                        do {
                                node_entry *e;
 
@@ -1077,7 +1074,7 @@ static void assign_po(ir_node *block, void *ctx) {
  */
 static ir_node *applyOneEdge(ir_node *iv, ir_node *rc, LFTR_edge *e, iv_env *env) {
        if (env->osr_flags & osr_flag_lftr_with_ov_check) {
-               tarval *tv_l, *tv_r, *tv, *tv_init, *tv_incr;
+               tarval *tv_l, *tv_r, *tv, *tv_init, *tv_incr, *tv_end;
                tarval_int_overflow_mode_t ovmode;
                scc *pscc;
 
@@ -1136,15 +1133,15 @@ static ir_node *applyOneEdge(ir_node *iv, ir_node *rc, LFTR_edge *e, iv_env *env
                }
 
                if (pscc->code == iro_Add) {
-                       tv = tarval_add(tv, tv_incr);
+                       tv_end = tarval_add(tv, tv_incr);
                } else {
                        assert(pscc->code == iro_Sub);
-                       tv = tarval_sub(tv, tv_incr, NULL);
+                       tv_end = tarval_sub(tv, tv_incr, NULL);
                }
 
                tarval_set_integer_overflow_mode(ovmode);
 
-               if (tv == tarval_bad || tv_init == tarval_bad) {
+               if (tv == tarval_bad || tv_init == tarval_bad || tv_end == tarval_bad) {
                        DB((dbg, LEVEL_4, " = OVERFLOW"));
                        return NULL;
                }
@@ -1291,8 +1288,8 @@ void remove_phi_cycles(ir_graph *irg) {
        env.process_scc   = process_phi_only_scc;
 
        /* Clear all links and move Proj nodes into the
-          the same block as it's predecessors.
-          This can improve the placement of new nodes.
+        * the same block as their predecessors.
+        * This can improve the placement of new nodes.
         */
        projs_moved = 0;
        irg_walk_graph(irg, NULL, clear_and_fix, &projs_moved);
@@ -1321,6 +1318,11 @@ void remove_phi_cycles(ir_graph *irg) {
        current_ir_graph = rem;
 }  /* remove_phi_cycles */
 
+ir_graph_pass_t *remove_phi_cycles_pass(const char *name)
+{
+       return def_graph_pass(name ? name : "remove_phi_cycles", remove_phi_cycles);
+}  /* remove_phi_cycles_pass */
+
 /**
  * Post-walker: fix Add and Sub nodes that where results of I<->P conversions.
  */
@@ -1337,14 +1339,14 @@ static void fix_adds_and_subs(ir_node *irn, void *ctx) {
                        if (get_irn_mode(pred) != mode) {
                                ir_node *block = get_nodes_block(pred);
 
-                               pred = new_r_Conv(current_ir_graph, block, pred, mode);
+                               pred = new_r_Conv(block, pred, mode);
                                set_Add_left(irn, pred);
                        }
                        pred = get_Add_right(irn);
                        if (get_irn_mode(pred) != mode) {
                                ir_node *block = get_nodes_block(pred);
 
-                               pred = new_r_Conv(current_ir_graph, block, pred, mode);
+                               pred = new_r_Conv(block, pred, mode);
                                set_Add_right(irn, pred);
                        }
                }
@@ -1361,13 +1363,13 @@ static void fix_adds_and_subs(ir_node *irn, void *ctx) {
                                if (l_mode != mode) {
                                        ir_node *block = get_nodes_block(left);
 
-                                       left = new_r_Conv(current_ir_graph, block, left, mode);
+                                       left = new_r_Conv(block, left, mode);
                                        set_Sub_left(irn, left);
                                }
                                if (r_mode != mode) {
                                        ir_node *block = get_nodes_block(right);
 
-                                       right = new_r_Conv(current_ir_graph, block, right, mode);
+                                       right = new_r_Conv(block, right, mode);
                                        set_Sub_right(irn, right);
                                }
                        }
@@ -1382,12 +1384,6 @@ void opt_osr(ir_graph *irg, unsigned flags) {
        int      edges;
        int      projs_moved;
 
-       if (! get_opt_strength_red()) {
-               /* only kill Phi cycles  */
-               remove_phi_cycles(irg);
-               return;
-       }
-
        rem = current_ir_graph;
        current_ir_graph = irg;
 
@@ -1435,7 +1431,7 @@ void opt_osr(ir_graph *irg, unsigned flags) {
                        irg_walk_graph(irg, NULL, fix_adds_and_subs, &env);
 
                /* try linear function test replacements */
-               //lftr(irg, &env); // currently buggy :-(
+               lftr(irg, &env);
                (void)lftr;
 
                set_irg_outs_inconsistent(irg);
@@ -1453,3 +1449,26 @@ void opt_osr(ir_graph *irg, unsigned flags) {
 
        current_ir_graph = rem;
 }  /* opt_osr */
+
+struct pass_t {
+       ir_graph_pass_t pass;
+       unsigned        flags;
+};
+
+/**
+* Wrapper for running opt_osr() as an ir_graph pass.
+*/
+static int pass_wrapper(ir_graph *irg, void *context) {
+       struct pass_t *pass = context;
+       opt_osr(irg, pass->flags);
+       return 0;
+}  /* pass_wrapper */
+
+ir_graph_pass_t *opt_osr_pass(const char *name, unsigned flags)
+{
+       struct pass_t *pass = XMALLOCZ(struct pass_t);
+
+       pass->flags = flags;
+       return def_graph_pass_constructor(
+               &pass->pass, name ? name : "osr", pass_wrapper);
+}  /* opt_osr_pass */