localopt/lower_dw opt: a==b && c==d => (a^b)|(c^d)==0
[libfirm] / ir / ir / iropt.c
index 541e406..111d1b3 100644 (file)
@@ -2951,20 +2951,21 @@ static ir_node *transform_node_And(ir_node *n)
                        ir_relation new_relation = a_relation & b_relation;
                        return new_rd_Cmp(dbgi, block, a_left, a_right, new_relation);
                }
-               /* Cmp(a==0) and Cmp(b==0) can be optimized to Cmp(a|b==0) */
-               if (is_Const(a_right) && is_Const_null(a_right)
-                               && is_Const(b_right) && is_Const_null(b_right)
-                               && a_relation == b_relation && a_relation == ir_relation_equal
-                               && !mode_is_float(get_irn_mode(a_left))
-                               && !mode_is_float(get_irn_mode(b_left))) {
-                       dbg_info *dbgi     = get_irn_dbg_info(n);
-                       ir_node  *block    = get_nodes_block(n);
-                       ir_mode  *mode     = get_irn_mode(a_left);
-                       ir_node  *n_b_left = get_irn_mode(b_left) != mode ?
-                               new_rd_Conv(dbgi, block, b_left, mode) : b_left;
-                       ir_node  *or       = new_rd_Or(dbgi, block, a_left, n_b_left, mode);
-                       ir_graph *irg      = get_irn_irg(n);
-                       ir_node  *zero     = create_zero_const(irg, mode);
+               /* Cmp(a==b) and Cmp(c==d) can be optimized to Cmp((a^b)|(c^d)==0) */
+               if (a_relation == b_relation && a_relation == ir_relation_equal
+                   && !mode_is_float(get_irn_mode(a_left))
+                   && !mode_is_float(get_irn_mode(b_left))
+                   && values_in_mode(get_irn_mode(a_left), get_irn_mode(b_left))) {
+                       dbg_info *dbgi   = get_irn_dbg_info(n);
+                       ir_node  *block  = get_nodes_block(n);
+                       ir_mode  *a_mode = get_irn_mode(a_left);
+                       ir_mode  *b_mode = get_irn_mode(b_left);
+                       ir_node  *xora   = new_rd_Eor(dbgi, block, a_left, a_right, a_mode);
+                       ir_node  *xorb   = new_rd_Eor(dbgi, block, b_left, b_right, b_mode);
+                       ir_node  *conv   = new_rd_Conv(dbgi, block, xorb, a_mode);
+                       ir_node  *or     = new_rd_Or(dbgi, block, xora, conv, a_mode);
+                       ir_graph *irg    = get_irn_irg(n);
+                       ir_node  *zero   = create_zero_const(irg, a_mode);
                        return new_rd_Cmp(dbgi, block, or, zero, ir_relation_equal);
                }
        }
@@ -4659,20 +4660,19 @@ static ir_node *transform_node_Or_Rotl(ir_node *irn_or)
        return n;
 }  /* transform_node_Or_Rotl */
 
-static bool is_cmp_unequal_zero(const ir_node *node)
+static bool is_cmp_unequal(const ir_node *node)
 {
        ir_relation relation = get_Cmp_relation(node);
        ir_node    *left     = get_Cmp_left(node);
        ir_node    *right    = get_Cmp_right(node);
        ir_mode    *mode     = get_irn_mode(left);
 
-       if (!is_Const(right) || !is_Const_null(right))
-               return false;
-       if (mode_is_signed(mode)) {
-               return relation == ir_relation_less_greater;
-       } else {
+       if (relation == ir_relation_less_greater)
+               return true;
+
+       if (!mode_is_signed(mode) && is_Const(right) && is_Const_null(right))
                return relation == ir_relation_greater;
-       }
+       return false;
 }
 
 /**
@@ -4712,18 +4712,21 @@ static ir_node *transform_node_Or(ir_node *n)
                        ir_relation new_relation = a_relation | b_relation;
                        return new_rd_Cmp(dbgi, block, a_left, a_right, new_relation);
                }
-               /* Cmp(a!=0) or Cmp(b!=0) => Cmp(a|b != 0) */
-               if (is_cmp_unequal_zero(a) && is_cmp_unequal_zero(b)
-                               && !mode_is_float(get_irn_mode(a_left))
-                               && !mode_is_float(get_irn_mode(b_left))) {
-                       ir_graph *irg      = get_irn_irg(n);
-                       dbg_info *dbgi     = get_irn_dbg_info(n);
-                       ir_node  *block    = get_nodes_block(n);
-                       ir_mode  *mode     = get_irn_mode(a_left);
-                       ir_node  *n_b_left = get_irn_mode(b_left) != mode ?
-                               new_rd_Conv(dbgi, block, b_left, mode) : b_left;
-                       ir_node  *or   = new_rd_Or(dbgi, block, a_left, n_b_left, mode);
-                       ir_node  *zero = create_zero_const(irg, mode);
+               /* Cmp(a!=b) or Cmp(c!=d) => Cmp((a^b)|(c^d) != 0) */
+               if (is_cmp_unequal(a) && is_cmp_unequal(b)
+                   && !mode_is_float(get_irn_mode(a_left))
+                   && !mode_is_float(get_irn_mode(b_left))
+                   && values_in_mode(get_irn_mode(a_left), get_irn_mode(b_left))) {
+                       ir_graph *irg    = get_irn_irg(n);
+                       dbg_info *dbgi   = get_irn_dbg_info(n);
+                       ir_node  *block  = get_nodes_block(n);
+                       ir_mode  *a_mode = get_irn_mode(a_left);
+                       ir_mode  *b_mode = get_irn_mode(b_left);
+                       ir_node  *xora   = new_rd_Eor(dbgi, block, a_left, a_right, a_mode);
+                       ir_node  *xorb   = new_rd_Eor(dbgi, block, b_left, b_right, b_mode);
+                       ir_node  *conv   = new_rd_Conv(dbgi, block, xorb, a_mode);
+                       ir_node  *or     = new_rd_Or(dbgi, block, xora, conv, a_mode);
+                       ir_node  *zero   = create_zero_const(irg, a_mode);
                        return new_rd_Cmp(dbgi, block, or, zero, ir_relation_less_greater);
                }
        }