/* optimize symmetric unop */
if (get_irn_op(pred) == get_irn_op(n)) {
n = get_unop_op(pred);
- DBG_OPT_ALGSIM2(oldn, pred, n);
+ DBG_OPT_ALGSIM2(oldn, pred, n, FS_OPT_IDEM_UNARY);
}
return n;
} /* equivalent_node_idempotent_unop */
/** Optimize Not(Not(x)) == x. */
#define equivalent_node_Not equivalent_node_idempotent_unop
-/** --x == x ??? Is this possible or can --x raise an
+/** -(-x) == x ??? Is this possible or can --x raise an
out of bounds exception if min =! max? */
#define equivalent_node_Minus equivalent_node_idempotent_unop
ir_mode *a_mode = get_irn_mode(a);
if (n_mode == a_mode) { /* No Conv necessary */
- /* leave strict floating point Conv's */
- if (get_Conv_strict(n))
- return n;
+ if (get_Conv_strict(n)) {
+ /* special case: the predecessor might be a also a Conv */
+ if (is_Conv(a)) {
+ if (! get_Conv_strict(a)) {
+ /* first one is not strict, kick it */
+ set_Conv_op(n, get_Conv_op(a));
+ return n;
+ }
+ /* else both are strict conv, second is superflous */
+ } else {
+ /* leave strict floating point Conv's */
+ return n;
+ }
+ }
n = a;
DBG_OPT_ALGSIM0(oldn, n, FS_OPT_CONV);
} else if (get_irn_op(a) == op_Conv) { /* Conv(Conv(b)) */
if (n_mode == mode_b) {
n = b; /* Convb(Conv*(xxxb(...))) == xxxb(...) */
DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_CONV);
- } else if (mode_is_int(n_mode) || mode_is_character(n_mode)) {
+ } else if (mode_is_int(n_mode)) {
if (smaller_mode(b_mode, a_mode)){
n = b; /* ConvS(ConvL(xxxS(...))) == xxxS(...) */
DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_CONV);
/*
* One could expect that we simply return the previous
* Bound here. However, this would be wrong, as we could
- * add an exception Proj to a new location than.
- * So, we must turn in into a tuple
+ * add an exception Proj to a new location then.
+ * So, we must turn in into a tuple.
*/
ret_tuple = 1;
}
DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_MUL_A_X_A);
}
}
+ /* Here we rely on constants be on the RIGHT side */
+ else if (is_Not(a) && classify_Const(b) == CNST_ONE) {
+ /* ~x + 1 = -x */
+ ir_node *op = get_Not_op(a);
+ ir_node *blk = get_irn_n(n, -1);
+ n = new_rd_Minus(get_irn_dbg_info(n), current_ir_graph, blk, op, mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_NOT_PLUS_1);
+ }
}
return n;
} /* transform_node_Add */
return n;
} /* transform_node_Cond */
+typedef ir_node* (*recursive_transform) (ir_node *n);
+
+/**
+ * makes use of distributive laws for and, or, eor
+ * and(a OP c, b OP c) -> and(a, b) OP c
+ */
+static ir_node *transform_bitwise_distributive(ir_node *n,
+ recursive_transform trans_func)
+{
+ ir_node *oldn = n;
+ ir_node *a = get_binop_left(n);
+ ir_node *b = get_binop_right(n);
+ ir_op *op = get_irn_op(a);
+ ir_op *op_root = get_irn_op(n);
+
+ if(op != get_irn_op(b))
+ return n;
+
+ if (op == op_Conv) {
+ ir_node *a_op = get_Conv_op(a);
+ ir_node *b_op = get_Conv_op(b);
+ ir_mode *a_mode = get_irn_mode(a_op);
+ ir_mode *b_mode = get_irn_mode(b_op);
+ if(a_mode == b_mode && (mode_is_int(a_mode) || a_mode == mode_b)) {
+ ir_node *blk = get_irn_n(n, -1);
+
+ n = exact_copy(n);
+ set_binop_left(n, a_op);
+ set_binop_right(n, b_op);
+ set_irn_mode(n, a_mode);
+ n = trans_func(n);
+ n = new_r_Conv(current_ir_graph, blk, n, get_irn_mode(oldn));
+
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_SHIFT_AND);
+ return n;
+ }
+ }
+
+ if (op == op_Eor) {
+ /* nothing to gain here */
+ return n;
+ }
+
+ if (op == op_Shrs || op == op_Shr || op == op_Shl
+ || op == op_And || op == op_Or || op == op_Eor) {
+ ir_node *a_left = get_binop_left(a);
+ ir_node *a_right = get_binop_right(a);
+ ir_node *b_left = get_binop_left(b);
+ ir_node *b_right = get_binop_right(b);
+ ir_node *c = NULL;
+ ir_node *op1, *op2;
+
+ if (is_op_commutative(op)) {
+ if (a_left == b_left) {
+ c = a_left;
+ op1 = a_right;
+ op2 = b_right;
+ } else if(a_left == b_right) {
+ c = a_left;
+ op1 = a_right;
+ op2 = b_left;
+ } else if(a_right == b_left) {
+ c = a_right;
+ op1 = a_left;
+ op2 = b_right;
+ }
+ }
+ if(a_right == b_right) {
+ c = a_right;
+ op1 = a_left;
+ op2 = b_left;
+ }
+
+ if (c != NULL) {
+ /* (a sop c) & (b sop c) => (a & b) sop c */
+ ir_node *blk = get_irn_n(n, -1);
+
+ ir_node *new_n = exact_copy(n);
+ set_binop_left(new_n, op1);
+ set_binop_right(new_n, op2);
+ new_n = trans_func(new_n);
+
+ if(op_root == op_Eor && op == op_Or) {
+ dbg_info *dbgi = get_irn_dbg_info(n);
+ ir_graph *irg = current_ir_graph;
+ ir_mode *mode = get_irn_mode(c);
+
+ c = new_rd_Not(dbgi, irg, blk, c, mode);
+ n = new_rd_And(dbgi, irg, blk, new_n, c, mode);
+ } else {
+ n = exact_copy(a);
+ set_irn_n(n, -1, blk);
+ set_binop_left(n, new_n);
+ set_binop_right(n, c);
+ }
+
+
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_SHIFT_AND);
+ return n;
+ }
+ }
+
+ return n;
+}
+
/**
* Transform an And.
*/
static ir_node *transform_node_And(ir_node *n) {
- ir_node *c, *oldn = n;
+ ir_node *c, *oldn;
ir_node *a = get_And_left(n);
ir_node *b = get_And_right(n);
HANDLE_BINOP_PHI(tarval_and, a,b,c);
+
+ n = transform_bitwise_distributive(n, transform_node_And);
+
return n;
} /* transform_node_And */
n = new_r_Not(current_ir_graph, get_irn_n(n, -1), a, mode_b);
DBG_OPT_ALGSIM0(oldn, n, FS_OPT_EOR_TO_NOT);
+ } else {
+ n = transform_bitwise_distributive(n, transform_node_Eor);
}
return n;
static ir_node *transform_node_Not(ir_node *n) {
ir_node *c, *oldn = n;
ir_node *a = get_Not_op(n);
+ ir_op *op_a = get_irn_op(a);
HANDLE_UNOP_PHI(tarval_not,a,c);
/* check for a boolean Not */
if ( (get_irn_mode(n) == mode_b)
- && (get_irn_op(a) == op_Proj)
+ && (op_a == op_Proj)
&& (get_irn_mode(a) == mode_b)
&& (get_irn_op(get_Proj_pred(a)) == op_Cmp)) {
/* We negate a Cmp. The Cmp has the negated result anyways! */
n = new_r_Proj(current_ir_graph, get_irn_n(n, -1), get_Proj_pred(a),
mode_b, get_negated_pnc(get_Proj_proj(a), mode_b));
DBG_OPT_ALGSIM0(oldn, n, FS_OPT_NOT_CMP);
+ return n;
+ }
+ if (op_a == op_Sub && classify_Const(get_Sub_right(a)) == CNST_ONE) {
+ /* ~(x-1) = -x */
+ ir_node *op = get_Sub_left(a);
+ ir_node *blk = get_irn_n(n, -1);
+ n = new_rd_Minus(get_irn_dbg_info(n), current_ir_graph, blk, op, get_irn_mode(n));
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_NOT_MINUS_1);
}
return n;
} /* transform_node_Not */
/**
* Transform a Minus.
+ * Optimize:
+ * -(~x) = x + 1
*/
static ir_node *transform_node_Minus(ir_node *n) {
ir_node *c, *oldn = n;
ir_node *a = get_Minus_op(n);
HANDLE_UNOP_PHI(tarval_neg,a,c);
+
+ if (is_Not(a)) {
+ /* -(~x) = x + 1 */
+ ir_node *op = get_Not_op(a);
+ ir_mode *mode = get_irn_mode(op);
+ tarval *tv = get_mode_one(mode);
+ ir_node *blk = get_irn_n(n, -1);
+ ir_node *c = new_r_Const(current_ir_graph, blk, mode, tv);
+ n = new_rd_Add(get_irn_dbg_info(n), current_ir_graph, blk, op, c, mode);
+ DBG_OPT_ALGSIM2(oldn, a, n, FS_OPT_MINUS_NOT);
+ }
+
return n;
} /* transform_node_Minus */
(!mode_overflow_on_unary_Minus(mode) ||
(mode_is_int(mode) && (proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg)))) {
left = get_Minus_op(left);
- tv = tarval_sub(get_mode_null(mode), tv);
+ tv = tarval_neg(tv);
- proj_nr = get_inversed_pnc(proj_nr);
- changed |= 2;
+ if (tv != tarval_bad) {
+ proj_nr = get_inversed_pnc(proj_nr);
+ changed |= 2;
+ }
}
/* for integer modes, we have more */
tarval_cmp(tv, get_mode_null(mode)) == pn_Cmp_Gt) {
tv = tarval_sub(tv, get_mode_one(mode));
- proj_nr ^= pn_Cmp_Eq;
- changed |= 2;
+ if (tv != tarval_bad) {
+ proj_nr ^= pn_Cmp_Eq;
+ changed |= 2;
+ }
}
/* c < 0 : a > c ==> a >= (c+1) a <= c ==> a < (c+1) */
else if ((proj_nr == pn_Cmp_Gt || proj_nr == pn_Cmp_Le) &&
tarval_cmp(tv, get_mode_null(mode)) == pn_Cmp_Lt) {
tv = tarval_add(tv, get_mode_one(mode));
- proj_nr ^= pn_Cmp_Eq;
- changed |= 2;
+ if (tv != tarval_bad) {
+ proj_nr ^= pn_Cmp_Eq;
+ changed |= 2;
+ }
}
/* the following reassociations work only for == and != */
left = get_Sub_left(left);
tv = value_of(right);
- changed = 1;
+ if (tv != tarval_bad) {
+ changed = 1;
+ }
}
if (tv != tarval_bad) {
*/
if ((proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg) &&
(get_irn_op(left) == op_And)) {
- if (is_single_bit_tarval(tv)) {
+ if (tarval_is_single_bit(tv)) {
/* check for Constant's match. We have check hare the tarvals,
because our const might be changed */
ir_node *la = get_And_left(left);
n = transform_node_Or_bf_store(n);
n = transform_node_Or_Rot(n);
+ if (n != oldn)
+ return n;
+
+ n = transform_bitwise_distributive(n, transform_node_Or);
return n;
} /* transform_node_Or */
ir_node *oldn = n, *sel = get_Mux_sel(n);
ir_mode *mode = get_irn_mode(n);
+ if (mode == mode_b) {
+ ir_node *t = get_Mux_true(n);
+ ir_node *f = get_Mux_false(n);
+ dbg_info *dbg = get_irn_dbg_info(n);
+ ir_node *block = get_irn_n(n, -1);
+ ir_graph *irg = current_ir_graph;
+
+ if (is_Const(t)) {
+ tarval *tv_t = get_Const_tarval(t);
+ if (tv_t == tarval_b_true) {
+ if (is_Const(f)) {
+ assert(get_Const_tarval(f) == tarval_b_false);
+ return sel;
+ } else {
+ return new_rd_Or(dbg, irg, block, sel, f, mode_b);
+ }
+ } else {
+ ir_node* not_sel = new_rd_Not(dbg, irg, block, sel, mode_b);
+ assert(tv_t == tarval_b_false);
+ if (is_Const(f)) {
+ assert(get_Const_tarval(f) == tarval_b_true);
+ return not_sel;
+ } else {
+ return new_rd_And(dbg, irg, block, not_sel, f, mode_b);
+ }
+ }
+ } else if (is_Const(f)) {
+ tarval *tv_f = get_Const_tarval(f);
+ if (tv_f == tarval_b_true) {
+ ir_node* not_sel = new_rd_Not(dbg, irg, block, sel, mode_b);
+ return new_rd_Or(dbg, irg, block, not_sel, t, mode_b);
+ } else {
+ assert(tv_f == tarval_b_false);
+ return new_rd_And(dbg, irg, block, sel, t, mode_b);
+ }
+ }
+ }
+
if (get_irn_op(sel) == op_Proj && !mode_honor_signed_zeros(mode)) {
ir_node *cmp = get_Proj_pred(sel);
long proj_nr = get_Proj_proj(sel);
* not be freed even if the equivalent node isn't the old one.
*/
static ir_node *transform_node(ir_node *n) {
- if (n->op->ops.transform_node)
- n = n->op->ops.transform_node(n);
+ ir_node *oldn;
+
+ /*
+ * Transform_node is the only "optimizing transformation" that might
+ * return a node with a different opcode. We iterate HERE until fixpoint
+ * to get the final result.
+ */
+ do {
+ oldn = n;
+ if (n->op->ops.transform_node)
+ n = n->op->ops.transform_node(n);
+ } while (oldn != n);
+
return n;
} /* transform_node */
/** Compares the attributes of two Proj nodes. */
static int node_cmp_attr_Proj(ir_node *a, ir_node *b) {
- return get_irn_proj_attr (a) != get_irn_proj_attr (b);
+ return get_irn_proj_attr(a) != get_irn_proj_attr(b);
} /* node_cmp_attr_Proj */
/** Compares the attributes of two Filter nodes. */
/** Compares the attributes of two Alloc nodes. */
static int node_cmp_attr_Alloc(ir_node *a, ir_node *b) {
- return (get_irn_alloc_attr(a).where != get_irn_alloc_attr(b).where)
- || (get_irn_alloc_attr(a).type != get_irn_alloc_attr(b).type);
+ const alloc_attr *pa = get_irn_alloc_attr(a);
+ const alloc_attr *pb = get_irn_alloc_attr(b);
+ return (pa->where != pb->where) || (pa->type != pb->type);
} /* node_cmp_attr_Alloc */
/** Compares the attributes of two Free nodes. */
static int node_cmp_attr_Free(ir_node *a, ir_node *b) {
- return (get_irn_free_attr(a).where != get_irn_free_attr(b).where)
- || (get_irn_free_attr(a).type != get_irn_free_attr(b).type);
+ const free_attr *pa = get_irn_free_attr(a);
+ const free_attr *pb = get_irn_free_attr(b);
+ return (pa->where != pb->where) || (pa->type != pb->type);
} /* node_cmp_attr_Free */
/** Compares the attributes of two SymConst nodes. */
static int node_cmp_attr_SymConst(ir_node *a, ir_node *b) {
- return (get_irn_symconst_attr(a).num != get_irn_symconst_attr(b).num)
- || (get_irn_symconst_attr(a).sym.type_p != get_irn_symconst_attr(b).sym.type_p)
- || (get_irn_symconst_attr(a).tp != get_irn_symconst_attr(b).tp);
+ const symconst_attr *pa = get_irn_symconst_attr(a);
+ const symconst_attr *pb = get_irn_symconst_attr(b);
+ return (pa->num != pb->num)
+ || (pa->sym.type_p != pb->sym.type_p)
+ || (pa->tp != pb->tp);
} /* node_cmp_attr_SymConst */
/** Compares the attributes of two Call nodes. */
/** Compares the attributes of two Sel nodes. */
static int node_cmp_attr_Sel(ir_node *a, ir_node *b) {
- return (get_irn_sel_attr(a).ent->kind != get_irn_sel_attr(b).ent->kind)
- || (get_irn_sel_attr(a).ent->name != get_irn_sel_attr(b).ent->name)
- || (get_irn_sel_attr(a).ent->owner != get_irn_sel_attr(b).ent->owner)
- || (get_irn_sel_attr(a).ent->ld_name != get_irn_sel_attr(b).ent->ld_name)
- || (get_irn_sel_attr(a).ent->type != get_irn_sel_attr(b).ent->type);
+ const ir_entity *a_ent = get_Sel_entity(a);
+ const ir_entity *b_ent = get_Sel_entity(b);
+ return
+ (a_ent->kind != b_ent->kind) ||
+ (a_ent->name != b_ent->name) ||
+ (a_ent->owner != b_ent->owner) ||
+ (a_ent->ld_name != b_ent->ld_name) ||
+ (a_ent->type != b_ent->type);
} /* node_cmp_attr_Sel */
/** Compares the attributes of two Phi nodes. */