tree-ssa-forwprop.c (truth_valued_ssa_name): New function.
authorKai Tietz <ktietz@redhat.com>
Thu, 7 Jul 2011 14:16:44 +0000 (16:16 +0200)
committerKai Tietz <ktietz@gcc.gnu.org>
Thu, 7 Jul 2011 14:16:44 +0000 (16:16 +0200)
2011-07-07  Kai Tietz  <ktietz@redhat.com>

        * tree-ssa-forwprop.c (truth_valued_ssa_name): New function.
        (lookup_logical_inverted_value): Likewise.
        (simplify_bitwise_binary_1): Likewise.
        (simplify_bitwise_binary): Use simplify_bitwise_binary_1.

2011-07-07  Kai Tietz  <ktietz@redhat.com>

        * gcc.dg/binop-notxor1.c: New test.
        * gcc.dg/binop-notand4a.c: New test.
        * gcc.dg/binop-notxor2.c: New test.
        * gcc.dg/binop-notand3a.c: New test.
        * gcc.dg/binop-notand2a.c: New test.
        * gcc.dg/binop-notand6a.c: New test.
        * gcc.dg/binop-notor1.c: New test.
        * gcc.dg/binop-notand1a.c: New test.
        * gcc.dg/binop-notand5a.c: New test.
        * gcc.dg/binop-notor2.c: New test.

From-SVN: r175974

13 files changed:
gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/binop-notand1a.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/binop-notand2a.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/binop-notand3a.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/binop-notand4a.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/binop-notand5a.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/binop-notand6a.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/binop-notor1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/binop-notor2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/binop-notxor1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/binop-notxor2.c [new file with mode: 0644]
gcc/tree-ssa-forwprop.c

index b2be0973cb0d998104cddec5d80d1767f2b7ca2a..09a817a1e94f6b125fe59e5edd818f3429b1f91c 100644 (file)
@@ -1,3 +1,10 @@
+2011-07-07  Kai Tietz  <ktietz@redhat.com>
+
+       * tree-ssa-forwprop.c (truth_valued_ssa_name): New function.
+       (lookup_logical_inverted_value): Likewise.
+       (simplify_bitwise_binary_1): Likewise.
+       (simplify_bitwise_binary): Use simplify_bitwise_binary_1.
+
 2011-07-07  Joseph Myers  <joseph@codesourcery.com>
 
        * gcc.c (%[Spec]): Don't document.
index e54290995d87711f37ee278b7540bedd08f67293..e73b5ea428a17450016255911c2a316f0a1cd33c 100644 (file)
@@ -1,3 +1,16 @@
+2011-07-07  Kai Tietz  <ktietz@redhat.com>
+
+       * gcc.dg/binop-notxor1.c: New test.
+       * gcc.dg/binop-notand4a.c: New test.
+       * gcc.dg/binop-notxor2.c: New test.
+       * gcc.dg/binop-notand3a.c: New test.
+       * gcc.dg/binop-notand2a.c: New test.
+       * gcc.dg/binop-notand6a.c: New test.
+       * gcc.dg/binop-notor1.c: New test.
+       * gcc.dg/binop-notand1a.c: New test.
+       * gcc.dg/binop-notand5a.c: New test.
+       * gcc.dg/binop-notor2.c: New test.
+
 2011-07-07  Jakub Jelinek  <jakub@redhat.com>
 
        PR middle-end/49640
diff --git a/gcc/testsuite/gcc.dg/binop-notand1a.c b/gcc/testsuite/gcc.dg/binop-notand1a.c
new file mode 100644 (file)
index 0000000..2d8202a
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (char a, unsigned short b)
+{
+  return (a & !a) | (b & !b);
+}
+
+/* As long as comparisons aren't boolified and casts from boolean-types
+   aren't preserved, the folding of  X & !X to zero fails.  */
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" { xfail *-*-* } } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/binop-notand2a.c b/gcc/testsuite/gcc.dg/binop-notand2a.c
new file mode 100644 (file)
index 0000000..0076d4b
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (int a)
+{
+  return (!a & 1) != (a == 0);
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/binop-notand3a.c b/gcc/testsuite/gcc.dg/binop-notand3a.c
new file mode 100644 (file)
index 0000000..40e8038
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (short a)
+{
+  return (!a & 1) != ((a == 0) & 1);
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/binop-notand4a.c b/gcc/testsuite/gcc.dg/binop-notand4a.c
new file mode 100644 (file)
index 0000000..1178cf7
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (unsigned char a, _Bool b)
+{
+  return (!a & a) | (b & !b);
+}
+
+/* As long as comparisons aren't boolified and casts from boolean-types
+   aren't preserved, the folding of  X & !X to zero fails.  */
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" { xfail *-*-* } } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/binop-notand5a.c b/gcc/testsuite/gcc.dg/binop-notand5a.c
new file mode 100644 (file)
index 0000000..289abcb
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (long a, unsigned long b)
+{
+  return (a & (a == 0)) | (b & !b);
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/binop-notand6a.c b/gcc/testsuite/gcc.dg/binop-notand6a.c
new file mode 100644 (file)
index 0000000..b9fe405
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (unsigned long a, long b)
+{
+  return (a & !a) | (b & (b == 0));
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/binop-notor1.c b/gcc/testsuite/gcc.dg/binop-notor1.c
new file mode 100644 (file)
index 0000000..a2cb6a3
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (_Bool a, _Bool b)
+{
+  return (a | !a) | (!b | b);
+}
+
+/* { dg-final { scan-tree-dump-times "return 1" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/binop-notor2.c b/gcc/testsuite/gcc.dg/binop-notor2.c
new file mode 100644 (file)
index 0000000..ab8d70e
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (_Bool a, _Bool b)
+{
+  return (a | (a == 0)) | ((b ^ 1) | b);
+}
+
+/* { dg-final { scan-tree-dump-times "return 1" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/binop-notxor1.c b/gcc/testsuite/gcc.dg/binop-notxor1.c
new file mode 100644 (file)
index 0000000..39c258d
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (_Bool a, _Bool b)
+{
+  return (a ^ !a) | (!b ^ b);
+}
+
+/* { dg-final { scan-tree-dump-times "return 1" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/binop-notxor2.c b/gcc/testsuite/gcc.dg/binop-notxor2.c
new file mode 100644 (file)
index 0000000..9f34cf2
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (_Bool a, _Bool b)
+{
+  return (a ^ (a == 0)) | ((b == 0) ^ b);
+}
+
+/* { dg-final { scan-tree-dump-times "return 1" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
index 893f17b47a4082775aac19ce640cdf5299e0e152..8e6b7040af0aaa12dc59ad99ceb2adf9e427782e 100644 (file)
@@ -1602,6 +1602,129 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
   return false;
 }
 
+/* Checks if expression has type of one-bit precision, or is a known
+   truth-valued expression.  */
+static bool
+truth_valued_ssa_name (tree name)
+{
+  gimple def;
+  tree type = TREE_TYPE (name);
+
+  if (!INTEGRAL_TYPE_P (type))
+    return false;
+  /* Don't check here for BOOLEAN_TYPE as the precision isn't
+     necessarily one and so ~X is not equal to !X.  */
+  if (TYPE_PRECISION (type) == 1)
+    return true;
+  def = SSA_NAME_DEF_STMT (name);
+  if (is_gimple_assign (def))
+    return truth_value_p (gimple_assign_rhs_code (def));
+  return false;
+}
+
+/* Helper routine for simplify_bitwise_binary_1 function.
+   Return for the SSA name NAME the expression X if it mets condition
+   NAME = !X. Otherwise return NULL_TREE.
+   Detected patterns for NAME = !X are:
+     !X and X == 0 for X with integral type.
+     X ^ 1, X != 1,or ~X for X with integral type with precision of one.  */
+static tree
+lookup_logical_inverted_value (tree name)
+{
+  tree op1, op2;
+  enum tree_code code;
+  gimple def;
+
+  /* If name has none-intergal type, or isn't a SSA_NAME, then
+     return.  */
+  if (TREE_CODE (name) != SSA_NAME
+      || !INTEGRAL_TYPE_P (TREE_TYPE (name)))
+    return NULL_TREE;
+  def = SSA_NAME_DEF_STMT (name);
+  if (!is_gimple_assign (def))
+    return NULL_TREE;
+
+  code = gimple_assign_rhs_code (def);
+  op1 = gimple_assign_rhs1 (def);
+  op2 = NULL_TREE;
+
+  /* Get for EQ_EXPR or BIT_XOR_EXPR operation the second operand.
+     If CODE isn't an EQ_EXPR, BIT_XOR_EXPR, TRUTH_NOT_EXPR,
+     or BIT_NOT_EXPR, then return.  */
+  if (code == EQ_EXPR || code == NE_EXPR
+      || code == BIT_XOR_EXPR)
+    op2 = gimple_assign_rhs2 (def);
+
+  switch (code)
+    {
+    case TRUTH_NOT_EXPR:
+      return op1;
+    case BIT_NOT_EXPR:
+      if (truth_valued_ssa_name (name))
+       return op1;
+      break;
+    case EQ_EXPR:
+      /* Check if we have X == 0 and X has an integral type.  */
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (op1)))
+       break;
+      if (integer_zerop (op2))
+       return op1;
+      break;
+    case NE_EXPR:
+      /* Check if we have X != 1 and X is a truth-valued.  */
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (op1)))
+       break;
+      if (integer_onep (op2) && truth_valued_ssa_name (op1))
+       return op1;
+      break;
+    case BIT_XOR_EXPR:
+      /* Check if we have X ^ 1 and X is truth valued.  */
+      if (integer_onep (op2) && truth_valued_ssa_name (op1))
+       return op1;
+      break;
+    default:
+      break;
+    }
+
+  return NULL_TREE;
+}
+
+/* Optimize ARG1 CODE ARG2 to a constant for bitwise binary
+   operations CODE, if one operand has the logically inverted
+   value of the other.  */
+static tree
+simplify_bitwise_binary_1 (enum tree_code code, tree type,
+                          tree arg1, tree arg2)
+{
+  tree anot;
+
+  /* If CODE isn't a bitwise binary operation, return NULL_TREE.  */
+  if (code != BIT_AND_EXPR && code != BIT_IOR_EXPR
+      && code != BIT_XOR_EXPR)
+    return NULL_TREE;
+
+  /* First check if operands ARG1 and ARG2 are equal.  If so
+     return NULL_TREE as this optimization is handled fold_stmt.  */
+  if (arg1 == arg2)
+    return NULL_TREE;
+  /* See if we have in arguments logical-not patterns.  */
+  if (((anot = lookup_logical_inverted_value (arg1)) == NULL_TREE
+       || anot != arg2)
+      && ((anot = lookup_logical_inverted_value (arg2)) == NULL_TREE
+         || anot != arg1))
+    return NULL_TREE;
+
+  /* X & !X -> 0.  */
+  if (code == BIT_AND_EXPR)
+    return fold_convert (type, integer_zero_node);
+  /* X | !X -> 1 and X ^ !X -> 1, if X is truth-valued.  */
+  if (truth_valued_ssa_name (anot))
+    return fold_convert (type, integer_one_node);
+
+  /* ??? Otherwise result is (X != 0 ? X : 1).  not handled.  */
+  return NULL_TREE;
+}
+
 /* Simplify bitwise binary operations.
    Return true if a transformation applied, otherwise return false.  */
 
@@ -1769,6 +1892,15 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
       return true;
     }
 
+  /* Try simple folding for X op !X, and X op X.  */
+  res = simplify_bitwise_binary_1 (code, TREE_TYPE (arg1), arg1, arg2);
+  if (res != NULL_TREE)
+    {
+      gimple_assign_set_rhs_from_tree (gsi, res);
+      update_stmt (gsi_stmt (*gsi));
+      return true;
+    }
+
   return false;
 }