summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/fold-const.c108
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/gcc.dg/fold-bitand-1.c34
-rw-r--r--gcc/testsuite/gcc.dg/fold-bitand-2.c42
-rw-r--r--gcc/testsuite/gcc.dg/fold-bitand-3.c25
-rw-r--r--gcc/testsuite/gcc.dg/fold-bitand-4.c44
7 files changed, 265 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2837ede708b..b510bddf429 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2007-09-23 Ollie Wild <aaw@google.com>
+
+ fold-const.c (fold_binary): Fold BIT_AND_EXPR's with a pointer operand.
+ (get_pointer_modulus_and_residue): New function.
+
2007-09-23 Richard Sandiford <rsandifo@nildram.co.uk>
* config/mips/mips.c (build_mips16_call_stub): On 64-bit targets,
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 426aad4ced1..12413d833d0 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -9384,6 +9384,97 @@ fold_mult_zconjz (tree type, tree expr)
}
+/* Subroutine of fold_binary. If P is the value of EXPR, computes
+ power-of-two M and (arbitrary) N such that M divides (P-N). This condition
+ guarantees that P and N have the same least significant log2(M) bits.
+ N is not otherwise constrained. In particular, N is not normalized to
+ 0 <= N < M as is common. In general, the precise value of P is unknown.
+ M is chosen as large as possible such that constant N can be determined.
+
+ Returns M and sets *RESIDUE to N. */
+
+static unsigned HOST_WIDE_INT
+get_pointer_modulus_and_residue (tree expr, unsigned HOST_WIDE_INT *residue)
+{
+ enum tree_code code;
+
+ *residue = 0;
+
+ code = TREE_CODE (expr);
+ if (code == ADDR_EXPR)
+ {
+ expr = TREE_OPERAND (expr, 0);
+ if (handled_component_p (expr))
+ {
+ HOST_WIDE_INT bitsize, bitpos;
+ tree offset;
+ enum machine_mode mode;
+ int unsignedp, volatilep;
+
+ expr = get_inner_reference (expr, &bitsize, &bitpos, &offset,
+ &mode, &unsignedp, &volatilep, false);
+ *residue = bitpos / BITS_PER_UNIT;
+ if (offset)
+ {
+ if (TREE_CODE (offset) == INTEGER_CST)
+ *residue += TREE_INT_CST_LOW (offset);
+ else
+ /* We don't handle more complicated offset expressions. */
+ return 1;
+ }
+ }
+
+ if (DECL_P (expr))
+ return DECL_ALIGN_UNIT (expr);
+ }
+ else if (code == POINTER_PLUS_EXPR)
+ {
+ tree op0, op1;
+ unsigned HOST_WIDE_INT modulus;
+ enum tree_code inner_code;
+
+ op0 = TREE_OPERAND (expr, 0);
+ STRIP_NOPS (op0);
+ modulus = get_pointer_modulus_and_residue (op0, residue);
+
+ op1 = TREE_OPERAND (expr, 1);
+ STRIP_NOPS (op1);
+ inner_code = TREE_CODE (op1);
+ if (inner_code == INTEGER_CST)
+ {
+ *residue += TREE_INT_CST_LOW (op1);
+ return modulus;
+ }
+ else if (inner_code == MULT_EXPR)
+ {
+ op1 = TREE_OPERAND (op1, 1);
+ if (TREE_CODE (op1) == INTEGER_CST)
+ {
+ unsigned HOST_WIDE_INT align;
+
+ /* Compute the greatest power-of-2 divisor of op1. */
+ align = TREE_INT_CST_LOW (op1);
+ align &= -align;
+
+ /* If align is non-zero and less than *modulus, replace
+ *modulus with align., If align is 0, then either op1 is 0
+ or the greatest power-of-2 divisor of op1 doesn't fit in an
+ unsigned HOST_WIDE_INT. In either case, no additional
+ constraint is imposed. */
+ if (align)
+ modulus = MIN (modulus, align);
+
+ return modulus;
+ }
+ }
+ }
+
+ /* If we get here, we were unable to determine anything useful about the
+ expression. */
+ return 1;
+}
+
+
/* Fold a binary expression of code CODE and type TYPE with operands
OP0 and OP1. Return the folded expression if folding is
successful. Otherwise, return NULL_TREE. */
@@ -10915,6 +11006,23 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
TREE_OPERAND (arg1, 0)));
}
+ /* If arg0 is derived from the address of an object or function, we may
+ be able to fold this expression using the object or function's
+ alignment. */
+ if (POINTER_TYPE_P (TREE_TYPE (arg0)) && host_integerp (arg1, 1))
+ {
+ unsigned HOST_WIDE_INT modulus, residue;
+ unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (arg1);
+
+ modulus = get_pointer_modulus_and_residue (arg0, &residue);
+
+ /* This works because modulus is a power of 2. If this weren't the
+ case, we'd have to replace it by its greatest power-of-2
+ divisor: modulus & -modulus. */
+ if (low < modulus)
+ return build_int_cst (type, residue & low);
+ }
+
goto associate;
case RDIV_EXPR:
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index ff03ded25b7..76fa88681c1 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2007-09-23 Ollie Wild <aaw@google.com>
+
+ gcc.dg/fold-bitand-1.c: New test.
+ gcc.dg/fold-bitand-2.c: New test.
+ gcc.dg/fold-bitand-3.c: New test.
+ gcc.dg/fold-bitand-4.c: New test.
+
2007-09-23 Richard Sandiford <rsandifo@nildram.co.uk>
* gcc.target/mips/gcc-have-sync-compare-and-swap-1.c: Don't expect
diff --git a/gcc/testsuite/gcc.dg/fold-bitand-1.c b/gcc/testsuite/gcc.dg/fold-bitand-1.c
new file mode 100644
index 00000000000..413ed67d239
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/fold-bitand-1.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-original" } */
+
+char c1 __attribute__ ((aligned (1)));
+char c2 __attribute__ ((aligned (2)));
+char c4 __attribute__ ((aligned (4)));
+char c8 __attribute__ ((aligned (8)));
+
+unsigned f1(void)
+{
+ return 3 & (__SIZE_TYPE__)&c1;
+}
+
+unsigned f2(void)
+{
+ return 3 & (__SIZE_TYPE__)&c2;
+}
+
+unsigned f3(void)
+{
+ return 3 & (__SIZE_TYPE__)&c4;
+}
+
+unsigned f4(void)
+{
+ return 3 & (__SIZE_TYPE__)&c8;
+}
+
+/* { dg-final { scan-tree-dump-times "\&c1 \& 3" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "\&c2 \& 3" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "\&c4 \& 3" 0 "original" } } */
+/* { dg-final { scan-tree-dump-times "\&c8 \& 3" 0 "original" } } */
+/* { dg-final { scan-tree-dump-times "return 0" 2 "original" } } */
+/* { dg-final { cleanup-tree-dump "original" } } */
diff --git a/gcc/testsuite/gcc.dg/fold-bitand-2.c b/gcc/testsuite/gcc.dg/fold-bitand-2.c
new file mode 100644
index 00000000000..de2e67449b1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/fold-bitand-2.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-original" } */
+
+struct {
+ char c1;
+ char c2;
+ char c3;
+ char c4;
+} s __attribute__ ((aligned (4)));
+
+unsigned f1 (void)
+{
+ return 3 & (__SIZE_TYPE__)&s.c1;
+}
+
+unsigned f2 (void)
+{
+ return 3 & (__SIZE_TYPE__)&s.c2;
+}
+
+unsigned f3 (void)
+{
+ return 3 & (__SIZE_TYPE__)&s.c3;
+}
+
+unsigned f4 (void)
+{
+ return 3 & (__SIZE_TYPE__)&s.c4;
+}
+
+unsigned f5 (void)
+{
+ return 4 & (__SIZE_TYPE__)&s.c1;
+}
+
+/* { dg-final { scan-tree-dump-times "\& 3" 0 "original" } } */
+/* { dg-final { scan-tree-dump-times "\& 4" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "return 0" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "return 1" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "return 2" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "return 3" 1 "original" } } */
+/* { dg-final { cleanup-tree-dump "original" } } */
diff --git a/gcc/testsuite/gcc.dg/fold-bitand-3.c b/gcc/testsuite/gcc.dg/fold-bitand-3.c
new file mode 100644
index 00000000000..43d765bbf2e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/fold-bitand-3.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-original" } */
+
+char c[4] __attribute__ ((aligned (4)));
+
+struct S {
+ char c1;
+ char c2;
+ char c3;
+ char c4;
+};
+
+int f1 (void)
+{
+ return 3 & (__SIZE_TYPE__)&c[1];
+}
+
+int f2 (void)
+{
+ return 3 & (__SIZE_TYPE__)&((struct S *)&c)->c2;
+}
+
+/* { dg-final { scan-tree-dump-times "\& 3" 0 "original" } } */
+/* { dg-final { scan-tree-dump-times "return 1" 2 "original" } } */
+/* { dg-final { cleanup-tree-dump "original" } } */
diff --git a/gcc/testsuite/gcc.dg/fold-bitand-4.c b/gcc/testsuite/gcc.dg/fold-bitand-4.c
new file mode 100644
index 00000000000..7d824260ff0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/fold-bitand-4.c
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-original" } */
+
+typedef char char4[4] __attribute__ ((aligned (4)));
+char4 c4[4] __attribute__ ((aligned (16)));
+
+typedef char char16[16] __attribute__ ((aligned (16)));
+char16 c16[4] __attribute__ ((aligned (4)));
+
+int f1 (void)
+{
+ /* 12 */
+ return 15 & (__SIZE_TYPE__)&c4[3];
+}
+
+int f2 (int i)
+{
+ /* Indeterminate */
+ return 15 & (__SIZE_TYPE__)&c4[i];
+}
+
+int f3 (int i)
+{
+ /* 0 */
+ return 3 & (__SIZE_TYPE__)&c4[i];
+}
+
+int f4 (int i)
+{
+ /* Indeterminate */
+ return 7 & (__SIZE_TYPE__)&c16[i];
+}
+
+int f5 (int i)
+{
+ /* 0 */
+ return 3 & (__SIZE_TYPE__)&c16[i];
+}
+
+/* { dg-final { scan-tree-dump-times "return 12" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "\& 15" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "return 0" 2 "original" } } */
+/* { dg-final { scan-tree-dump-times "\& 7" 1 "original" } } */
+/* { dg-final { cleanup-tree-dump "original" } } */
OpenPOWER on IntegriCloud