summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2010-09-30 19:21:34 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2010-09-30 19:21:34 +0000
commit50194c948e64c8f34a3c1808e32af0e9ef918e34 (patch)
treeb8f4be9858411bbb0b971675fd0bd1a833a0e271 /gcc
parent445b7c96edf27f8a16adf5f9ef86cca29b1c7a59 (diff)
downloadgcc-50194c948e64c8f34a3c1808e32af0e9ef918e34.tar.gz
PR tree-optimization/31261
* fold-const.c (fold_binary): Optimize ((A & N) + B) & M for constants M and N, M == (1LL << cst) - 1 && (N & M) == M. * gcc.dg/tree-ssa/pr31261.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@164761 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/fold-const.c127
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr31261.c40
4 files changed, 178 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b081a2c0674..ae7d85d188f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2010-09-30 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/31261
+ * fold-const.c (fold_binary): Optimize ((A & N) + B) & M
+ for constants M and N, M == (1LL << cst) - 1 && (N & M) == M.
+
2010-09-30 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
PR bootstrap/45796
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 25ab4875f41..b2dbb981cfc 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -11071,6 +11071,133 @@ fold_binary_loc (location_t loc,
fold_convert_loc (loc, type, arg0));
}
+ /* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M,
+ ((A & N) + B) & M -> (A + B) & M
+ Similarly if (N & M) == 0,
+ ((A | N) + B) & M -> (A + B) & M
+ and for - instead of + (or unary - instead of +)
+ and/or ^ instead of |.
+ If B is constant and (B & M) == 0, fold into A & M. */
+ if (host_integerp (arg1, 1))
+ {
+ unsigned HOST_WIDE_INT cst1 = tree_low_cst (arg1, 1);
+ if (~cst1 && (cst1 & (cst1 + 1)) == 0
+ && INTEGRAL_TYPE_P (TREE_TYPE (arg0))
+ && (TREE_CODE (arg0) == PLUS_EXPR
+ || TREE_CODE (arg0) == MINUS_EXPR
+ || TREE_CODE (arg0) == NEGATE_EXPR)
+ && (TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0))
+ || TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE))
+ {
+ tree pmop[2];
+ int which = 0;
+ unsigned HOST_WIDE_INT cst0;
+
+ /* Now we know that arg0 is (C + D) or (C - D) or
+ -C and arg1 (M) is == (1LL << cst) - 1.
+ Store C into PMOP[0] and D into PMOP[1]. */
+ pmop[0] = TREE_OPERAND (arg0, 0);
+ pmop[1] = NULL;
+ if (TREE_CODE (arg0) != NEGATE_EXPR)
+ {
+ pmop[1] = TREE_OPERAND (arg0, 1);
+ which = 1;
+ }
+
+ if (!host_integerp (TYPE_MAX_VALUE (TREE_TYPE (arg0)), 1)
+ || (tree_low_cst (TYPE_MAX_VALUE (TREE_TYPE (arg0)), 1)
+ & cst1) != cst1)
+ which = -1;
+
+ for (; which >= 0; which--)
+ switch (TREE_CODE (pmop[which]))
+ {
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ if (TREE_CODE (TREE_OPERAND (pmop[which], 1))
+ != INTEGER_CST)
+ break;
+ /* tree_low_cst not used, because we don't care about
+ the upper bits. */
+ cst0 = TREE_INT_CST_LOW (TREE_OPERAND (pmop[which], 1));
+ cst0 &= cst1;
+ if (TREE_CODE (pmop[which]) == BIT_AND_EXPR)
+ {
+ if (cst0 != cst1)
+ break;
+ }
+ else if (cst0 != 0)
+ break;
+ /* If C or D is of the form (A & N) where
+ (N & M) == M, or of the form (A | N) or
+ (A ^ N) where (N & M) == 0, replace it with A. */
+ pmop[which] = TREE_OPERAND (pmop[which], 0);
+ break;
+ case INTEGER_CST:
+ /* If C or D is a N where (N & M) == 0, it can be
+ omitted (assumed 0). */
+ if ((TREE_CODE (arg0) == PLUS_EXPR
+ || (TREE_CODE (arg0) == MINUS_EXPR && which == 0))
+ && (TREE_INT_CST_LOW (pmop[which]) & cst1) == 0)
+ pmop[which] = NULL;
+ break;
+ default:
+ break;
+ }
+
+ /* Only build anything new if we optimized one or both arguments
+ above. */
+ if (pmop[0] != TREE_OPERAND (arg0, 0)
+ || (TREE_CODE (arg0) != NEGATE_EXPR
+ && pmop[1] != TREE_OPERAND (arg0, 1)))
+ {
+ tree utype = type;
+ if (! TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0)))
+ {
+ /* Perform the operations in a type that has defined
+ overflow behavior. */
+ utype = unsigned_type_for (type);
+ if (pmop[0] != NULL)
+ pmop[0] = fold_convert_loc (loc, utype, pmop[0]);
+ if (pmop[1] != NULL)
+ pmop[1] = fold_convert_loc (loc, utype, pmop[1]);
+ }
+
+ if (TREE_CODE (arg0) == NEGATE_EXPR)
+ tem = fold_build1_loc (loc, NEGATE_EXPR, utype, pmop[0]);
+ else if (TREE_CODE (arg0) == PLUS_EXPR)
+ {
+ if (pmop[0] != NULL && pmop[1] != NULL)
+ tem = fold_build2_loc (loc, PLUS_EXPR, utype,
+ pmop[0], pmop[1]);
+ else if (pmop[0] != NULL)
+ tem = pmop[0];
+ else if (pmop[1] != NULL)
+ tem = pmop[1];
+ else
+ return build_int_cst (type, 0);
+ }
+ else if (pmop[0] == NULL)
+ tem = fold_build1_loc (loc, NEGATE_EXPR, utype, pmop[1]);
+ else
+ tem = fold_build2_loc (loc, MINUS_EXPR, utype,
+ pmop[0], pmop[1]);
+ /* TEM is now the new binary +, - or unary - replacement. */
+ if (utype == type)
+ return fold_build2_loc (loc, BIT_AND_EXPR, type,
+ tem, arg1);
+ else
+ {
+ tem = fold_build2_loc (loc, BIT_AND_EXPR, utype, tem,
+ fold_convert_loc (loc, utype,
+ arg1));
+ return fold_convert_loc (loc, type, tem);
+ }
+ }
+ }
+ }
+
t1 = distribute_bit_expr (loc, code, type, arg0, arg1);
if (t1 != NULL_TREE)
return t1;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index fd164d46872..1775235b92d 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2010-09-30 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/31261
+ * gcc.dg/tree-ssa/pr31261.c: New test.
+
2010-09-30 Michael Eager <eager@eagercon.com>
* gcc.c-torture/execute/cmpsi-2.c: New testcase.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr31261.c b/gcc/testsuite/gcc.dg/tree-ssa/pr31261.c
new file mode 100644
index 00000000000..42bd2a21ef3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr31261.c
@@ -0,0 +1,40 @@
+/* PR tree-optimization/31261 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-original" } */
+
+unsigned int
+f1 (unsigned int a)
+{
+ return (8 - (a & 7)) & 7;
+}
+
+long int
+f2 (long int b)
+{
+ return (16 + (b & 7)) & 15;
+}
+
+char
+f3 (char c)
+{
+ return -(c & 63) & 31;
+}
+
+int
+f4 (int d)
+{
+ return (12 - (d & 15)) & 7;
+}
+
+int
+f5 (int e)
+{
+ return (12 - (e & 7)) & 15;
+}
+
+/* { dg-final { scan-tree-dump-times "return -a \& 7;" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "return b \& 7;" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "return \\(char\\) -\\(unsigned char\\) c \& 31;" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "return \\(int\\) \\(12 - \\(unsigned int\\) d\\) \& 7;" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "return 12 - \\(e \& 7\\) \& 15;" 1 "original" } } */
+/* { dg-final { cleanup-tree-dump "original" } } */