+ a = get_Add_left(n);
+ b = get_Add_right(n);
+
+ mode = get_irn_mode(n);
+ HANDLE_BINOP_PHI(tarval_add, a, b, c, mode);
+
+ /* for FP these optimizations are only allowed if fp_strict_algebraic is disabled */
+ if (mode_is_float(mode) && (get_irg_fp_model(current_ir_graph) & fp_strict_algebraic))
+ return n;
+
+ if (mode_is_num(mode)) {
+ /* the following code leads to endless recursion when Mul are replaced by a simple instruction chain */
+ if (!is_arch_dep_running() && a == b && mode_is_int(mode)) {
+ ir_node *block = get_irn_n(n, -1);
+
+ n = new_rd_Mul(
+ get_irn_dbg_info(n),
+ current_ir_graph,
+ block,
+ a,
+ new_r_Const_long(current_ir_graph, block, mode, 2),
+ mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_A_A);
+ return n;
+ }
+ if (is_Minus(a)) {
+ n = new_rd_Sub(
+ get_irn_dbg_info(n),
+ current_ir_graph,
+ get_irn_n(n, -1),
+ b,
+ get_Minus_op(a),
+ mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_A_MINUS_B);
+ return n;
+ }
+ if (is_Minus(b)) {
+ n = new_rd_Sub(
+ get_irn_dbg_info(n),
+ current_ir_graph,
+ get_irn_n(n, -1),
+ a,
+ get_Minus_op(b),
+ mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_A_MINUS_B);
+ return n;
+ }
+ if (get_mode_arithmetic(mode) == irma_twos_complement) {
+ /* Here we rely on constants be on the RIGHT side */
+ if (is_Not(a)) {
+ ir_node *op = get_Not_op(a);
+
+ if (is_Const(b) && is_Const_one(b)) {
+ /* ~x + 1 = -x */
+ 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;
+ }
+ if (op == b) {
+ /* ~x + x = -1 */
+ ir_node *blk = get_irn_n(n, -1);
+ n = new_r_Const(current_ir_graph, blk, mode, get_mode_minus_one(mode));
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_X_NOT_X);
+ return n;
+ }
+ }
+ if (is_Not(b)) {
+ ir_node *op = get_Not_op(b);
+
+ if (op == a) {
+ /* x + ~x = -1 */
+ ir_node *blk = get_irn_n(n, -1);
+ n = new_r_Const(current_ir_graph, blk, mode, get_mode_minus_one(mode));
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_ADD_X_NOT_X);
+ return n;
+ }
+ }
+ }
+ }
+ return n;
+} /* transform_node_Add */
+
+/**
+ * returns -cnst or NULL if impossible
+ */
+static ir_node *const_negate(ir_node *cnst) {
+ tarval *tv = tarval_neg(get_Const_tarval(cnst));
+ dbg_info *dbgi = get_irn_dbg_info(cnst);
+ ir_graph *irg = get_irn_irg(cnst);
+ ir_node *block = get_nodes_block(cnst);
+ ir_mode *mode = get_irn_mode(cnst);
+ if (tv == tarval_bad) return NULL;
+ return new_rd_Const(dbgi, irg, block, mode, tv);
+}
+
+/**
+ * Do the AddSub optimization, then Transform
+ * Constant folding on Phi
+ * Sub(0,a) -> Minus(a)
+ * Sub(Mul(a, x), a) -> Mul(a, x-1)
+ * Sub(Sub(x, y), b) -> Sub(x, Add(y,b))
+ * Sub(Add(a, x), x) -> a
+ * Sub(x, Add(x, a)) -> -a
+ * Sub(x, Const) -> Add(x, -Const)
+ */
+static ir_node *transform_node_Sub(ir_node *n) {
+ ir_mode *mode;
+ ir_node *oldn = n;
+ ir_node *a, *b, *c;
+
+ n = transform_node_AddSub(n);
+
+ a = get_Sub_left(n);
+ b = get_Sub_right(n);
+
+ mode = get_irn_mode(n);
+
+restart:
+ HANDLE_BINOP_PHI(tarval_sub, a, b, c, mode);
+
+ /* for FP these optimizations are only allowed if fp_strict_algebraic is disabled */
+ if (mode_is_float(mode) && (get_irg_fp_model(current_ir_graph) & fp_strict_algebraic))
+ return n;
+
+ if (is_Const(b) && get_irn_mode(b) != mode_P) {
+ /* a - C -> a + (-C) */
+ ir_node *cnst = const_negate(b);
+ if (cnst != NULL) {
+ ir_node *block = get_nodes_block(n);
+ dbg_info *dbgi = get_irn_dbg_info(n);
+ ir_graph *irg = get_irn_irg(n);
+
+ n = new_rd_Add(dbgi, irg, block, a, cnst, mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_TO_ADD);
+ return n;
+ }
+ }
+
+ if (is_Minus(a)) { /* (-a) - b -> -(a + b) */
+ ir_graph *irg = current_ir_graph;
+ dbg_info *dbg = get_irn_dbg_info(n);
+ ir_node *block = get_nodes_block(n);
+ ir_node *left = get_Minus_op(a);
+ ir_node *add = new_rd_Add(dbg, irg, block, left, b, mode);
+
+ n = new_rd_Minus(dbg, irg, block, add, mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_TO_ADD);
+ return n;
+ } else if (is_Minus(b)) { /* a - (-b) -> a + b */
+ ir_graph *irg = current_ir_graph;
+ dbg_info *dbg = get_irn_dbg_info(n);
+ ir_node *block = get_nodes_block(n);
+ ir_node *right = get_Minus_op(b);
+
+ n = new_rd_Add(dbg, irg, block, a, right, mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_MINUS);
+ return n;
+ } else if (is_Sub(b)) { /* a - (b - c) -> a + (c - b) */
+ ir_graph *irg = current_ir_graph;
+ dbg_info *s_dbg = get_irn_dbg_info(b);
+ ir_node *s_block = get_nodes_block(b);
+ ir_node *s_left = get_Sub_right(b);
+ ir_node *s_right = get_Sub_left(b);
+ ir_mode *s_mode = get_irn_mode(b);
+ ir_node *sub = new_rd_Sub(s_dbg, irg, s_block, s_left, s_right, s_mode);
+ dbg_info *a_dbg = get_irn_dbg_info(n);
+ ir_node *a_block = get_nodes_block(n);
+
+ n = new_rd_Add(a_dbg, irg, a_block, a, sub, mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_TO_ADD);
+ return n;
+ } else if (is_Mul(b)) { /* a - (b * C) -> a + (b * -C) */
+ ir_node *m_right = get_Mul_right(b);
+ if (is_Const(m_right)) {
+ ir_node *cnst2 = const_negate(m_right);
+ if (cnst2 != NULL) {
+ ir_graph *irg = current_ir_graph;
+ dbg_info *m_dbg = get_irn_dbg_info(b);
+ ir_node *m_block = get_nodes_block(b);
+ ir_node *m_left = get_Mul_left(b);
+ ir_mode *m_mode = get_irn_mode(b);
+ ir_node *mul = new_rd_Mul(m_dbg, irg, m_block, m_left, cnst2, m_mode);
+ dbg_info *a_dbg = get_irn_dbg_info(n);
+ ir_node *a_block = get_nodes_block(n);
+
+ n = new_rd_Add(a_dbg, irg, a_block, a, mul, mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_TO_ADD);
+ return n;
+ }
+ }
+ }
+
+ /* Beware of Sub(P, P) which cannot be optimized into a simple Minus ... */
+ if (mode_is_num(mode) && mode == get_irn_mode(a) && is_Const(a) && is_Const_null(a)) {
+ n = new_rd_Minus(
+ get_irn_dbg_info(n),
+ current_ir_graph,
+ get_irn_n(n, -1),
+ b,
+ mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_0_A);
+ return n;
+ }
+ if (is_Add(a)) {
+ if (mode_wrap_around(mode)) {
+ ir_node *left = get_Add_left(a);
+ ir_node *right = get_Add_right(a);
+
+ /* FIXME: Does the Conv's work only for two complement or generally? */
+ if (left == b) {
+ if (mode != get_irn_mode(right)) {
+ /* This Sub is an effective Cast */
+ right = new_r_Conv(get_irn_irg(n), get_irn_n(n, -1), right, mode);
+ }
+ n = right;
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_ADD_SUB);
+ return n;
+ } else if (right == b) {
+ if (mode != get_irn_mode(left)) {
+ /* This Sub is an effective Cast */
+ left = new_r_Conv(get_irn_irg(n), get_irn_n(n, -1), left, mode);
+ }
+ n = left;
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_ADD_SUB);
+ return n;
+ }
+ }
+ }
+ if (is_Add(b)) {
+ if (mode_wrap_around(mode)) {
+ ir_node *left = get_Add_left(b);
+ ir_node *right = get_Add_right(b);
+
+ /* FIXME: Does the Conv's work only for two complement or generally? */
+ if (left == a) {
+ ir_mode *r_mode = get_irn_mode(right);
+
+ n = new_r_Minus(get_irn_irg(n), get_irn_n(n, -1), right, r_mode);
+ if (mode != r_mode) {
+ /* This Sub is an effective Cast */
+ n = new_r_Conv(get_irn_irg(n), get_irn_n(n, -1), n, mode);
+ }
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_ADD_SUB);
+ return n;
+ } else if (right == a) {
+ ir_mode *l_mode = get_irn_mode(left);
+
+ n = new_r_Minus(get_irn_irg(n), get_irn_n(n, -1), left, l_mode);
+ if (mode != l_mode) {
+ /* This Sub is an effective Cast */
+ n = new_r_Conv(get_irn_irg(n), get_irn_n(n, -1), n, mode);
+ }
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_ADD_SUB);
+ return n;
+ }
+ }
+ }
+ if (mode_is_int(mode) && is_Conv(a) && is_Conv(b)) {
+ ir_mode *mode = get_irn_mode(a);
+
+ if (mode == get_irn_mode(b)) {
+ ir_mode *ma, *mb;
+ ir_node *op_a = get_Conv_op(a);
+ ir_node *op_b = get_Conv_op(b);
+
+ /* check if it's allowed to skip the conv */
+ ma = get_irn_mode(op_a);
+ mb = get_irn_mode(op_b);
+
+ if (mode_is_reference(ma) && mode_is_reference(mb)) {
+ /* SubInt(ConvInt(aP), ConvInt(bP)) -> SubInt(aP,bP) */
+ a = op_a; b = op_b;
+ set_Sub_left(n, a);
+ set_Sub_right(n, b);
+
+ goto restart;
+ }
+ }
+ }
+ /* do NOT execute this code if reassociation is enabled, it does the inverse! */
+ if (!is_reassoc_running() && is_Mul(a)) {
+ ir_node *ma = get_Mul_left(a);
+ ir_node *mb = get_Mul_right(a);
+
+ if (ma == b) {
+ ir_node *blk = get_irn_n(n, -1);
+ n = new_rd_Mul(
+ get_irn_dbg_info(n),
+ current_ir_graph, blk,
+ ma,
+ new_rd_Sub(
+ get_irn_dbg_info(n),
+ current_ir_graph, blk,
+ mb,
+ new_r_Const_long(current_ir_graph, blk, mode, 1),
+ mode),
+ mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_MUL_A_X_A);
+ return n;
+ } else if (mb == b) {
+ ir_node *blk = get_irn_n(n, -1);
+ n = new_rd_Mul(
+ get_irn_dbg_info(n),
+ current_ir_graph, blk,
+ mb,
+ new_rd_Sub(
+ get_irn_dbg_info(n),
+ current_ir_graph, blk,
+ ma,
+ new_r_Const_long(current_ir_graph, blk, mode, 1),
+ mode),
+ mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_MUL_A_X_A);
+ return n;
+ }
+ }
+ if (is_Sub(a)) { /* (x - y) - b -> x - (y + b) */
+ ir_node *x = get_Sub_left(a);
+ ir_node *y = get_Sub_right(a);
+ ir_node *blk = get_irn_n(n, -1);
+ ir_mode *m_b = get_irn_mode(b);
+ ir_mode *m_y = get_irn_mode(y);
+ ir_mode *add_mode;
+ ir_node *add;
+
+ /* Determine the right mode for the Add. */
+ if (m_b == m_y)
+ add_mode = m_b;
+ else if (mode_is_reference(m_b))
+ add_mode = m_b;
+ else if (mode_is_reference(m_y))
+ add_mode = m_y;
+ else {
+ /*
+ * Both modes are different but none is reference,
+ * happens for instance in SubP(SubP(P, Iu), Is).
+ * We have two possibilities here: Cast or ignore.
+ * Currently we ignore this case.
+ */
+ return n;
+ }
+
+ add = new_r_Add(current_ir_graph, blk, y, b, add_mode);
+
+ n = new_rd_Sub(get_irn_dbg_info(n), current_ir_graph, blk, x, add, mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_SUB_X_Y_Z);
+ return n;
+ }
+
+ if (get_mode_arithmetic(mode) == irma_twos_complement) {
+ if (is_Const(a) && is_Not(b)) {
+ /* c - ~X = X + (c+1) */
+ tarval *tv = get_Const_tarval(a);
+
+ tv = tarval_add(tv, get_mode_one(mode));
+ if (tv != tarval_bad) {
+ 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, get_Not_op(b), c, mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_SUB_C_NOT_X);
+ return n;
+ }
+ }
+ }
+ return n;
+} /* transform_node_Sub */
+
+/**
+ * Several transformation done on n*n=2n bits mul.
+ * These transformations must be done here because new nodes may be produced.
+ */
+static ir_node *transform_node_Mul2n(ir_node *n, ir_mode *mode) {
+ ir_node *oldn = n;
+ ir_node *a = get_Mul_left(n);
+ ir_node *b = get_Mul_right(n);
+ tarval *ta = value_of(a);
+ tarval *tb = value_of(b);
+ ir_mode *smode = get_irn_mode(a);
+
+ if (ta == get_mode_one(smode)) {
+ ir_node *blk = get_irn_n(n, -1);
+ n = new_rd_Conv(get_irn_dbg_info(n), current_ir_graph, blk, b, mode);
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_NEUTRAL_1);
+ return n;
+ }
+ else if (ta == get_mode_minus_one(smode)) {
+ ir_node *blk = get_irn_n(n, -1);
+ n = new_rd_Minus(get_irn_dbg_info(n), current_ir_graph, blk, b, smode);
+ n = new_rd_Conv(get_irn_dbg_info(n), current_ir_graph, blk, n, mode);
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_MUL_MINUS_1);
+ return n;
+ }
+ if (tb == get_mode_one(smode)) {
+ ir_node *blk = get_irn_n(a, -1);
+ n = new_rd_Conv(get_irn_dbg_info(n), current_ir_graph, blk, a, mode);
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_NEUTRAL_1);
+ return n;
+ }
+ else if (tb == get_mode_minus_one(smode)) {
+ ir_node *blk = get_irn_n(n, -1);
+ n = new_rd_Minus(get_irn_dbg_info(n), current_ir_graph, blk, a, smode);
+ n = new_rd_Conv(get_irn_dbg_info(n), current_ir_graph, blk, n, mode);
+ DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_MUL_MINUS_1);
+ return n;
+ }
+ return n;
+}
+
+/**
+ * Transform Mul(a,-1) into -a.
+ * Do constant evaluation of Phi nodes.
+ * Do architecture dependent optimizations on Mul nodes
+ */
+static ir_node *transform_node_Mul(ir_node *n) {
+ ir_node *c, *oldn = n;
+ ir_mode *mode = get_irn_mode(n);
+ ir_node *a = get_Mul_left(n);
+ ir_node *b = get_Mul_right(n);
+
+ if (is_Bad(a) || is_Bad(b))
+ return n;
+
+ if (mode != get_irn_mode(a))
+ return transform_node_Mul2n(n, mode);
+
+ 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;
+ }