fix incorrect and(Cmp(a,0),Cmp(b,0)) localopt
authorMatthias Braun <matze@braunis.de>
Wed, 13 Apr 2011 10:26:08 +0000 (12:26 +0200)
committerMatthias Braun <matze@braunis.de>
Wed, 13 Apr 2011 10:26:31 +0000 (12:26 +0200)
include/libfirm/iropt.h
ir/ir/iropt.c
ir/lower/lower_dw.c

index 9e25788..9d1f1a1 100644 (file)
@@ -103,13 +103,6 @@ FIRM_API int ir_is_negated_value(const ir_node *a, const ir_node *b);
 FIRM_API ir_relation ir_get_possible_cmp_relations(const ir_node *left,
                                                    const ir_node *right);
 
-/**
- * tests whether a given Cmp node is a non-floating point equal/not-equal test with 0
- * (this is a bit tricky because it has to catch x!=0 for the signed case and
- *  x>0 for the unsigned case)
- */
-FIRM_API int ir_is_equality_cmp_0(const ir_node *node);
-
 #include "end.h"
 
 #endif
index ab5b63a..03eeb57 100644 (file)
@@ -3107,27 +3107,6 @@ static ir_node *transform_bitwise_distributive(ir_node *n,
        return n;
 }
 
-int ir_is_equality_cmp_0(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);
-
-       /* this probably makes no sense if unordered is involved */
-       assert(!mode_is_float(mode));
-
-       if (!is_Const(right) || !is_Const_null(right))
-               return false;
-       if (relation == ir_relation_equal)
-               return true;
-       if (mode_is_signed(mode)) {
-               return relation == ir_relation_less_greater;
-       } else {
-               return relation == ir_relation_greater;
-       }
-}
-
 /**
  * Create a 0 constant of given mode.
  */
@@ -3151,33 +3130,35 @@ static ir_node *transform_node_And(ir_node *n)
        vrp_attr *a_vrp, *b_vrp;
 
        if (is_Cmp(a) && is_Cmp(b)) {
-               ir_node *a_left  = get_Cmp_left(a);
-               ir_node *a_right = get_Cmp_left(a);
-               ir_node *b_left  = get_Cmp_left(b);
-               ir_node *b_right = get_Cmp_right(b);
+               ir_node    *a_left     = get_Cmp_left(a);
+               ir_node    *a_right    = get_Cmp_right(a);
+               ir_node    *b_left     = get_Cmp_left(b);
+               ir_node    *b_right    = get_Cmp_right(b);
+               ir_relation a_relation = get_Cmp_relation(a);
+               ir_relation b_relation = get_Cmp_relation(b);
                /* we can combine the relations of two compares with the same
                 * operands */
                if (a_left == b_left && b_left == b_right) {
                        dbg_info   *dbgi         = get_irn_dbg_info(n);
                        ir_node    *block        = get_nodes_block(n);
-                       ir_relation a_relation   = get_Cmp_relation(a);
-                       ir_relation b_relation   = get_Cmp_relation(b);
                        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 (ir_is_equality_cmp_0(a) && ir_is_equality_cmp_0(b)
-                               && (get_Cmp_relation(a) & ir_relation_equal) == (get_Cmp_relation(b) & ir_relation_equal)) {
-                       dbg_info    *dbgi     = get_irn_dbg_info(n);
-                       ir_node     *block    = get_nodes_block(n);
-                       ir_relation  relation = get_Cmp_relation(a);
-                       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);
-                       return new_rd_Cmp(dbgi, block, or, zero, 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);
+                       return new_rd_Cmp(dbgi, block, or, zero, ir_relation_equal);
                }
        }
 
@@ -4821,6 +4802,22 @@ 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)
+{
+       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 {
+               return relation == ir_relation_greater;
+       }
+}
+
 /**
  * Transform an Or.
  */
@@ -4858,6 +4855,20 @@ 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);
+                       return new_rd_Cmp(dbgi, block, or, zero, ir_relation_less_greater);
+               }
        }
 
        mode = get_irn_mode(n);
index 4c4ab33..ca5b096 100644 (file)
@@ -982,6 +982,27 @@ static void lower_Not(ir_node *node, ir_mode *mode, lower_env_t *env)
        set_lowered(env, node, res_low, res_high);
 }
 
+static bool is_equality_cmp_0(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);
+
+       /* this probably makes no sense if unordered is involved */
+       assert(!mode_is_float(mode));
+
+       if (!is_Const(right) || !is_Const_null(right))
+               return false;
+       if (relation == ir_relation_equal)
+               return true;
+       if (mode_is_signed(mode)) {
+               return relation == ir_relation_less_greater;
+       } else {
+               return relation == ir_relation_greater;
+       }
+}
+
 /**
  * Translate a Cond.
  */
@@ -1052,7 +1073,7 @@ static void lower_Cond(ir_node *node, ir_mode *mode, lower_env_t *env)
        dbg      = get_irn_dbg_info(sel);
        relation = get_Cmp_relation(sel);
 
-       if (ir_is_equality_cmp_0(sel)) {
+       if (is_equality_cmp_0(sel)) {
                /* x ==/!= 0 ==> or(low,high) ==/!= 0 */
                ir_mode *mode   = env->low_unsigned;
                ir_node *low    = new_r_Conv(block, lentry->low_word, mode);
@@ -1320,7 +1341,7 @@ static void lower_Cmp(ir_node *cmp, ir_mode *m, lower_env_t *env)
        dbg      = get_irn_dbg_info(cmp);
 
        /* easy case for x ==/!= 0 (see lower_Cond for details) */
-       if (ir_is_equality_cmp_0(cmp)) {
+       if (is_equality_cmp_0(cmp)) {
                ir_graph *irg     = get_irn_irg(cmp);
                ir_mode  *mode    = env->low_unsigned;
                ir_node  *low     = new_r_Conv(block, lentry->low_word, mode);