+/**
+ * Transform AddP(P, ConvIs(Iu)), AddP(P, ConvIu(Is)) and
+ * SubP(P, ConvIs(Iu)), SubP(P, ConvIu(Is)).
+ * If possible, remove the Conv's.
+ */
+static ir_node *transform_node_AddSub(ir_node *n)
+{
+ ir_mode *mode = get_irn_mode(n);
+
+ if (mode_is_reference(mode)) {
+ ir_node *left = get_binop_left(n);
+ ir_node *right = get_binop_right(n);
+ int ref_bits = get_mode_size_bits(mode);
+
+ if (get_irn_op(left) == op_Conv) {
+ ir_mode *mode = get_irn_mode(left);
+ int bits = get_mode_size_bits(mode);
+
+ if (ref_bits == bits &&
+ mode_is_int(mode) &&
+ get_mode_arithmetic(mode) == irma_twos_complement) {
+ ir_node *pre = get_Conv_op(left);
+ ir_mode *pre_mode = get_irn_mode(pre);
+
+ if (mode_is_int(pre_mode) &&
+ get_mode_size_bits(pre_mode) == bits &&
+ get_mode_arithmetic(pre_mode) == irma_twos_complement) {
+ /* ok, this conv just changes to sign, moreover the calculation
+ * is done with same number of bits as our address mode, so
+ * we can ignore the conv as address calculation can be viewed
+ * as either signed or unsigned
+ */
+ set_binop_left(n, pre);
+ }
+ }
+ }
+
+ if (get_irn_op(right) == op_Conv) {
+ ir_mode *mode = get_irn_mode(right);
+ int bits = get_mode_size_bits(mode);
+
+ if (ref_bits == bits &&
+ mode_is_int(mode) &&
+ get_mode_arithmetic(mode) == irma_twos_complement) {
+ ir_node *pre = get_Conv_op(right);
+ ir_mode *pre_mode = get_irn_mode(pre);
+
+ if (mode_is_int(pre_mode) &&
+ get_mode_size_bits(pre_mode) == bits &&
+ get_mode_arithmetic(pre_mode) == irma_twos_complement) {
+ /* ok, this conv just changes to sign, moreover the calculation
+ * is done with same number of bits as our address mode, so
+ * we can ignore the conv as address calculation can be viewed
+ * as either signed or unsigned
+ */
+ set_binop_right(n, pre);
+ }
+ }
+ }
+ }
+ return n;
+}
+
+/**
+ * Do the AddSub optimization, then Transform
+ * Add(a,a) -> Mul(a, 2)
+ * Add(Mul(a, x), a) -> Mul(a, x+1)
+ * if the mode is integer or float.
+ * Transform Add(a,-b) into Sub(a,b).
+ * Reassociation might fold this further.
+ */
+static ir_node *transform_node_Add(ir_node *n)
+{
+ ir_mode *mode;
+ ir_node *oldn = n;
+
+ n = transform_node_AddSub(n);
+
+ mode = get_irn_mode(n);
+ if (mode_is_num(mode)) {
+ ir_node *a = get_Add_left(n);
+ ir_node *b = get_Add_right(n);
+
+ if (a == b) {
+ 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);
+ }
+ else if (get_irn_op(a) == op_Minus) {
+ 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);
+ }
+ else if (get_irn_op(b) == op_Minus) {
+ 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);
+ }
+ /* do NOT execute this code if reassociation is enabled, it does the inverse! */
+ else if (!get_opt_reassociation() && get_irn_op(a) == op_Mul) {
+ ir_node *ma = get_Mul_left(a);
+ ir_node *mb = get_Mul_right(a);
+
+ if (b == ma) {
+ ir_node *blk = get_irn_n(n, -1);
+ n = new_rd_Mul(
+ get_irn_dbg_info(n), current_ir_graph, blk,
+ ma,
+ new_rd_Add(
+ 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_ADD_MUL_A_X_A);
+ }
+ else if (b == mb) {
+ ir_node *blk = get_irn_n(n, -1);
+ n = new_rd_Mul(
+ get_irn_dbg_info(n), current_ir_graph, blk,
+ mb,
+ new_rd_Add(
+ 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_ADD_MUL_A_X_A);
+ }
+ }
+ /* do NOT execute this code if reassociation is enabled, it does the inverse! */
+ else if (!get_opt_reassociation() && get_irn_op(b) == op_Mul) {
+ ir_node *ma = get_Mul_left(b);
+ ir_node *mb = get_Mul_right(b);
+
+ if (a == ma) {
+ ir_node *blk = get_irn_n(n, -1);
+ n = new_rd_Mul(
+ get_irn_dbg_info(n), current_ir_graph, blk,
+ ma,
+ new_rd_Add(
+ 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_ADD_MUL_A_X_A);
+ }
+ else if (a == mb) {
+ ir_node *blk = get_irn_n(n, -1);
+ n = new_rd_Mul(
+ get_irn_dbg_info(n), current_ir_graph, blk,
+ mb,
+ new_rd_Add(
+ 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_ADD_MUL_A_X_A);
+ }
+ }
+ }
+ return n;
+}
+
+/**
+ * Do the AddSub optimization, then Transform
+ * Sub(0,a) -> Minus(a)
+ * Sub(Mul(a, x), a) -> Mul(a, x-1)
+ */
+static ir_node *transform_node_Sub(ir_node *n)
+{
+ ir_mode *mode;
+ ir_node *oldn = n;
+ ir_node *a, *b;
+
+ n = transform_node_AddSub(n);
+
+ mode = get_irn_mode(n);
+ a = get_Sub_left(n);
+ b = get_Sub_right(n);
+ if (mode_is_num(mode) && (classify_Const(a) == CNST_NULL)) {
+ 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);
+ }
+ /* do NOT execute this code if reassociation is enabled, it does the inverse! */
+ else if (get_opt_reassociation() && get_irn_op(a) == op_Mul) {
+ 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);
+ }
+ 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;
+}
+
+/**
+ * Transform Mul(a,-1) into -a.
+ * Do architecture dependent optimizations on Mul nodes
+ */
+static ir_node *transform_node_Mul(ir_node *n) {
+ ir_node *oldn = n;
+ ir_mode *mode = get_irn_mode(n);
+
+ if (mode_is_signed(mode)) {
+ ir_node *r = NULL;
+ ir_node *a = get_Mul_left(n);
+ ir_node *b = get_Mul_right(n);
+
+ 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;
+ }
+ }
+ return arch_dep_replace_mul_with_shifts(n);
+}
+
+/**
+ * transform a Div Node
+ */