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:
parent
50b73fcde4
commit
e5901cad3f
@ -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,
|
||||
|
108
gcc/fold-const.c
108
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:
|
||||
|
@ -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
|
||||
|
34
gcc/testsuite/gcc.dg/fold-bitand-1.c
Normal file
34
gcc/testsuite/gcc.dg/fold-bitand-1.c
Normal 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" } } */
|
42
gcc/testsuite/gcc.dg/fold-bitand-2.c
Normal file
42
gcc/testsuite/gcc.dg/fold-bitand-2.c
Normal 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" } } */
|
25
gcc/testsuite/gcc.dg/fold-bitand-3.c
Normal file
25
gcc/testsuite/gcc.dg/fold-bitand-3.c
Normal 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" } } */
|
44
gcc/testsuite/gcc.dg/fold-bitand-4.c
Normal file
44
gcc/testsuite/gcc.dg/fold-bitand-4.c
Normal 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" } } */
|
Loading…
Reference in New Issue
Block a user