re PR middle-end/18041 (OR of two single-bit bitfields is inefficient)
authorRichard Guenther <rguenther@suse.de>
Wed, 11 May 2011 10:52:57 +0000 (10:52 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Wed, 11 May 2011 10:52:57 +0000 (10:52 +0000)
2011-05-11  Richard Guenther  <rguenther@suse.de>

PR tree-optimization/18041
* tree-ssa-forwprop.c (simplify_bitwise_and): Rename to ...
(simplify_bitwise_binary): ... this.  Handle operand conversions
by applying them to the result instead.
(tree_ssa_forward_propagate_single_use_vars): Adjust.  CSE tree code.

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

From-SVN: r173650

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

index 77dd16db4c0dda51955f07aca61d737f8f2153d8..98795b8cdf908bba48cb78a83454ef0dead14f1e 100644 (file)
@@ -1,3 +1,11 @@
+2011-05-11  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/18041
+       * tree-ssa-forwprop.c (simplify_bitwise_and): Rename to ...
+       (simplify_bitwise_binary): ... this.  Handle operand conversions
+       by applying them to the result instead.
+       (tree_ssa_forward_propagate_single_use_vars): Adjust.  CSE tree code.
+
 2011-05-11  Richard Guenther  <rguenther@suse.de>
 
        * gimple.c (gimple_canonical_types_compatible_p): Split out
index 761b4af350d00a2a0c512e10af5a369069c625fd..becc9781918ef3cbb9ad48faaf1256610d066c0a 100644 (file)
@@ -1,3 +1,8 @@
+2011-05-11  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/18041
+       * gcc.dg/tree-ssa/forwprop-13.c: New testcase.
+
 2011-05-11  Alan Modra  <amodra@gmail.com>
 
        PR target/47755
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-13.c b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-13.c
new file mode 100644 (file)
index 0000000..aab4ff6
--- /dev/null
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-optimized" } */
+
+struct B {
+    unsigned bit0 : 1;
+    unsigned bit1 : 1;
+};
+
+void
+foo (struct B *b)
+{
+  b->bit0 = b->bit0 | b->bit1;
+}
+
+/* { dg-final { scan-tree-dump-not "\\\(unsigned" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
index 65e058d7231a3c7df6771ed7c427076bb57531f7..02d9523886609f63f565361b176db5df24a3d46d 100644 (file)
@@ -1612,44 +1612,90 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
   return false;
 }
 
-/* Run bitwise and assignments throug the folder.  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 folder rather than the ssa name.
-*/
+/* Simplify bitwise binary operations.
+   Return true if a transformation applied, otherwise return false.  */
 
-static void
-simplify_bitwise_and (gimple_stmt_iterator *gsi, gimple stmt)
+static bool
+simplify_bitwise_binary (gimple_stmt_iterator *gsi)
 {
-  tree res;
+  gimple stmt = gsi_stmt (*gsi);
   tree arg1 = gimple_assign_rhs1 (stmt);
   tree arg2 = gimple_assign_rhs2 (stmt);
+  enum tree_code code = gimple_assign_rhs_code (stmt);
+  tree res;
 
-  if (TREE_CODE (arg2) != INTEGER_CST)
-    return;
-
-  if (TREE_CODE (arg1) == SSA_NAME && !SSA_NAME_IS_DEFAULT_DEF (arg1))
+  /* 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
+     folder rather than the ssa name.  */
+  if (code == BIT_AND_EXPR
+      && TREE_CODE (arg2) == INTEGER_CST
+      && TREE_CODE (arg1) == SSA_NAME)
     {
       gimple def = SSA_NAME_DEF_STMT (arg1);
+      tree op = arg1;
 
-      if (gimple_assign_cast_p (def)
-         && INTEGRAL_TYPE_P (gimple_expr_type (def)))
+      /* ???  This looks bogus - the conversion could be truncating.  */
+      if (is_gimple_assign (def)
+         && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def))
+         && INTEGRAL_TYPE_P (TREE_TYPE (arg1)))
        {
-         tree op = gimple_assign_rhs1 (def);
+         tree opp = gimple_assign_rhs1 (def);
+         if (TREE_CODE (opp) == ADDR_EXPR)
+           op = opp;
+       }
 
-         if (TREE_CODE (op) == ADDR_EXPR)
-           arg1 = op;
+      res = fold_binary_loc (gimple_location (stmt),
+                            BIT_AND_EXPR, TREE_TYPE (gimple_assign_lhs (stmt)),
+                            op, arg2);
+      if (res && is_gimple_min_invariant (res))
+       {
+         gimple_assign_set_rhs_from_tree (gsi, res);
+         update_stmt (stmt);
+         return true;
        }
     }
 
-  res = fold_binary_loc (gimple_location (stmt),
-                    BIT_AND_EXPR, TREE_TYPE (gimple_assign_lhs (stmt)),
-                    arg1, arg2);
-  if (res && is_gimple_min_invariant (res))
+  /* 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)
     {
-      gimple_assign_set_rhs_from_tree (gsi, res);
-      update_stmt (stmt);
+      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)))
+       {
+         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;
+           }
+       }
     }
-  return;
+
+  return false;
 }
 
 
@@ -2123,6 +2169,7 @@ tree_ssa_forward_propagate_single_use_vars (void)
            {
              tree lhs = gimple_assign_lhs (stmt);
              tree rhs = gimple_assign_rhs1 (stmt);
+             enum tree_code code = gimple_assign_rhs_code (stmt);
 
              if (TREE_CODE (lhs) != SSA_NAME)
                {
@@ -2130,10 +2177,10 @@ tree_ssa_forward_propagate_single_use_vars (void)
                  continue;
                }
 
-             if (gimple_assign_rhs_code (stmt) == ADDR_EXPR
+             if (code == ADDR_EXPR
                  /* Handle pointer conversions on invariant addresses
                     as well, as this is valid gimple.  */
-                 || (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))
+                 || (CONVERT_EXPR_CODE_P (code)
                      && TREE_CODE (rhs) == ADDR_EXPR
                      && POINTER_TYPE_P (TREE_TYPE (lhs))))
                {
@@ -2151,7 +2198,7 @@ tree_ssa_forward_propagate_single_use_vars (void)
                  else
                    gsi_next (&gsi);
                }
-             else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
+             else if (code == POINTER_PLUS_EXPR
                       && can_propagate_from (stmt))
                {
                  if (TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST
@@ -2183,14 +2230,14 @@ tree_ssa_forward_propagate_single_use_vars (void)
                  else
                    gsi_next (&gsi);
                }
-             else if ((gimple_assign_rhs_code (stmt) == BIT_NOT_EXPR
-                       || gimple_assign_rhs_code (stmt) == NEGATE_EXPR)
+             else if ((code == BIT_NOT_EXPR
+                       || code == NEGATE_EXPR)
                       && TREE_CODE (rhs) == SSA_NAME)
                {
                  simplify_not_neg_expr (&gsi);
                  gsi_next (&gsi);
                }
-             else if (gimple_assign_rhs_code (stmt) == COND_EXPR)
+             else if (code == COND_EXPR)
                 {
                   /* In this case the entire COND_EXPR is in rhs1. */
                  int did_something;
@@ -2203,27 +2250,28 @@ tree_ssa_forward_propagate_single_use_vars (void)
                    && did_something, stmt, WARN_STRICT_OVERFLOW_CONDITIONAL);
                  gsi_next (&gsi);
                 }
-             else if (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt))
-                                       == tcc_comparison)
+             else if (TREE_CODE_CLASS (code) == tcc_comparison)
                {
                  if (forward_propagate_comparison (stmt))
                    cfg_changed = true;
                  gsi_next (&gsi);
                }
-             else if (gimple_assign_rhs_code (stmt) == BIT_AND_EXPR)
+             else if (code == BIT_AND_EXPR
+                      || code == BIT_IOR_EXPR
+                      || code == BIT_XOR_EXPR)
                {
-                 simplify_bitwise_and (&gsi, stmt);
-                 gsi_next (&gsi);
+                 if (!simplify_bitwise_binary (&gsi))
+                   gsi_next (&gsi);
                }
-             else if (gimple_assign_rhs_code (stmt) == PLUS_EXPR
-                      || gimple_assign_rhs_code (stmt) == MINUS_EXPR)
+             else if (code == PLUS_EXPR
+                      || code == MINUS_EXPR)
                {
                  cfg_changed |= associate_plusminus (stmt);
                  gsi_next (&gsi);
                }
-             else if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))
-                      || gimple_assign_rhs_code (stmt) == FLOAT_EXPR
-                      || gimple_assign_rhs_code (stmt) == FIX_TRUNC_EXPR)
+             else if (CONVERT_EXPR_CODE_P (code)
+                      || code == FLOAT_EXPR
+                      || code == FIX_TRUNC_EXPR)
                {
                  if (!combine_conversions (&gsi))
                    gsi_next (&gsi);