- add more passes
[libfirm] / ir / opt / opt_osr.c
index c479549..fa32056 100644 (file)
@@ -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;)
@@ -303,19 +304,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");
@@ -644,7 +644,7 @@ static int check_users_for_reg_pressure(ir_node *iv, iv_env *env) {
         *
         * For now our capabilities for doing linear function test
         * are limited, so check if the iv has the right form: Only ONE
-        * phi, only one Add/Sub with a Const
+        * Phi, only one Add/Sub with a Const.
         */
        if (! is_counter_iv(iv, env))
                return 0;
@@ -1058,26 +1058,6 @@ static void assign_po(ir_node *block, void *ctx) {
        e->POnum = env->POnum++;
 }  /* assign_po */
 
-/**
- * Follows the LFTR edges and return the last node in the chain.
- *
- * @param irn  the node that should be followed
- * @param env  the IV environment
- *
- * @note
- * In the current implementation only the last edge is stored, so
- * only one chain exists. That's why we might miss some opportunities.
- */
-static ir_node *followEdges(ir_node *irn, iv_env *env) {
-       for (;;) {
-               LFTR_edge *e = LFTR_find(irn, env);
-               if (e)
-                       irn = e->dst;
-               else
-                       return irn;
-       }
-}  /* followEdges */
-
 /**
  * Apply one LFTR edge operation.
  * Return NULL if the transformation cannot be done safely without
@@ -1097,7 +1077,7 @@ static ir_node *followEdges(ir_node *irn, iv_env *env) {
  */
 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;
 
@@ -1108,6 +1088,11 @@ static ir_node *applyOneEdge(ir_node *iv, ir_node *rc, LFTR_edge *e, iv_env *env
 
                /* overflow can only be decided for Consts */
                if (! is_Const(e->rc)) {
+                       if (e->code == iro_Add && mode_is_reference(get_irn_mode(e->rc))) {
+                               /* However we allow ONE Pointer Add, as pointer arithmetic with wrap
+                                  around is undefined anyway */
+                               return do_apply(e->code, NULL, rc, e->rc, get_irn_mode(e->rc));
+                       }
                        DB((dbg, LEVEL_4, " = UNKNOWN (%+F)", e->rc));
                        return NULL;
                }
@@ -1151,21 +1136,21 @@ 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;
                }
                return new_Const(tv);
        }
-       return do_apply(e->code, NULL, rc, e->rc, get_irn_mode(rc));
+       return do_apply(e->code, NULL, rc, e->rc, get_irn_mode(e->dst));
 }  /* applyOneEdge */
 
 /**
@@ -1174,14 +1159,16 @@ static ir_node *applyOneEdge(ir_node *iv, ir_node *rc, LFTR_edge *e, iv_env *env
  * Return NULL if the transformation cannot be done safely without
  * an Overflow.
  *
- * @param iv   the IV node that starts the LFTR edge chain
+ * @param pIV  points to the IV node that starts the LFTR edge chain
+ *             after translation points to the new IV
  * @param rc   the region constant that should be translated
  * @param env  the IV environment
  *
  * @return the translated region constant or NULL
  *         if the translation was not possible
  */
-static ir_node *applyEdges(ir_node *iv, ir_node *rc, iv_env *env) {
+static ir_node *applyEdges(ir_node **pIV, ir_node *rc, iv_env *env) {
+       ir_node *iv = *pIV;
        if (env->osr_flags & osr_flag_lftr_with_ov_check) {
                /* overflow can only be decided for Consts */
                if (! is_counter_iv(iv, env)) {
@@ -1197,14 +1184,14 @@ static ir_node *applyEdges(ir_node *iv, ir_node *rc, iv_env *env) {
 
        for (; rc;) {
                LFTR_edge *e = LFTR_find(iv, env);
-               if (e) {
+               if (e != NULL) {
                        rc = applyOneEdge(iv, rc, e, env);
                        iv = e->dst;
-               }
-               else
+               } else
                        break;
        }
        DB((dbg, LEVEL_3, "\n"));
+       *pIV = iv;
        return rc;
 }  /* applyEdges */
 
@@ -1229,18 +1216,14 @@ static void do_lftr(ir_node *cmp, void *ctx) {
        if (liv && is_rc(right, liv)) {
                iv = left; rc = right;
 
-               nright = applyEdges(iv, rc, env);
-               if (nright && nright != rc) {
-                       nleft = followEdges(iv, env);
-               }
+               nright = applyEdges(&iv, rc, env);
+               nleft  = iv;
        }
        else if (riv && is_rc(left, riv)) {
                iv = right; rc = left;
 
-               nleft = applyEdges(iv, rc, env);
-               if (nleft && nleft != rc) {
-                       nright = followEdges(iv, env);
-               }
+               nleft  = applyEdges(&iv, rc, env);
+               nright = iv;
        }
 
        if (nleft && nright) {
@@ -1338,10 +1321,17 @@ 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, int verify, int dump)
+{
+       return def_graph_pass(name ? name : "remove_phi_cycles", verify, dump, remove_phi_cycles);
+}  /* remove_phi_cycles_pass */
+
 /**
  * Post-walker: fix Add and Sub nodes that where results of I<->P conversions.
  */
 static void fix_adds_and_subs(ir_node *irn, void *ctx) {
+       (void) ctx;
+
        if (is_Add(irn)) {
                ir_mode *mode = get_irn_mode(irn);
 
@@ -1352,14 +1342,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);
                        }
                }
@@ -1376,13 +1366,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);
                                }
                        }
@@ -1407,7 +1397,6 @@ void opt_osr(ir_graph *irg, unsigned flags) {
        current_ir_graph = irg;
 
        FIRM_DBG_REGISTER(dbg, "firm.opt.osr");
-       firm_dbg_set_mask(dbg, SET_LEVEL_4);
 
        DB((dbg, LEVEL_1, "Doing Operator Strength Reduction for %+F\n", irg));
 
@@ -1447,13 +1436,13 @@ void opt_osr(ir_graph *irg, unsigned flags) {
        do_dfs(irg, &env);
 
        if (env.replaced) {
-               /* try linear function test replacements */
-               //lftr(irg, &env); // currently buggy :-(
-               (void) lftr;
-
                if (env.need_postpass)
                        irg_walk_graph(irg, NULL, fix_adds_and_subs, &env);
 
+               /* try linear function test replacements */
+               lftr(irg, &env);
+               (void)lftr;
+
                set_irg_outs_inconsistent(irg);
                DB((dbg, LEVEL_1, "Replacements: %u + %u (lftr)\n\n", env.replaced, env.lftr_replaced));
        }
@@ -1469,3 +1458,35 @@ 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, int verify, int dump, unsigned flags)
+{
+       struct pass_t *pass = xmalloc(sizeof(*pass));
+
+       pass->pass.kind       = k_ir_prog_pass;
+       pass->pass.run_on_irg = pass_wrapper;
+       pass->pass.context    = pass;
+       pass->pass.name       = name ? name : "osr";
+       pass->pass.verify     = verify != 0;
+       pass->pass.dump       = dump != 0;
+
+       pass->flags = flags;
+
+       INIT_LIST_HEAD(&pass->pass.list);
+
+       return &pass->pass;
+}  /* opt_osr_pass */