+ HANDLE_BINOP_PHI(tarval_mul, a, b, c, mode);
+
+ if (mode_is_signed(mode)) {
+ ir_node *r = NULL;
+
+ if (value_of(a) == get_mode_minus_one(mode))
+ r = b;
+ else if (value_of(b) == get_mode_minus_one(mode))
+ r = a;
+ if (r) {
+ n = new_rd_Minus(get_irn_dbg_info(n), current_ir_graph, get_irn_n(n, -1), r, mode);
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_MUL_MINUS_1);
+ return n;
+ }
+ }
+ if (is_Minus(a)) {
+ if (is_Const(b)) { /* (-a) * const -> a * -const */
+ ir_node *cnst = const_negate(b);
+ if (cnst != NULL) {
+ dbg_info *dbgi = get_irn_dbg_info(n);
+ ir_node *block = get_nodes_block(n);
+ n = new_rd_Mul(dbgi, current_ir_graph, block, get_Minus_op(a), cnst, mode);
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_MUL_MINUS_1);
+ return n;
+ }
+ } else if (is_Minus(b)) { /* (-a) * (-b) -> a * b */
+ dbg_info *dbgi = get_irn_dbg_info(n);
+ ir_node *block = get_nodes_block(n);
+ n = new_rd_Mul(dbgi, current_ir_graph, block, get_Minus_op(a), get_Minus_op(b), mode);
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_MUL_MINUS_MINUS);
+ return n;
+ } else if (is_Sub(b)) { /* (-a) * (b - c) -> a * (c - b) */
+ ir_node *sub_l = get_Sub_left(b);
+ ir_node *sub_r = get_Sub_right(b);
+ dbg_info *dbgi = get_irn_dbg_info(n);
+ ir_graph *irg = current_ir_graph;
+ ir_node *block = get_nodes_block(n);
+ ir_node *new_b = new_rd_Sub(dbgi, irg, block, sub_r, sub_l, mode);
+ n = new_rd_Mul(dbgi, irg, block, get_Minus_op(a), new_b, mode);
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_MUL_MINUS);
+ return n;
+ }
+ } else if (is_Minus(b)) {
+ if (is_Sub(a)) { /* (a - b) * (-c) -> (b - a) * c */
+ ir_node *sub_l = get_Sub_left(a);
+ ir_node *sub_r = get_Sub_right(a);
+ dbg_info *dbgi = get_irn_dbg_info(n);
+ ir_graph *irg = current_ir_graph;
+ ir_node *block = get_nodes_block(n);
+ ir_node *new_a = new_rd_Sub(dbgi, irg, block, sub_r, sub_l, mode);
+ n = new_rd_Mul(dbgi, irg, block, new_a, get_Minus_op(b), mode);
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_MUL_MINUS);
+ return n;
+ }
+ }
+ if (get_mode_arithmetic(mode) == irma_ieee754) {
+ if (is_Const(a)) {
+ tarval *tv = get_Const_tarval(a);
+ if (tarval_ieee754_get_exponent(tv) == 1 && tarval_ieee754_zero_mantissa(tv)) {
+ n = new_rd_Add(get_irn_dbg_info(n), current_ir_graph, get_irn_n(n, -1), b, b, mode);
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_ADD_A_A);
+ return n;
+ }
+ }
+ else if (is_Const(b)) {
+ tarval *tv = get_Const_tarval(b);
+ if (tarval_ieee754_get_exponent(tv) == 1 && tarval_ieee754_zero_mantissa(tv)) {
+ n = new_rd_Add(get_irn_dbg_info(n), current_ir_graph, get_irn_n(n, -1), a, a, mode);
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_ADD_A_A);
+ return n;
+ }
+ }
+ }
+ return arch_dep_replace_mul_with_shifts(n);
+} /* transform_node_Mul */
+
+/**
+ * Transform a Div Node.
+ */
+static ir_node *transform_node_Div(ir_node *n) {
+ ir_mode *mode = get_Div_resmode(n);
+ ir_node *a = get_Div_left(n);
+ ir_node *b = get_Div_right(n);
+ ir_node *value;
+ tarval *tv;
+
+ if (is_Const(b) && is_const_Phi(a)) {
+ /* check for Div(Phi, Const) */
+ value = apply_binop_on_phi(a, get_Const_tarval(b), tarval_div, mode, 0);
+ if (value) {
+ DBG_OPT_ALGSIM0(n, value, FS_OPT_CONST_PHI);
+ goto make_tuple;
+ }
+ }
+ else if (is_Const(a) && is_const_Phi(b)) {
+ /* check for Div(Const, Phi) */
+ value = apply_binop_on_phi(b, get_Const_tarval(a), tarval_div, mode, 1);
+ if (value) {
+ DBG_OPT_ALGSIM0(n, value, FS_OPT_CONST_PHI);
+ goto make_tuple;
+ }
+ }
+ else if (is_const_Phi(a) && is_const_Phi(b)) {
+ /* check for Div(Phi, Phi) */
+ value = apply_binop_on_2_phis(a, b, tarval_div, mode);
+ if (value) {
+ DBG_OPT_ALGSIM0(n, value, FS_OPT_CONST_PHI);
+ goto make_tuple;
+ }
+ }
+
+ value = n;
+ tv = value_of(n);
+ if (tv != tarval_bad) {
+ value = new_Const(get_tarval_mode(tv), tv);
+
+ DBG_OPT_CSTEVAL(n, value);
+ goto make_tuple;
+ } else {
+ ir_node *a = get_Div_left(n);
+ ir_node *b = get_Div_right(n);
+ ir_node *dummy;
+
+ if (a == b && value_not_zero(a, &dummy)) {
+ /* BEWARE: we can optimize a/a to 1 only if this cannot cause a exception */
+ value = new_Const(mode, get_mode_one(mode));
+ DBG_OPT_CSTEVAL(n, value);
+ goto make_tuple;
+ } else {
+ if (mode_is_signed(mode) && is_Const(b)) {
+ tarval *tv = get_Const_tarval(b);
+
+ if (tv == get_mode_minus_one(mode)) {
+ /* a / -1 */
+ value = new_rd_Minus(get_irn_dbg_info(n), current_ir_graph, get_irn_n(n, -1), a, mode);
+ DBG_OPT_CSTEVAL(n, value);
+ goto make_tuple;
+ }
+ }
+ /* Try architecture dependent optimization */
+ value = arch_dep_replace_div_by_const(n);
+ }
+ }
+
+ if (value != n) {
+ ir_node *mem, *blk;
+
+make_tuple:
+ /* Turn Div into a tuple (mem, jmp, bad, value) */
+ mem = get_Div_mem(n);
+ blk = get_irn_n(n, -1);
+
+ /* skip a potential Pin */
+ if (is_Pin(mem))
+ mem = get_Pin_op(mem);
+ turn_into_tuple(n, pn_Div_max);
+ set_Tuple_pred(n, pn_Div_M, mem);
+ set_Tuple_pred(n, pn_Div_X_regular, new_r_Jmp(current_ir_graph, blk));
+ set_Tuple_pred(n, pn_Div_X_except, new_Bad());
+ set_Tuple_pred(n, pn_Div_res, value);
+ }
+ return n;
+} /* transform_node_Div */
+
+/**
+ * Transform a Mod node.
+ */
+static ir_node *transform_node_Mod(ir_node *n) {
+ ir_mode *mode = get_Mod_resmode(n);
+ ir_node *a = get_Mod_left(n);
+ ir_node *b = get_Mod_right(n);
+ ir_node *value;
+ tarval *tv;
+
+ if (is_Const(b) && is_const_Phi(a)) {
+ /* check for Div(Phi, Const) */
+ value = apply_binop_on_phi(a, get_Const_tarval(b), tarval_mod, mode, 0);
+ if (value) {
+ DBG_OPT_ALGSIM0(n, value, FS_OPT_CONST_PHI);
+ goto make_tuple;
+ }
+ }
+ else if (is_Const(a) && is_const_Phi(b)) {
+ /* check for Div(Const, Phi) */
+ value = apply_binop_on_phi(b, get_Const_tarval(a), tarval_mod, mode, 1);
+ if (value) {
+ DBG_OPT_ALGSIM0(n, value, FS_OPT_CONST_PHI);
+ goto make_tuple;
+ }
+ }
+ else if (is_const_Phi(a) && is_const_Phi(b)) {
+ /* check for Div(Phi, Phi) */
+ value = apply_binop_on_2_phis(a, b, tarval_mod, mode);
+ if (value) {
+ DBG_OPT_ALGSIM0(n, value, FS_OPT_CONST_PHI);
+ goto make_tuple;
+ }
+ }
+
+ value = n;
+ tv = value_of(n);
+ if (tv != tarval_bad) {
+ value = new_Const(get_tarval_mode(tv), tv);
+
+ DBG_OPT_CSTEVAL(n, value);
+ goto make_tuple;
+ } else {
+ ir_node *a = get_Mod_left(n);
+ ir_node *b = get_Mod_right(n);
+ ir_node *dummy;
+
+ if (a == b && value_not_zero(a, &dummy)) {
+ /* BEWARE: we can optimize a%a to 0 only if this cannot cause a exception */
+ value = new_Const(mode, get_mode_null(mode));
+ DBG_OPT_CSTEVAL(n, value);
+ goto make_tuple;
+ } else {
+ if (mode_is_signed(mode) && is_Const(b)) {
+ tarval *tv = get_Const_tarval(b);
+
+ if (tv == get_mode_minus_one(mode)) {
+ /* a % -1 = 0 */
+ value = new_Const(mode, get_mode_null(mode));
+ DBG_OPT_CSTEVAL(n, value);
+ goto make_tuple;
+ }
+ }
+ /* Try architecture dependent optimization */
+ value = arch_dep_replace_mod_by_const(n);
+ }
+ }
+
+ if (value != n) {
+ ir_node *mem, *blk;
+
+make_tuple:
+ /* Turn Mod into a tuple (mem, jmp, bad, value) */
+ mem = get_Mod_mem(n);
+ blk = get_irn_n(n, -1);
+
+ /* skip a potential Pin */
+ if (is_Pin(mem))
+ mem = get_Pin_op(mem);
+ turn_into_tuple(n, pn_Mod_max);
+ set_Tuple_pred(n, pn_Mod_M, mem);
+ set_Tuple_pred(n, pn_Mod_X_regular, new_r_Jmp(current_ir_graph, blk));
+ set_Tuple_pred(n, pn_Mod_X_except, new_Bad());
+ set_Tuple_pred(n, pn_Mod_res, value);
+ }
+ return n;
+} /* transform_node_Mod */
+
+/**
+ * Transform a DivMod node.
+ */
+static ir_node *transform_node_DivMod(ir_node *n) {
+ ir_node *dummy;
+ ir_node *a = get_DivMod_left(n);
+ ir_node *b = get_DivMod_right(n);
+ ir_mode *mode = get_DivMod_resmode(n);
+ tarval *ta, *tb;
+ int evaluated = 0;
+ ir_node *va, *vb;
+
+ if (is_Const(b) && is_const_Phi(a)) {
+ /* check for Div(Phi, Const) */
+ va = apply_binop_on_phi(a, get_Const_tarval(b), tarval_div, mode, 0);
+ vb = apply_binop_on_phi(a, get_Const_tarval(b), tarval_mod, mode, 0);
+ if (va && vb) {
+ DBG_OPT_ALGSIM0(n, va, FS_OPT_CONST_PHI);
+ DBG_OPT_ALGSIM0(n, vb, FS_OPT_CONST_PHI);
+ goto make_tuple;
+ }
+ }
+ else if (is_Const(a) && is_const_Phi(b)) {
+ /* check for Div(Const, Phi) */
+ va = apply_binop_on_phi(b, get_Const_tarval(a), tarval_div, mode, 1);
+ vb = apply_binop_on_phi(b, get_Const_tarval(a), tarval_mod, mode, 1);
+ if (va && vb) {
+ DBG_OPT_ALGSIM0(n, va, FS_OPT_CONST_PHI);
+ DBG_OPT_ALGSIM0(n, vb, FS_OPT_CONST_PHI);
+ goto make_tuple;
+ }
+ }
+ else if (is_const_Phi(a) && is_const_Phi(b)) {
+ /* check for Div(Phi, Phi) */
+ va = apply_binop_on_2_phis(a, b, tarval_div, mode);
+ vb = apply_binop_on_2_phis(a, b, tarval_mod, mode);
+ if (va && vb) {
+ DBG_OPT_ALGSIM0(n, va, FS_OPT_CONST_PHI);
+ DBG_OPT_ALGSIM0(n, vb, FS_OPT_CONST_PHI);
+ goto make_tuple;
+ }
+ }
+
+ ta = value_of(a);
+ tb = value_of(b);
+ if (tb != tarval_bad) {
+ if (tb == get_mode_one(get_tarval_mode(tb))) {
+ va = a;
+ vb = new_Const(mode, get_mode_null(mode));
+ DBG_OPT_CSTEVAL(n, vb);
+ goto make_tuple;
+ } else if (ta != tarval_bad) {
+ tarval *resa, *resb;
+ resa = tarval_div(ta, tb);
+ if (resa == tarval_bad) return n; /* Causes exception!!! Model by replacing through
+ Jmp for X result!? */
+ resb = tarval_mod(ta, tb);
+ if (resb == tarval_bad) return n; /* Causes exception! */
+ va = new_Const(mode, resa);
+ vb = new_Const(mode, resb);
+ DBG_OPT_CSTEVAL(n, va);
+ DBG_OPT_CSTEVAL(n, vb);
+ goto make_tuple;
+ } else if (mode_is_signed(mode) && tb == get_mode_minus_one(mode)) {
+ va = new_rd_Minus(get_irn_dbg_info(n), current_ir_graph, get_irn_n(n, -1), a, mode);
+ vb = new_Const(mode, get_mode_null(mode));
+ DBG_OPT_CSTEVAL(n, va);
+ DBG_OPT_CSTEVAL(n, vb);
+ goto make_tuple;
+ } else { /* Try architecture dependent optimization */
+ va = a;
+ vb = b;
+ arch_dep_replace_divmod_by_const(&va, &vb, n);
+ evaluated = va != NULL;
+ }
+ } else if (a == b) {
+ if (value_not_zero(a, &dummy)) {
+ /* a/a && a != 0 */
+ va = new_Const(mode, get_mode_one(mode));
+ vb = new_Const(mode, get_mode_null(mode));
+ DBG_OPT_CSTEVAL(n, va);
+ DBG_OPT_CSTEVAL(n, vb);
+ goto make_tuple;
+ } else {
+ /* BEWARE: it is NOT possible to optimize a/a to 1, as this may cause a exception */
+ return n;
+ }
+ } else if (ta == get_mode_null(mode) && value_not_zero(b, &dummy)) {
+ /* 0 / non-Const = 0 */
+ vb = va = a;
+ goto make_tuple;
+ }
+
+ if (evaluated) { /* replace by tuple */
+ ir_node *mem, *blk;
+
+make_tuple:
+ mem = get_DivMod_mem(n);
+ /* skip a potential Pin */
+ if (is_Pin(mem))
+ mem = get_Pin_op(mem);
+
+ blk = get_irn_n(n, -1);
+ turn_into_tuple(n, pn_DivMod_max);
+ set_Tuple_pred(n, pn_DivMod_M, mem);
+ set_Tuple_pred(n, pn_DivMod_X_regular, new_r_Jmp(current_ir_graph, blk));
+ set_Tuple_pred(n, pn_DivMod_X_except, new_Bad()); /* no exception */
+ set_Tuple_pred(n, pn_DivMod_res_div, va);
+ set_Tuple_pred(n, pn_DivMod_res_mod, vb);
+ }
+
+ return n;
+} /* transform_node_DivMod */
+
+/**
+ * Optimize x / c to x * (1/c)
+ */
+static ir_node *transform_node_Quot(ir_node *n) {
+ ir_mode *mode = get_Quot_resmode(n);
+ ir_node *oldn = n;
+
+ if (get_mode_arithmetic(mode) == irma_ieee754) {
+ ir_node *b = get_Quot_right(n);
+
+ if (is_Const(b)) {
+ tarval *tv = get_Const_tarval(b);
+
+ tv = tarval_quo(get_mode_one(mode), tv);
+
+ /* Do the transformation if the result is either exact or we are not
+ using strict rules. */
+ if (tv != tarval_bad &&
+ (tarval_ieee754_get_exact() || (get_irg_fp_model(current_ir_graph) & fp_strict_algebraic) == 0)) {
+ ir_node *blk = get_irn_n(n, -1);
+ ir_node *c = new_r_Const(current_ir_graph, blk, mode, tv);
+ ir_node *a = get_Quot_left(n);
+ ir_node *m = new_rd_Mul(get_irn_dbg_info(n), current_ir_graph, blk, a, c, mode);
+ ir_node *mem = get_Quot_mem(n);
+
+ /* skip a potential Pin */
+ if (is_Pin(mem))
+ mem = get_Pin_op(mem);
+ turn_into_tuple(n, pn_Quot_max);
+ set_Tuple_pred(n, pn_Quot_M, mem);
+ set_Tuple_pred(n, pn_Quot_X_regular, new_r_Jmp(current_ir_graph, blk));
+ set_Tuple_pred(n, pn_Quot_X_except, new_r_Bad(current_ir_graph));
+ set_Tuple_pred(n, pn_Quot_res, m);
+ DBG_OPT_ALGSIM1(oldn, a, b, m, FS_OPT_FP_INV_MUL);
+ }
+ }
+ }
+ return n;
+} /* transform_node_Quot */
+
+/**
+ * Optimize Abs(x) into x if x is Confirmed >= 0
+ * Optimize Abs(x) into -x if x is Confirmed <= 0
+ */
+static ir_node *transform_node_Abs(ir_node *n) {
+ ir_node *c, *oldn = n;
+ ir_node *a = get_Abs_op(n);
+ ir_mode *mode;
+
+ HANDLE_UNOP_PHI(tarval_abs, a, c);
+
+ switch (classify_value_sign(a)) {
+ case value_classified_negative:
+ mode = get_irn_mode(n);
+
+ /*
+ * We can replace the Abs by -x here.
+ * We even could add a new Confirm here.
+ *
+ * Note that -x would create a new node, so we could
+ * not run it in the equivalent_node() context.
+ */
+ n = new_rd_Minus(get_irn_dbg_info(n), current_ir_graph,
+ get_irn_n(n, -1), a, mode);
+
+ DBG_OPT_CONFIRM(oldn, n);
+ return n;
+ case value_classified_positive:
+ /* n is positive, Abs is not needed */
+ n = a;
+
+ DBG_OPT_CONFIRM(oldn, n);
+ return n;
+ default:
+ return n;
+ }
+} /* transform_node_Abs */
+
+/**
+ * Transform a Cond node.
+ *
+ * Replace the Cond by a Jmp if it branches on a constant
+ * condition.
+ */
+static ir_node *transform_node_Cond(ir_node *n) {
+
+ ir_node *jmp;
+ ir_node *a = get_Cond_selector(n);
+ tarval *ta = value_of(a);
+
+ /* we need block info which is not available in floating irgs */
+ if (get_irg_pinned(current_ir_graph) == op_pin_state_floats)
+ return n;
+
+ if ((ta != tarval_bad) &&
+ (get_irn_mode(a) == mode_b) &&
+ (get_opt_unreachable_code())) {
+ /* It's a boolean Cond, branching on a boolean constant.
+ Replace it by a tuple (Bad, Jmp) or (Jmp, Bad) */
+ jmp = new_r_Jmp(current_ir_graph, get_nodes_block(n));
+ turn_into_tuple(n, pn_Cond_max);
+ if (ta == tarval_b_true) {
+ set_Tuple_pred(n, pn_Cond_false, new_Bad());
+ set_Tuple_pred(n, pn_Cond_true, jmp);
+ } else {
+ set_Tuple_pred(n, pn_Cond_false, jmp);
+ set_Tuple_pred(n, pn_Cond_true, new_Bad());
+ }
+ /* We might generate an endless loop, so keep it alive. */
+ add_End_keepalive(get_irg_end(current_ir_graph), get_nodes_block(n));
+ }
+ 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
+ * note, might return a different op than n
+ */
+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 = NULL;
+ ir_node *op2 = NULL;
+
+ 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);
+ add_identities(current_ir_graph->value_table, n);
+ }
+
+ 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 *a = get_And_left(n);
+ ir_node *b = get_And_right(n);
+ ir_mode *mode;
+
+ mode = get_irn_mode(n);
+ HANDLE_BINOP_PHI(tarval_and, a, b, c, mode);
+
+ /* we can evaluate 2 Projs of the same Cmp */
+ if (mode == mode_b && is_Proj(a) && is_Proj(b)) {
+ ir_node *pred_a = get_Proj_pred(a);
+ ir_node *pred_b = get_Proj_pred(b);
+ if (pred_a == pred_b) {
+ dbg_info *dbgi = get_irn_dbg_info(n);
+ ir_node *block = get_nodes_block(pred_a);
+ pn_Cmp pn_a = get_Proj_proj(a);
+ pn_Cmp pn_b = get_Proj_proj(b);
+ /* yes, we can simply calculate with pncs */
+ pn_Cmp new_pnc = pn_a & pn_b;
+
+ return new_rd_Proj(dbgi, current_ir_graph, block, pred_a, mode_b, new_pnc);
+ }
+ }
+ if (is_Or(a)) {
+ if (is_Not(b)) {
+ ir_node *op = get_Not_op(b);
+ if (is_And(op)) {
+ ir_node *ba = get_And_left(op);
+ ir_node *bb = get_And_right(op);
+
+ /* it's enough to test the following cases due to normalization! */
+ if (get_Or_left(a) == ba && get_Or_right(a) == bb) {
+ /* (a|b) & ~(a&b) = a^b */
+ ir_node *block = get_nodes_block(n);
+
+ n = new_rd_Eor(get_irn_dbg_info(n), current_ir_graph, block, ba, bb, mode);
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_TO_EOR);
+ return n;
+ }
+ }
+ }
+ }
+ if (is_Or(b)) {
+ if (is_Not(a)) {
+ ir_node *op = get_Not_op(a);
+ if (is_And(op)) {
+ ir_node *aa = get_And_left(op);
+ ir_node *ab = get_And_right(op);
+
+ /* it's enough to test the following cases due to normalization! */
+ if (get_Or_left(b) == aa && get_Or_right(b) == ab) {
+ /* (a|b) & ~(a&b) = a^b */
+ ir_node *block = get_nodes_block(n);
+
+ n = new_rd_Eor(get_irn_dbg_info(n), current_ir_graph, block, aa, ab, mode);
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_TO_EOR);
+ return n;
+ }
+ }
+ }
+ }
+ if (is_Eor(a)) {
+ ir_node *al = get_Eor_left(a);
+ ir_node *ar = get_Eor_right(a);
+
+ if (al == b) {
+ /* (b ^ a) & b -> ~a & b */
+ dbg_info *dbg = get_irn_dbg_info(n);
+ ir_node *block = get_nodes_block(n);
+
+ ar = new_rd_Not(dbg, current_ir_graph, block, ar, mode);
+ n = new_rd_And(dbg, current_ir_graph, block, ar, b, mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_EOR_TO_NOT);
+ return n;
+ }
+ if (ar == b) {
+ /* (a ^ b) & b -> ~a & b */
+ dbg_info *dbg = get_irn_dbg_info(n);
+ ir_node *block = get_nodes_block(n);
+
+ al = new_rd_Not(dbg, current_ir_graph, block, al, mode);
+ n = new_rd_And(dbg, current_ir_graph, block, al, b, mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_EOR_TO_NOT);
+ return n;
+ }
+ }
+ if (is_Eor(b)) {
+ ir_node *bl = get_Eor_left(b);
+ ir_node *br = get_Eor_right(b);
+
+ if (bl == a) {
+ /* a & (a ^ b) -> a & ~b */
+ dbg_info *dbg = get_irn_dbg_info(n);
+ ir_node *block = get_nodes_block(n);
+
+ br = new_rd_Not(dbg, current_ir_graph, block, br, mode);
+ n = new_rd_And(dbg, current_ir_graph, block, br, a, mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_EOR_TO_NOT);
+ return n;
+ }
+ if (br == a) {
+ /* a & (b ^ a) -> a & ~b */
+ dbg_info *dbg = get_irn_dbg_info(n);
+ ir_node *block = get_nodes_block(n);
+
+ bl = new_rd_Not(dbg, current_ir_graph, block, bl, mode);
+ n = new_rd_And(dbg, current_ir_graph, block, bl, a, mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_EOR_TO_NOT);
+ return n;
+ }
+ }
+ if (is_Not(a) && is_Not(b)) {
+ /* ~a & ~b = ~(a|b) */
+ ir_node *block = get_nodes_block(n);
+ ir_mode *mode = get_irn_mode(n);
+
+ a = get_Not_op(a);
+ b = get_Not_op(b);
+ n = new_rd_Or(get_irn_dbg_info(n), current_ir_graph, block, a, b, mode);
+ n = new_rd_Not(get_irn_dbg_info(n), current_ir_graph, block, n, mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_DEMORGAN);
+ return n;
+ }
+
+ n = transform_bitwise_distributive(n, transform_node_And);
+
+ return n;
+} /* transform_node_And */
+
+/**
+ * Transform an Eor.
+ */
+static ir_node *transform_node_Eor(ir_node *n) {
+ ir_node *c, *oldn = n;
+ ir_node *a = get_Eor_left(n);
+ ir_node *b = get_Eor_right(n);
+ ir_mode *mode = get_irn_mode(n);
+
+ HANDLE_BINOP_PHI(tarval_eor, a, b, c, mode);
+
+ /* we can evaluate 2 Projs of the same Cmp */
+ if (mode == mode_b && is_Proj(a) && is_Proj(b)) {
+ ir_node *pred_a = get_Proj_pred(a);
+ ir_node *pred_b = get_Proj_pred(b);
+ if(pred_a == pred_b) {
+ dbg_info *dbgi = get_irn_dbg_info(n);
+ ir_node *block = get_nodes_block(pred_a);
+ pn_Cmp pn_a = get_Proj_proj(a);
+ pn_Cmp pn_b = get_Proj_proj(b);
+ /* yes, we can simply calculate with pncs */
+ pn_Cmp new_pnc = pn_a ^ pn_b;
+
+ return new_rd_Proj(dbgi, current_ir_graph, block, pred_a, mode_b,
+ new_pnc);
+ }
+ }
+
+ if (a == b) {
+ /* a ^ a = 0 */
+ n = new_rd_Const(get_irn_dbg_info(n), current_ir_graph, get_irn_n(n, -1),
+ mode, get_mode_null(mode));
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_EOR_A_A);
+ } else if (mode == mode_b &&
+ is_Proj(a) &&
+ is_Const(b) && is_Const_one(b) &&
+ is_Cmp(get_Proj_pred(a))) {
+ /* The Eor negates 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));
+
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_EOR_TO_NOT_BOOL);
+ } else if (is_Const(b)) {
+ if (is_Not(a)) { /* ~x ^ const -> x ^ ~const */
+ ir_node *cnst = new_Const(mode, tarval_not(get_Const_tarval(b)));
+ ir_node *not_op = get_Not_op(a);
+ dbg_info *dbg = get_irn_dbg_info(n);
+ ir_graph *irg = current_ir_graph;
+ ir_node *block = get_nodes_block(n);
+ ir_mode *mode = get_irn_mode(n);
+ n = new_rd_Eor(dbg, irg, block, not_op, cnst, mode);
+ return n;
+ } else if (is_Const_all_one(b)) { /* x ^ 1...1 -> ~1 */
+ n = new_r_Not(current_ir_graph, get_nodes_block(n), a, mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_EOR_TO_NOT);
+ }
+ } else {
+ n = transform_bitwise_distributive(n, transform_node_Eor);
+ }
+
+ return n;
+} /* transform_node_Eor */
+
+/**
+ * Transform a Not.
+ */
+static ir_node *transform_node_Not(ir_node *n) {
+ ir_node *c, *oldn = n;
+ ir_node *a = get_Not_op(n);
+ ir_mode *mode = get_irn_mode(n);
+
+ HANDLE_UNOP_PHI(tarval_not,a,c);
+
+ /* check for a boolean Not */
+ if (mode == mode_b &&
+ is_Proj(a) &&
+ is_Cmp(get_Proj_pred(a))) {
+ /* 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 (is_Eor(a)) {
+ ir_node *eor_b = get_Eor_right(a);
+ if (is_Const(eor_b)) { /* ~(x ^ const) -> x ^ ~const */
+ ir_node *cnst = new_Const(mode, tarval_not(get_Const_tarval(eor_b)));
+ ir_node *eor_a = get_Eor_left(a);
+ dbg_info *dbg = get_irn_dbg_info(n);
+ ir_graph *irg = current_ir_graph;
+ ir_node *block = get_nodes_block(n);
+ ir_mode *mode = get_irn_mode(n);
+ n = new_rd_Eor(dbg, irg, block, eor_a, cnst, mode);
+ return n;
+ }
+ }
+ if (get_mode_arithmetic(mode) == irma_twos_complement) {
+ if (is_Minus(a)) { /* ~-x -> x + -1 */
+ dbg_info *dbg = get_irn_dbg_info(n);
+ ir_graph *irg = current_ir_graph;
+ ir_node *block = get_nodes_block(n);
+ ir_node *add_l = get_Minus_op(a);
+ ir_node *add_r = new_rd_Const(dbg, irg, block, mode, get_mode_minus_one(mode));
+ n = new_rd_Add(dbg, irg, block, add_l, add_r, mode);
+ } else if (is_Add(a)) {
+ ir_node *add_r = get_Add_right(a);
+ if (is_Const(add_r) && is_Const_all_one(add_r)) {
+ /* ~(x + -1) = -x */
+ ir_node *op = get_Add_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
+ * -(a-b) = b - a
+ * -(a >>u (size-1)) = a >>s (size-1)
+ * -(a >>s (size-1)) = a >>u (size-1)
+ * -(a * const) -> a * -const
+ */
+static ir_node *transform_node_Minus(ir_node *n) {
+ ir_node *c, *oldn = n;
+ ir_node *a = get_Minus_op(n);
+ ir_mode *mode;
+
+ HANDLE_UNOP_PHI(tarval_neg,a,c);
+
+ mode = get_irn_mode(a);
+ if (get_mode_arithmetic(mode) == irma_twos_complement) {
+ /* the following rules are only to twos-complement */
+ if (is_Not(a)) {
+ /* -(~x) = x + 1 */
+ ir_node *op = get_Not_op(a);
+ 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;
+ }
+ if (is_Shr(a)) {
+ ir_node *c = get_Shr_right(a);
+
+ if (is_Const(c)) {
+ tarval *tv = get_Const_tarval(c);
+
+ if (tarval_is_long(tv) && get_tarval_long(tv) == get_mode_size_bits(mode) - 1) {
+ /* -(a >>u (size-1)) = a >>s (size-1) */
+ ir_node *v = get_Shr_left(a);
+
+ n = new_rd_Shrs(get_irn_dbg_info(n), current_ir_graph, get_irn_n(n, -1), v, c, mode);
+ DBG_OPT_ALGSIM2(oldn, a, n, FS_OPT_PREDICATE);
+ return n;
+ }
+ }
+ }
+ if (is_Shrs(a)) {
+ ir_node *c = get_Shrs_right(a);
+
+ if (is_Const(c)) {
+ tarval *tv = get_Const_tarval(c);
+
+ if (tarval_is_long(tv) && get_tarval_long(tv) == get_mode_size_bits(mode) - 1) {
+ /* -(a >>s (size-1)) = a >>u (size-1) */
+ ir_node *v = get_Shrs_left(a);
+
+ n = new_rd_Shr(get_irn_dbg_info(n), current_ir_graph, get_irn_n(n, -1), v, c, mode);
+ DBG_OPT_ALGSIM2(oldn, a, n, FS_OPT_PREDICATE);
+ return n;
+ }
+ }
+ }
+ }
+ if (is_Sub(a)) {
+ /* - (a-b) = b - a */
+ ir_node *la = get_Sub_left(a);
+ ir_node *ra = get_Sub_right(a);
+ ir_node *blk = get_irn_n(n, -1);
+
+ n = new_rd_Sub(get_irn_dbg_info(n), current_ir_graph, blk, ra, la, mode);
+ DBG_OPT_ALGSIM2(oldn, a, n, FS_OPT_MINUS_SUB);
+ return n;
+ }
+
+ if (is_Mul(a)) { /* -(a * const) -> a * -const */
+ ir_node *mul_l = get_Mul_left(a);
+ ir_node *mul_r = get_Mul_right(a);
+ if (is_Const(mul_r)) {
+ tarval *tv = tarval_neg(get_Const_tarval(mul_r));
+ ir_node *cnst = new_Const(mode, tv);
+ dbg_info *dbg = get_irn_dbg_info(a);
+ ir_graph *irg = current_ir_graph;
+ ir_node *block = get_nodes_block(a);
+ n = new_rd_Mul(dbg, irg, block, mul_l, cnst, mode);
+ DBG_OPT_ALGSIM2(oldn, a, n, FS_OPT_MINUS_MUL_C);
+ return n;
+ }
+ }
+
+ return n;
+} /* transform_node_Minus */
+
+/**
+ * Transform a Cast_type(Const) into a new Const_type
+ */