re PR tree-optimization/15256 ([tree-ssa] Optimize manual bitfield manipilation.)
authorRichard Guenther <rguenther@suse.de>
Wed, 11 May 2011 14:13:38 +0000 (14:13 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Wed, 11 May 2011 14:13:38 +0000 (14:13 +0000)
2011-05-11  Richard Guenther  <rguenther@suse.de>

PR tree-optimization/15256
* tree-ssa-forwprop.c (simplify_bitwise_binary): Canonicalize
(A & B) | C, combine (A op CST1) op CST2.
(tree_ssa_forward_propagate_single_use_vars): Only bother to
visit assigns that have uses.

* gcc.dg/tree-ssa/forwprop-14.c: New testcase.

From-SVN: r173659

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/forwprop-14.c [new file with mode: 0644]
gcc/tree-ssa-forwprop.c

index d4db4ef00a83143a912b5059fee5060d3c71b5d8..09654faf15d75075142d12e88a581c60b76f4755 100644 (file)
@@ -1,3 +1,11 @@
+2011-05-11  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/15256
+       * tree-ssa-forwprop.c (simplify_bitwise_binary): Canonicalize
+       (A & B) | C, combine (A op CST1) op CST2.
+       (tree_ssa_forward_propagate_single_use_vars): Only bother to
+       visit assigns that have uses.
+
 2011-05-11  Nathan Froyd  <froydnj@codesourcery.com>
 
        * ggc-page.c (extra_order_size_table): Use struct
index 5fde36e00a3bc685d799c311adc9fa2b92c128b9..a7e2261fa190413013c1979540f9708f6bd12b2f 100644 (file)
@@ -1,3 +1,8 @@
+2011-05-11  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/15256
+       * gcc.dg/tree-ssa/forwprop-14.c: New testcase.
+
 2011-05-11  Jakub Jelinek  <jakub@redhat.com>
 
        PR debug/48159
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-14.c b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-14.c
new file mode 100644 (file)
index 0000000..7432e0d
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-optimized" } */
+
+unsigned int
+foo (unsigned int eax)
+{
+  eax |= 4;
+  eax &= 247;
+  eax |= 16;
+  eax &= 223;
+  eax |= 64;
+  eax &= 127;
+  return eax;
+}
+
+/* { dg-final { scan-tree-dump-times " & " 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " \\\| " 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
index 02d9523886609f63f565361b176db5df24a3d46d..605547081e4f06a352bf34c327e50a899be61630 100644 (file)
@@ -1623,6 +1623,9 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
   tree arg2 = gimple_assign_rhs2 (stmt);
   enum tree_code code = gimple_assign_rhs_code (stmt);
   tree res;
+  gimple def1 = NULL, def2 = NULL;
+  tree def1_arg1, def2_arg1;
+  enum tree_code def1_code, def2_code;
 
   /* If the first argument is an SSA name that is itself a result of a
      typecast of an ADDR_EXPR to an integer, feed the ADDR_EXPR to the
@@ -1655,44 +1658,102 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
        }
     }
 
+  def1_code = TREE_CODE (arg1);
+  def1_arg1 = arg1;
+  if (TREE_CODE (arg1) == SSA_NAME)
+    {
+      def1 = SSA_NAME_DEF_STMT (arg1);
+      if (is_gimple_assign (def1))
+       {
+         def1_code = gimple_assign_rhs_code (def1);
+         def1_arg1 = gimple_assign_rhs1 (def1);
+       }
+    }
+
+  def2_code = TREE_CODE (arg2);
+  def2_arg1 = arg2;
+  if (TREE_CODE (arg2) == SSA_NAME)
+    {
+      def2 = SSA_NAME_DEF_STMT (arg2);
+      if (is_gimple_assign (def2))
+       {
+         def2_code = gimple_assign_rhs_code (def2);
+         def2_arg1 = gimple_assign_rhs1 (def2);
+       }
+    }
+
   /* For bitwise binary operations apply operand conversions to the
      binary operation result instead of to the operands.  This allows
      to combine successive conversions and bitwise binary operations.  */
-  if (TREE_CODE (arg1) == SSA_NAME
-      && TREE_CODE (arg2) == SSA_NAME)
+  if (CONVERT_EXPR_CODE_P (def1_code)
+      && CONVERT_EXPR_CODE_P (def2_code)
+      && types_compatible_p (TREE_TYPE (def1_arg1), TREE_TYPE (def2_arg1))
+      /* Make sure that the conversion widens the operands or that it
+        changes the operation to a bitfield precision.  */
+      && ((TYPE_PRECISION (TREE_TYPE (def1_arg1))
+          < TYPE_PRECISION (TREE_TYPE (arg1)))
+         || (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (arg1)))
+             != MODE_INT)
+         || (TYPE_PRECISION (TREE_TYPE (arg1))
+             != GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (arg1))))))
     {
-      gimple def_stmt1 = SSA_NAME_DEF_STMT (arg1);
-      gimple def_stmt2 = SSA_NAME_DEF_STMT (arg2);
-      if (is_gimple_assign (def_stmt1)
-         && is_gimple_assign (def_stmt2)
-         && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt1))
-         && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt2)))
+      gimple newop;
+      tree tem = create_tmp_reg (TREE_TYPE (def1_arg1),
+                                NULL);
+      newop = gimple_build_assign_with_ops (code, tem, def1_arg1, def2_arg1);
+      tem = make_ssa_name (tem, newop);
+      gimple_assign_set_lhs (newop, tem);
+      gsi_insert_before (gsi, newop, GSI_SAME_STMT);
+      gimple_assign_set_rhs_with_ops_1 (gsi, NOP_EXPR,
+                                       tem, NULL_TREE, NULL_TREE);
+      update_stmt (gsi_stmt (*gsi));
+      return true;
+    }
+
+  /* (a | CST1) & CST2  ->  (a & CST2) | (CST1 & CST2).  */
+  if (code == BIT_AND_EXPR
+      && def1_code == BIT_IOR_EXPR
+      && TREE_CODE (arg2) == INTEGER_CST
+      && TREE_CODE (gimple_assign_rhs2 (def1)) == INTEGER_CST)
+    {
+      tree cst = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg2),
+                             arg2, gimple_assign_rhs2 (def1));
+      tree tem;
+      gimple newop;
+      if (integer_zerop (cst))
        {
-         tree darg1 = gimple_assign_rhs1 (def_stmt1);
-         tree darg2 = gimple_assign_rhs1 (def_stmt2);
-         /* Make sure that the conversion widens the operands or that it
-            changes the operation to a bitfield precision.  */
-         if (types_compatible_p (TREE_TYPE (darg1), TREE_TYPE (darg2))
-             && ((TYPE_PRECISION (TREE_TYPE (darg1))
-                  < TYPE_PRECISION (TREE_TYPE (arg1)))
-                 || (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (arg1)))
-                     != MODE_INT)
-                 || (TYPE_PRECISION (TREE_TYPE (arg1))
-                     != GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (arg1))))))
-           {
-             gimple newop;
-             tree tem = create_tmp_reg (TREE_TYPE (darg1),
-                                        NULL);
-             newop = gimple_build_assign_with_ops (code, tem, darg1, darg2);
-             tem = make_ssa_name (tem, newop);
-             gimple_assign_set_lhs (newop, tem);
-             gsi_insert_before (gsi, newop, GSI_SAME_STMT);
-             gimple_assign_set_rhs_with_ops_1 (gsi, NOP_EXPR,
-                                               tem, NULL_TREE, NULL_TREE);
-             update_stmt (gsi_stmt (*gsi));
-             return true;
-           }
+         gimple_assign_set_rhs1 (stmt, def1_arg1);
+         update_stmt (stmt);
+         return true;
        }
+      tem = create_tmp_reg (TREE_TYPE (arg2), NULL);
+      newop = gimple_build_assign_with_ops (BIT_AND_EXPR,
+                                           tem, def1_arg1, arg2);
+      tem = make_ssa_name (tem, newop);
+      gimple_assign_set_lhs (newop, tem);
+      /* Make sure to re-process the new stmt as it's walking upwards.  */
+      gsi_insert_before (gsi, newop, GSI_NEW_STMT);
+      gimple_assign_set_rhs1 (stmt, tem);
+      gimple_assign_set_rhs2 (stmt, cst);
+      gimple_assign_set_rhs_code (stmt, BIT_IOR_EXPR);
+      update_stmt (stmt);
+      return true;
+    }
+
+  /* Combine successive equal operations with constants.  */
+  if ((code == BIT_AND_EXPR
+       || code == BIT_IOR_EXPR
+       || code == BIT_XOR_EXPR)
+      && def1_code == code 
+      && TREE_CODE (arg2) == INTEGER_CST
+      && TREE_CODE (gimple_assign_rhs2 (def1)) == INTEGER_CST)
+    {
+      tree cst = fold_build2 (code, TREE_TYPE (arg2),
+                             arg2, gimple_assign_rhs2 (def1));
+      gimple_assign_set_rhs1 (stmt, def1_arg1);
+      gimple_assign_set_rhs2 (stmt, cst);
+      update_stmt (stmt);
+      return true;
     }
 
   return false;
@@ -2171,7 +2232,8 @@ tree_ssa_forward_propagate_single_use_vars (void)
              tree rhs = gimple_assign_rhs1 (stmt);
              enum tree_code code = gimple_assign_rhs_code (stmt);
 
-             if (TREE_CODE (lhs) != SSA_NAME)
+             if (TREE_CODE (lhs) != SSA_NAME
+                 || has_zero_uses (lhs))
                {
                  gsi_next (&gsi);
                  continue;