fold-const.c (fold_binary): Fold BIT_AND_EXPR's with a pointer operand.

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.

From-SVN: r128701
This commit is contained in:
Ollie Wild 2007-09-23 20:05:40 +00:00 committed by Ollie Wild
parent 50b73fcde4
commit e5901cad3f
7 changed files with 265 additions and 0 deletions

View File

@ -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,

View File

@ -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:

View File

@ -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

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -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" } } */