#include "array.h"
#include "firmstat.h"
#include "error.h"
+#include "irpass_t.h"
/** The debug handle. */
DEBUG_ONLY(static firm_dbg_module_t *dbg;)
* @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");
*
* 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;
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
*/
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;
/* 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;
}
}
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 */
/**
* 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)) {
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 */
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) {
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);
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);
}
}
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);
}
}
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));
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));
}
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 */