+ br = new_rd_Not(dbg, block, br, mode);
+ n = new_rd_And(dbg, 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, block, bl, mode);
+ n = new_rd_And(dbg, 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), block, a, b, mode);
+ n = new_rd_Not(get_irn_dbg_info(n), block, n, mode);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_DEMORGAN);
+ return n;
+ }
+
+ if (is_Const(a)) {
+ vrp_attr *b_vrp = vrp_get_info(b);
+ ir_tarval *a_val = get_Const_tarval(a);
+ if (b_vrp != NULL && tarval_or(a_val, b_vrp->bits_not_set) == a_val) {
+ return b;
+ }
+ }
+
+ if (is_Const(b)) {
+ vrp_attr *a_vrp = vrp_get_info(a);
+ ir_tarval *b_val = get_Const_tarval(b);
+ if (a_vrp != NULL && tarval_or(b_val, a_vrp->bits_not_set) == b_val) {
+ return a;
+ }
+ }
+
+ n = transform_bitwise_distributive(n, transform_node_And);
+ if (is_And(n))
+ n = transform_node_bitop_shift(n);
+
+ return n;
+}
+
+/**
+ * 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 (is_Cmp(a)) {
+ dbg_info *dbgi = get_irn_dbg_info(a);
+ ir_node *block = get_nodes_block(a);
+ ir_relation relation = get_Cmp_relation(a);
+ relation = get_negated_relation(relation);
+ n = new_rd_Cmp(dbgi, block, get_Cmp_left(a), get_Cmp_right(a), relation);
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_NOT_CMP);
+ return n;
+ }
+
+ /* normalize ~(a ^ b) => a ^ ~b */
+ if (is_Eor(a) || is_Or_Eor_Add(a)) {
+ dbg_info *dbg = get_irn_dbg_info(n);
+ ir_node *block = get_nodes_block(n);
+ ir_node *eor_right = get_binop_right(a);
+ ir_node *eor_left = get_binop_left(a);
+ eor_right = new_rd_Not(dbg, block, eor_right, mode);
+ n = new_rd_Eor(dbg, block, eor_left, eor_right, 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 = get_irn_irg(n);
+ ir_node *block = get_nodes_block(n);
+ ir_node *add_l = get_Minus_op(a);
+ ir_node *add_r = new_rd_Const(dbg, irg, get_mode_minus_one(mode));
+ n = new_rd_Add(dbg, block, add_l, add_r, mode);
+ } else if (is_Add(a) || is_Or_Eor_Add(a)) {
+ ir_node *add_r = get_binop_right(a);
+ if (is_Const(add_r) && is_Const_all_one(add_r)) {
+ /* ~(x + -1) = -x */
+ ir_node *op = get_binop_left(a);
+ ir_node *blk = get_nodes_block(n);
+ n = new_rd_Minus(get_irn_dbg_info(n), blk, op, get_irn_mode(n));
+ DBG_OPT_ALGSIM0(oldn, n, FS_OPT_NOT_MINUS_1);
+ }
+ }
+ }
+ return n;
+}
+
+/**
+ * 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);
+ ir_tarval *tv = get_mode_one(mode);
+ ir_node *blk = get_nodes_block(n);
+ ir_graph *irg = get_irn_irg(blk);
+ ir_node *c = new_r_Const(irg, tv);
+ n = new_rd_Add(get_irn_dbg_info(n), 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)) {
+ ir_tarval *tv = get_Const_tarval(c);
+
+ if (tarval_is_long(tv) && get_tarval_long(tv) == (int) 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), get_nodes_block(n), 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)) {
+ ir_tarval *tv = get_Const_tarval(c);
+
+ if (tarval_is_long(tv) && get_tarval_long(tv) == (int) 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), get_nodes_block(n), 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_nodes_block(n);
+
+ n = new_rd_Sub(get_irn_dbg_info(n), 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);
+ ir_tarval *tv = value_of(mul_r);
+ if (tv != tarval_bad) {
+ tv = tarval_neg(tv);
+ if (tv != tarval_bad) {
+ ir_graph *irg = get_irn_irg(n);
+ ir_node *cnst = new_r_Const(irg, tv);
+ dbg_info *dbg = get_irn_dbg_info(a);
+ ir_node *block = get_nodes_block(a);
+ n = new_rd_Mul(dbg, block, mul_l, cnst, mode);
+ DBG_OPT_ALGSIM2(oldn, a, n, FS_OPT_MINUS_MUL_C);
+ return n;
+ }
+ }
+ }
+
+ return n;
+}
+
+/**
+ * Transform a Proj(Load) with a non-null address.
+ */
+static ir_node *transform_node_Proj_Load(ir_node *proj)
+{
+ if (get_irn_mode(proj) == mode_X) {
+ ir_node *load = get_Proj_pred(proj);
+
+ /* get the Load address */
+ const ir_node *addr = get_Load_ptr(load);
+ const ir_node *confirm;
+
+ if (value_not_null(addr, &confirm)) {
+ if (confirm == NULL) {
+ /* this node may float if it did not depend on a Confirm */
+ set_irn_pinned(load, op_pin_state_floats);
+ }
+ if (get_Proj_proj(proj) == pn_Load_X_except) {
+ ir_graph *irg = get_irn_irg(proj);
+ DBG_OPT_EXC_REM(proj);
+ return new_r_Bad(irg, mode_X);
+ } else {
+ ir_node *blk = get_nodes_block(load);
+ return new_r_Jmp(blk);
+ }
+ }
+ }
+ return proj;
+}
+
+/**
+ * Transform a Proj(Store) with a non-null address.
+ */
+static ir_node *transform_node_Proj_Store(ir_node *proj)
+{
+ if (get_irn_mode(proj) == mode_X) {
+ ir_node *store = get_Proj_pred(proj);
+
+ /* get the load/store address */
+ const ir_node *addr = get_Store_ptr(store);
+ const ir_node *confirm;
+
+ if (value_not_null(addr, &confirm)) {
+ if (confirm == NULL) {
+ /* this node may float if it did not depend on a Confirm */
+ set_irn_pinned(store, op_pin_state_floats);
+ }
+ if (get_Proj_proj(proj) == pn_Store_X_except) {
+ ir_graph *irg = get_irn_irg(proj);
+ DBG_OPT_EXC_REM(proj);
+ return new_r_Bad(irg, mode_X);
+ } else {
+ ir_node *blk = get_nodes_block(store);
+ return new_r_Jmp(blk);
+ }
+ }
+ }
+ return proj;
+}
+
+/**
+ * Transform a Proj(Div) with a non-zero value.
+ * Removes the exceptions and routes the memory to the NoMem node.
+ */
+static ir_node *transform_node_Proj_Div(ir_node *proj)
+{
+ ir_node *div = get_Proj_pred(proj);
+ ir_node *b = get_Div_right(div);
+ ir_node *res, *new_mem;
+ const ir_node *confirm;
+ long proj_nr;
+
+ if (value_not_zero(b, &confirm)) {
+ /* div(x, y) && y != 0 */
+ if (confirm == NULL) {
+ /* we are sure we have a Const != 0 */
+ new_mem = get_Div_mem(div);
+ new_mem = skip_Pin(new_mem);
+ set_Div_mem(div, new_mem);
+ set_irn_pinned(div, op_pin_state_floats);
+ }
+
+ proj_nr = get_Proj_proj(proj);
+ switch (proj_nr) {
+ case pn_Div_X_regular:
+ return new_r_Jmp(get_nodes_block(div));
+
+ case pn_Div_X_except: {
+ ir_graph *irg = get_irn_irg(proj);
+ /* we found an exception handler, remove it */
+ DBG_OPT_EXC_REM(proj);
+ return new_r_Bad(irg, mode_X);
+ }
+
+ case pn_Div_M: {
+ ir_graph *irg = get_irn_irg(proj);
+ res = get_Div_mem(div);
+ new_mem = get_irg_no_mem(irg);
+
+ if (confirm) {
+ /* This node can only float up to the Confirm block */
+ new_mem = new_r_Pin(get_nodes_block(confirm), new_mem);
+ }
+ set_irn_pinned(div, op_pin_state_floats);
+ /* this is a Div without exception, we can remove the memory edge */
+ set_Div_mem(div, new_mem);
+ return res;
+ }
+ }
+ }
+ return proj;
+}
+
+/**
+ * Transform a Proj(Mod) with a non-zero value.
+ * Removes the exceptions and routes the memory to the NoMem node.
+ */
+static ir_node *transform_node_Proj_Mod(ir_node *proj)
+{
+ ir_node *mod = get_Proj_pred(proj);
+ ir_node *b = get_Mod_right(mod);
+ ir_node *res, *new_mem;
+ const ir_node *confirm;
+ long proj_nr;