diff options
author | aaw <aaw@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-09-23 20:05:40 +0000 |
---|---|---|
committer | aaw <aaw@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-09-23 20:05:40 +0000 |
commit | 4486d2b7f11c5ca684304a8cff46baefc892d089 (patch) | |
tree | 2d3fd9b7aeae8ab84d172e1ceed387e1e4e97364 /gcc/fold-const.c | |
parent | ee37867ca544a6c76553fc9563f5162797b3a869 (diff) | |
download | ppe42-gcc-4486d2b7f11c5ca684304a8cff46baefc892d089.tar.gz ppe42-gcc-4486d2b7f11c5ca684304a8cff46baefc892d089.zip |
gcc/
fold-const.c (fold_binary): Fold BIT_AND_EXPR's with a pointer operand.
(get_pointer_modulus_and_residue): New function.
gcc/testsuite/
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@128701 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 108 |
1 files changed, 108 insertions, 0 deletions
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: |