# include "irgwalk.h"
# include "reassoc_t.h"
# include "irhooks.h"
+# include "irloop.h"
# include "debug.h"
-static firm_dbg_module_t *dbg;
+DEBUG_ONLY(static firm_dbg_module_t *dbg;)
typedef struct _walker_t {
int changes; /* set, if a reassociation take place */
} const_class_t;
/**
- * returns whether a node is constant, ie is a constant or
+ * returns whether a node is constant ie is a constant or
* is loop invariant
+ *
+ * @param n the node to be checked for constant
+ * @param block a block that might be in a loop
*/
-static const_class_t get_const_class(ir_node *n)
+static const_class_t get_const_class(ir_node *n, ir_node *block)
{
ir_op *op = get_irn_op(n);
if (op == op_SymConst)
return CONST_EXPR;
+ /*
+ * Beware: Bad nodes are always loop-invariant, but
+ * cannot handled in later code, so filter them here
+ */
+ if (! is_Bad(n) && is_loop_invariant(n, block))
+ return CONST_EXPR;
+
return NO_CONSTANT;
}
{
ir_node *op_a = get_binop_left(binop);
ir_node *op_b = get_binop_right(binop);
- int class_a = get_const_class(op_a);
- int class_b = get_const_class(op_b);
+ ir_node *block = get_nodes_block(binop);
+ int class_a = get_const_class(op_a, block);
+ int class_b = get_const_class(op_b, block);
assert(is_op_commutative(get_irn_op(binop)));
*/
static int reassoc_Sub(ir_node **in)
{
- ir_node *n = *in;
+ ir_node *n = *in;
+ ir_node *block = get_nodes_block(n);
ir_node *right = get_Sub_right(n);
/* FIXME: Do not apply this rule for unsigned Sub's because our code
* As there is NO real Minus in Firm it makes no sense to do this
* for non-real constants yet.
* */
- if (get_const_class(right) == REAL_CONSTANT) {
+ if (get_const_class(right, block) == REAL_CONSTANT) {
ir_node *left = get_Sub_left(n);
ir_node *block = get_nodes_block(n);
ir_mode *mode = get_irn_mode(n);
dbg_info *dbi = get_irn_dbg_info(n);
ir_node *irn, *c;
- switch (get_const_class(left)) {
+ switch (get_const_class(left, block)) {
case REAL_CONSTANT:
irn = optimize_in_place(n);
if (irn != n) {
return 0;
}
-/** Retrieve a mode form the operands. We need this, because
+/** Retrieve a mode from the operands. We need this, because
* Add and Sub are allowed to operate on (P, Is)
*/
static ir_mode *get_mode_from_ops(ir_node *op1, ir_node *op2)
* reassociate a commutative Binop
*
* BEWARE: this rule leads to a potential loop, if
- * all two operands are are constant expressions and the third is a
+ * two operands are are constant expressions and the third is a
* constant, so avoid this situation.
*/
static int reassoc_commutative(ir_node **node)
{
- ir_node *n = *node;
+ ir_node *n = *node;
ir_op *op = get_irn_op(n);
ir_node *block = get_nodes_block(n);
ir_node *t1, *c1;
if (is_Bad(t2))
return 0;
- c_c1 = get_const_class(c1);
- c_c2 = get_const_class(c2);
- c_t2 = get_const_class(t2);
+ c_c1 = get_const_class(c1, block);
+ c_c2 = get_const_class(c2, block);
+ c_t2 = get_const_class(t2, block);
if ( ((c_c1 > NO_CONSTANT) & (c_t2 > NO_CONSTANT)) &&
((((c_c1 ^ c_c2 ^ c_t2) & CONST_EXPR) == 0) || ((c_c1 & c_c2 & c_t2) == CONST_EXPR)) ) {
- /* all three are constant and either all are constant expressions or two of them are:
- * then, applying this rule would lead into a cycle
+ /* All three are constant and either all are constant expressions or two of them are:
+ * then applying this rule would lead into a cycle
*
- * Note that if t2 is a constant so is c2, so we save one test.
+ * Note that if t2 is a constant so is c2 hence we save one test.
*/
return 0;
}
c1, get_irn_opname(n), c2, get_irn_opname(n),
t2, c1, get_irn_opname(n), c2, get_irn_opname(n), t2));
/*
- * in some rare cases it can really happen that we get the same node back.
+ * In some rare cases it can really happen that we get the same node back.
* This might be happen in dead loops, were the Phi nodes are already gone away.
* So check this.
- */
+ */
if (n != irn) {
exchange(n, irn);
*node = irn;
*/
static int reassoc_Mul(ir_node **node)
{
- ir_node *n = *node;
+ ir_node *n = *node;
ir_node *add_sub, *c;
ir_op *op;
t1 = get_binop_left(add_sub);
t2 = get_binop_right(add_sub);
- in[0] = new_rd_Mul(NULL, current_ir_graph, block, c, t1, mode);
- in[1] = new_rd_Mul(NULL, current_ir_graph, block, c, t2, mode);
+ /* we can only multiplication rules on integer arithmetic */
+ if (mode_is_int(get_irn_mode(t1)) && mode_is_int(get_irn_mode(t2))) {
+ in[0] = new_rd_Mul(NULL, current_ir_graph, block, c, t1, mode);
+ in[1] = new_rd_Mul(NULL, current_ir_graph, block, c, t2, mode);
- mode = get_mode_from_ops(in[0], in[1]);
- irn = optimize_node(new_ir_node(NULL, current_ir_graph, block, op, mode, 2, in));
+ mode = get_mode_from_ops(in[0], in[1]);
+ irn = optimize_node(new_ir_node(NULL, current_ir_graph, block, op, mode, 2, in));
- DBG((dbg, LEVEL_5, "Applied: (%n .%s. %n) %n %n => (%n %n %n) .%s. (%n %n %n)\n",
- t1, get_op_name(op), t2, n, c, t1, n, c, get_op_name(op), t2, n, c));
- exchange(n, irn);
- *node = irn;
+ /* In some cases it might happen that the new irn is equal the old one, for
+ * instance in:
+ * (x - 1) * y == x * y - y
+ * will be transformed back by simpler optimization
+ * We could switch simple optimizations off, but this only happens iff y
+ * is a loop-invariant expreassion and that it is not clear if the new form
+ * is better.
+ * So, we let the old one.
+ */
+ if (irn != n) {
+ DBG((dbg, LEVEL_5, "Applied: (%n .%s. %n) %n %n => (%n %n %n) .%s. (%n %n %n)\n",
+ t1, get_op_name(op), t2, n, c, t1, n, c, get_op_name(op), t2, n, c));
+ exchange(n, irn);
+ *node = irn;
- return 1;
+ return 1;
+ }
+ }
}
return 0;
}
/**
- * The walker for the reassociation
+ * The walker for the reassociation.
*/
static void do_reassociation(ir_node *n, void *env)
{
hook_reassociate(1);
- /* reassociation must run until fixpoint */
+ /* reassociation must run until a fixpoint is reached. */
do {
ir_op *op = get_irn_op(n);
ir_mode *mode = get_irn_mode(n);
res = 0;
/* reassociation works only for integer or reference modes */
- if (op->reassociate && (mode_is_int(mode) || mode_is_reference(mode))) {
- res = op->reassociate(&n);
+ if (op->ops.reassociate && (mode_is_int(mode) || mode_is_reference(mode))) {
+ res = op->ops.reassociate(&n);
+
+ wenv->changes |= res;
}
} while (res == 1);
void optimize_reassociation(ir_graph *irg)
{
walker_t env;
+ irg_loopinfo_state state;
assert(get_irg_phase_state(irg) != phase_building);
+ assert(get_irg_pinned(irg) != op_pin_state_floats &&
+ "Reassociation needs pinned graph to work properly");
/* reassociation needs constant folding */
if (!get_opt_reassociation() || !get_opt_constant_folding())
return;
- env.changes = 0;
+ /*
+ * Calculate loop info, so we could identify loop-invariant
+ * code and threat it like a constant.
+ * We only need control flow loops here but can handle generic
+ * INTRA info as well.
+ */
+ state = get_irg_loopinfo_state(irg);
+ if ((state & loopinfo_inter) ||
+ (state & (loopinfo_constructed | loopinfo_valid)) != (loopinfo_constructed | loopinfo_valid))
+ construct_cf_backedges(irg);
- irg_walk_graph(irg, NULL, do_reassociation, &env);
+ env.changes = 0;
/* now we have collected enough information, optimize */
irg_walk_graph(irg, NULL, do_reassociation, &env);
/* Handle graph state */
if (env.changes) {
- if (get_irg_outs_state(current_ir_graph) == outs_consistent)
- set_irg_outs_inconsistent(current_ir_graph);
+ if (get_irg_outs_state(irg) == outs_consistent)
+ set_irg_outs_inconsistent(irg);
+ set_irg_loopinfo_inconsistent(irg);
+ }
+}
+
+/* Sets the default reassociation operation for an ir_op_ops. */
+ir_op_ops *firm_set_default_reassoc(opcode code, ir_op_ops *ops)
+{
+#define CASE(a) case iro_##a: ops->reassociate = reassoc_##a; break
+
+ switch (code) {
+ CASE(Mul);
+ CASE(Add);
+ CASE(Sub);
+ CASE(And);
+ CASE(Or);
+ CASE(Eor);
+ default:
+ /* leave NULL */;
}
+
+ return ops;
+#undef CASE
}
/* initialize the reassociation by adding operations to some opcodes */
void firm_init_reassociation(void)
{
-#define INIT(a) op_##a->reassociate = reassoc_##a;
- INIT(Mul);
- INIT(Add);
- INIT(Sub);
- INIT(And);
- INIT(Or);
- INIT(Eor);
-#undef INIT
-
- dbg = firm_dbg_register("firm.opt.reassoc");
- firm_dbg_set_mask(dbg, -1);
+ FIRM_DBG_REGISTER(dbg, "firm.opt.reassoc");
}