diff options
-rw-r--r-- | gcc/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/fold-const.c | 108 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/fold-bitand-1.c | 34 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/fold-bitand-2.c | 42 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/fold-bitand-3.c | 25 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/fold-bitand-4.c | 44 |
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" } } */ |