re PR tree-optimization/14796 ([tree-ssa] combine two shifts into one)
authorJames A. Morrison <phython@gcc.gnu.org>
Sun, 12 Jun 2005 08:03:23 +0000 (08:03 +0000)
committerJames A. Morrison <phython@gcc.gnu.org>
Sun, 12 Jun 2005 08:03:23 +0000 (08:03 +0000)
2005-06-12  James A. Morrison  <phython@gcc.gnu.org>

        PR tree-optimization/14796
        * fold-const.c (fold_binary): Transform (A >> C) << C into
        one BIT_AND_EXPR.
        <shift>: Transform (A OP c1) OP c2 into A OP (c1 + c2).

From-SVN: r100853

gcc/ChangeLog
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr14796-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr14796-2.c [new file with mode: 0644]

index 4a6d731acb1c03427e0335fc38243b87b4ecf217..6582d719891a2dbaba35837926e0f619dddb0497 100644 (file)
@@ -1,3 +1,10 @@
+2005-06-12  James A. Morrison  <phython@gcc.gnu.org>
+
+       PR tree-optimization/14796
+       * fold-const.c (fold_binary): Transform (A >> C) << C into
+       one BIT_AND_EXPR.
+       <shift>: Transform (A OP c1) OP c2 into A OP (c1 + c2).
+
 2005-06-11  Geoffrey Keating  <geoffk@apple.com>
 
        * config/rs6000/predicates.md (reg_or_arith_cint_operand): Delete.
index 96fffe995d4d7a8756aa20928c7b68397a45559b..1994410d4be8b7d3338d194f0ce94bda60c4e12e 100644 (file)
@@ -8742,6 +8742,59 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
         don't try to compute it in the compiler.  */
       if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_sgn (arg1) < 0)
        return NULL_TREE;
+
+      /* Turn (a OP c1) OP c2 into a OP (c1+c2).  */
+      if (TREE_CODE (arg0) == code && host_integerp (arg1, false)
+         && TREE_INT_CST_LOW (arg1) < TYPE_PRECISION (type)
+         && host_integerp (TREE_OPERAND (arg0, 1), false)
+         && TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) < TYPE_PRECISION (type))
+       {
+         HOST_WIDE_INT low = (TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1))
+                              + TREE_INT_CST_LOW (arg1));
+
+         /* Deal with a OP (c1 + c2) being undefined but (a OP c1) OP c2
+            being well defined.  */
+         if (low >= TYPE_PRECISION (type))
+           {
+             if (code == LROTATE_EXPR || code == RROTATE_EXPR)
+               low = low % TYPE_PRECISION (type);
+             else if (TYPE_UNSIGNED (type) || code == LSHIFT_EXPR)
+               return build_int_cst (type, 0);
+             else
+               low = TYPE_PRECISION (type) - 1;
+           }
+
+         return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
+                             build_int_cst (type, low));
+       }
+
+      /* Transform (x >> c) << c into x & (-1<<c)  */
+      if (code == LSHIFT_EXPR && TREE_CODE (arg0) == RSHIFT_EXPR
+         && host_integerp (arg1, false)
+         && TREE_INT_CST_LOW (arg1) < TYPE_PRECISION (type)
+         && host_integerp (TREE_OPERAND (arg0, 1), false)
+         && TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) < TYPE_PRECISION (type))
+       {
+         HOST_WIDE_INT low0 = TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1));
+         HOST_WIDE_INT low1 = TREE_INT_CST_LOW (arg1);
+         unsigned HOST_WIDE_INT low;
+         HOST_WIDE_INT high;
+         tree lshift;
+         tree arg00;
+
+         if (low0 == low1)
+           {
+             arg00 = fold_convert (type, TREE_OPERAND (arg0, 0));
+
+             lshift_double (-1, -1, low0 < low1 ? low0 : low1,
+                            TYPE_PRECISION (type), &low, &high, 1);
+             lshift = build_int_cst_wide (type, low, high);
+
+             return fold_build2 (BIT_AND_EXPR, type, arg00, lshift);
+           }
+       }
+
+
       /* Rewrite an LROTATE_EXPR by a constant into an
         RROTATE_EXPR by a new constant.  */
       if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST)
index 6140b216890972da47f403ebe1f4066a0e6df543..e890f8066cc04b2bc44b44d3d1dc57cc92701030 100644 (file)
@@ -1,3 +1,8 @@
+2005-06-12  James A. Morrison  <phython@gcc.gnu.org>
+
+       * gcc.dg/pr14796-1.c: New.
+       * gcc.dg/pr14796-2.c: New.
+
 2005-06-11  Steven G. Kargl  <kargls@comcast.net>
 
        PR fortran/17792
diff --git a/gcc/testsuite/gcc.dg/pr14796-1.c b/gcc/testsuite/gcc.dg/pr14796-1.c
new file mode 100644 (file)
index 0000000..c927e2b
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-gimple" } */
+
+int f (int a) {
+       return (a << 3) << 6;
+}
+
+int g (int b) {
+       return (b >> 5) << 5;
+}
+
+/* { dg-final { scan-tree-dump "a << 9" "gimple" } } */
+/* { dg-final { scan-tree-dump "b & -32" "gimple" } } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/pr14796-2.c b/gcc/testsuite/gcc.dg/pr14796-2.c
new file mode 100644 (file)
index 0000000..de4ec27
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-gimple" } */
+
+int f (int a) {
+       return (a << 31) << 6;
+}
+
+unsigned int g (unsigned int a) {
+       return (a >> 7) >> 25;
+}
+
+int h (int b) {
+       return (b >> 30) >> 30;
+}
+
+long long j (long long c) {
+       return (c >> 35) << 35;
+}
+/* { dg-final { scan-tree-dump-times "= 0" 2 "gimple" } } */
+/* { dg-final { scan-tree-dump "b >> 31" "gimple" } } */
+/* { dg-final { scan-tree-dump "c & -34359738368" "gimple" } } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */