The notable changes since the last version:

First, it should properly handle signed single bit types, though I haven't tested it with real code.

Second, the transformation is only applied when the result is used in a conditional. Thus it's much less likely to pessimize targets with and-not instructions as it's highly likely we'll eliminate two gimple statements rather than just one.


Other comments (such as not needing to retrieve gsi_stmt) were also addressed. Testcase was renamed, but is otherwise unchanged.

Bootstrapped and regression tested on x86_64-unknown-linux-gnu.

OK for the trunk?
        * tree-ssa-forwprop.c (simplify_bitwise_binary_boolean): New function.
        (simplify_bitwise_binary): Use it to simpify certain binary ops on
        booleans.
    
        * gcc.dg/tree-ssa/forwprop-28.c: New test.


diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-28.c 
b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-28.c
new file mode 100644
index 0000000..2c42065
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-28.c
@@ -0,0 +1,76 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-forwprop1" } */
+
+extern char * frob (void);
+extern _Bool testit(void);
+
+test (int code)
+{
+  char * temp = frob();;
+  int rotate = (code == 22);
+  if (temp == 0 && !rotate)
+      oof();
+}
+
+test_2 (int code)
+{
+  char * temp = frob();
+  int rotate = (code == 22);
+  if (!rotate && temp == 0)
+      oof();
+}
+
+
+test_3 (int code)
+{
+  char * temp = frob();
+  int rotate = (code == 22);
+  if (!rotate || temp == 0)
+      oof();
+}
+
+
+test_4 (int code)
+{
+  char * temp = frob();
+  int rotate = (code == 22);
+  if (temp == 0 || !rotate)
+      oof();
+}
+
+
+test_5 (int code)
+{
+  _Bool temp = testit();;
+  _Bool rotate = (code == 22);
+  if (temp == 0 && !rotate)
+      oof();
+}
+
+test_6 (int code)
+{
+  _Bool temp = testit();
+  _Bool rotate = (code == 22);
+  if (!rotate && temp == 0)
+      oof();
+}
+
+
+test_7 (int code)
+{
+  _Bool temp = testit();
+  _Bool rotate = (code == 22);
+  if (!rotate || temp == 0)
+      oof();
+}
+
+
+test_8 (int code)
+{
+  _Bool temp = testit();
+  _Bool rotate = (code == 22);
+  if (temp == 0 || !rotate)
+      oof();
+}
+
+/* { dg-final { scan-tree-dump-times "Replaced" 8 "forwprop1"} } */
diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c
index c6a7eaf..29a0bb7 100644
--- a/gcc/tree-ssa-forwprop.c
+++ b/gcc/tree-ssa-forwprop.c
@@ -1870,6 +1870,52 @@ hoist_conversion_for_bitop_p (tree to, tree from)
   return false;
 }
 
+/* GSI points to a statement of the form
+
+   result = OP0 CODE OP1
+
+   Where OP0 and OP1 are single bit SSA_NAMEs and CODE is either
+   BIT_AND_EXPR or BIT_IOR_EXPR.
+
+   If OP0 is fed by a bitwise negation of another single bit SSA_NAME,
+   then we can simplify the two statements into a single LT_EXPR or LE_EXPR
+   when code is BIT_AND_EXPR and BIT_IOR_EXPR respectively.
+
+   If a simplification is mode, return TRUE, else return FALSE.  */
+static bool
+simplify_bitwise_binary_boolean (gimple_stmt_iterator *gsi,
+                                enum tree_code code,
+                                tree op0, tree op1)
+{
+  gimple op0_def_stmt = SSA_NAME_DEF_STMT (op0);
+
+  if (!is_gimple_assign (op0_def_stmt)
+      || (gimple_assign_rhs_code (op0_def_stmt) != BIT_NOT_EXPR))
+    return false;
+
+  tree x = gimple_assign_rhs1 (op0_def_stmt);
+  if (TREE_CODE (x) == SSA_NAME
+      && INTEGRAL_TYPE_P (TREE_TYPE (x))
+      && TYPE_PRECISION (TREE_TYPE (x)) == 1
+      && TYPE_UNSIGNED (TREE_TYPE (x)) == TYPE_UNSIGNED (TREE_TYPE (op1)))
+    {
+      enum tree_code newcode;
+
+      gimple stmt = gsi_stmt (*gsi);
+      gimple_assign_set_rhs1 (stmt, x);
+      gimple_assign_set_rhs2 (stmt, op1);
+      if (code == BIT_AND_EXPR)
+       newcode = TYPE_UNSIGNED (TREE_TYPE (x)) ? LT_EXPR : GT_EXPR;
+      else
+       newcode = TYPE_UNSIGNED (TREE_TYPE (x)) ? LE_EXPR : GE_EXPR;
+      gimple_assign_set_rhs_code (stmt, newcode); 
+      update_stmt (stmt);
+      return true;
+    }
+  return false;
+
+}
+
 /* Simplify bitwise binary operations.
    Return true if a transformation applied, otherwise return false.  */
 
@@ -2117,8 +2163,44 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
              return true;
            }
        }
-    }
 
+      /* If arg1 and arg2 are booleans (or any single bit type)
+         then try to simplify:
+
+          (~X & Y) -> X < Y
+          (X & ~Y) -> Y < X
+          (~X | Y) -> X <= Y
+          (X | ~Y) -> Y <= X 
+
+         But only do this if our result feeds into a comparison as
+         this transformation is not always a win, particularly on
+         targets with and-not instructions.  */
+      if (TREE_CODE (arg1) == SSA_NAME
+         && TREE_CODE (arg2) == SSA_NAME
+         && INTEGRAL_TYPE_P (TREE_TYPE (arg1))
+         && TYPE_PRECISION (TREE_TYPE (arg1)) == 1
+         && TYPE_PRECISION (TREE_TYPE (arg2)) == 1
+         && (TYPE_UNSIGNED (TREE_TYPE (arg1))
+             == TYPE_UNSIGNED (TREE_TYPE (arg2))))
+       {
+         use_operand_p use_p;
+          gimple use_stmt;
+
+         if (single_imm_use (gimple_assign_lhs (stmt), &use_p, &use_stmt))
+           {
+             if (gimple_code (use_stmt) == GIMPLE_COND
+                 && gimple_cond_lhs (use_stmt) == gimple_assign_lhs (stmt)
+                 && integer_zerop (gimple_cond_rhs (use_stmt))
+                 && gimple_cond_code (use_stmt) == NE_EXPR)
+               {
+                 if (simplify_bitwise_binary_boolean (gsi, code, arg1, arg2))
+                   return true;
+                 if (simplify_bitwise_binary_boolean (gsi, code, arg2, arg1))
+                   return true;
+               }
+           }
+       }
+    }
   return false;
 }
 

Reply via email to