re PR tree-optimization/30137 (Missed folding of pointer comparison)
2006-12-31 Richard Guenther <rguenther@suse.de> PR middle-end/30137 * fold-const.c (fold_comparison): Fold comparison of addresses of components. * testsuite/gcc.dg/pr30137-1.c: New testcase. * testsuite/gcc.dg/pr30137-2.c: Likewise. From-SVN: r120301
This commit is contained in:
parent
870aa1ebe0
commit
e015f57888
5 changed files with 159 additions and 0 deletions
|
@ -1,3 +1,9 @@
|
|||
2006-12-31 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
PR middle-end/30137
|
||||
* fold-const.c (fold_comparison): Fold comparison of addresses
|
||||
of components.
|
||||
|
||||
2006-12-31 Roger Sayle <roger@eyesopen.com>
|
||||
|
||||
PR middle-end/30322
|
||||
|
|
104
gcc/fold-const.c
104
gcc/fold-const.c
|
@ -7988,6 +7988,110 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
|
|||
return fold_build2 (code, type, variable, lhs);
|
||||
}
|
||||
|
||||
/* For comparisons of pointers we can decompose it to a compile time
|
||||
comparison of the base objects and the offsets into the object.
|
||||
This requires at least one operand being an ADDR_EXPR to do more
|
||||
than the operand_equal_p test below. */
|
||||
if (POINTER_TYPE_P (TREE_TYPE (arg0))
|
||||
&& (TREE_CODE (arg0) == ADDR_EXPR
|
||||
|| TREE_CODE (arg1) == ADDR_EXPR))
|
||||
{
|
||||
tree base0, base1, offset0 = NULL_TREE, offset1 = NULL_TREE;
|
||||
HOST_WIDE_INT bitsize, bitpos0 = 0, bitpos1 = 0;
|
||||
enum machine_mode mode;
|
||||
int volatilep, unsignedp;
|
||||
bool indirect_base0 = false;
|
||||
|
||||
/* Get base and offset for the access. Strip ADDR_EXPR for
|
||||
get_inner_reference, but put it back by stripping INDIRECT_REF
|
||||
off the base object if possible. */
|
||||
base0 = arg0;
|
||||
if (TREE_CODE (arg0) == ADDR_EXPR)
|
||||
{
|
||||
base0 = get_inner_reference (TREE_OPERAND (arg0, 0),
|
||||
&bitsize, &bitpos0, &offset0, &mode,
|
||||
&unsignedp, &volatilep, false);
|
||||
if (TREE_CODE (base0) == INDIRECT_REF)
|
||||
base0 = TREE_OPERAND (base0, 0);
|
||||
else
|
||||
indirect_base0 = true;
|
||||
}
|
||||
|
||||
base1 = arg1;
|
||||
if (TREE_CODE (arg1) == ADDR_EXPR)
|
||||
{
|
||||
base1 = get_inner_reference (TREE_OPERAND (arg1, 0),
|
||||
&bitsize, &bitpos1, &offset1, &mode,
|
||||
&unsignedp, &volatilep, false);
|
||||
/* We have to make sure to have an indirect/non-indirect base1
|
||||
just the same as we did for base0. */
|
||||
if (TREE_CODE (base1) == INDIRECT_REF
|
||||
&& !indirect_base0)
|
||||
base1 = TREE_OPERAND (base1, 0);
|
||||
else if (!indirect_base0)
|
||||
base1 = NULL_TREE;
|
||||
}
|
||||
else if (indirect_base0)
|
||||
base1 = NULL_TREE;
|
||||
|
||||
/* If we have equivalent bases we might be able to simplify. */
|
||||
if (base0 && base1
|
||||
&& operand_equal_p (base0, base1, 0))
|
||||
{
|
||||
/* We can fold this expression to a constant if the non-constant
|
||||
offset parts are equal. */
|
||||
if (offset0 == offset1
|
||||
|| (offset0 && offset1
|
||||
&& operand_equal_p (offset0, offset1, 0)))
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case EQ_EXPR:
|
||||
return build_int_cst (boolean_type_node, bitpos0 == bitpos1);
|
||||
case NE_EXPR:
|
||||
return build_int_cst (boolean_type_node, bitpos0 != bitpos1);
|
||||
case LT_EXPR:
|
||||
return build_int_cst (boolean_type_node, bitpos0 < bitpos1);
|
||||
case LE_EXPR:
|
||||
return build_int_cst (boolean_type_node, bitpos0 <= bitpos1);
|
||||
case GE_EXPR:
|
||||
return build_int_cst (boolean_type_node, bitpos0 >= bitpos1);
|
||||
case GT_EXPR:
|
||||
return build_int_cst (boolean_type_node, bitpos0 > bitpos1);
|
||||
default:;
|
||||
}
|
||||
}
|
||||
/* We can simplify the comparison to a comparison of the variable
|
||||
offset parts if the constant offset parts are equal.
|
||||
Be careful to use signed size type here because otherwise we
|
||||
mess with array offsets in the wrong way. This is possible
|
||||
because pointer arithmetic is restricted to retain within an
|
||||
object and overflow on pointer differences is undefined as of
|
||||
6.5.6/8 and /9 with respect to the signed ptrdiff_t. */
|
||||
else if (bitpos0 == bitpos1)
|
||||
{
|
||||
tree signed_size_type_node;
|
||||
signed_size_type_node = signed_type_for (size_type_node);
|
||||
|
||||
/* By converting to signed size type we cover middle-end pointer
|
||||
arithmetic which operates on unsigned pointer types of size
|
||||
type size and ARRAY_REF offsets which are properly sign or
|
||||
zero extended from their type in case it is narrower than
|
||||
size type. */
|
||||
if (offset0 == NULL_TREE)
|
||||
offset0 = build_int_cst (signed_size_type_node, 0);
|
||||
else
|
||||
offset0 = fold_convert (signed_size_type_node, offset0);
|
||||
if (offset1 == NULL_TREE)
|
||||
offset1 = build_int_cst (signed_size_type_node, 0);
|
||||
else
|
||||
offset1 = fold_convert (signed_size_type_node, offset1);
|
||||
|
||||
return fold_build2 (code, type, offset0, offset1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is a comparison of two exprs that look like an ARRAY_REF of the
|
||||
same object, then we can fold this to a comparison of the two offsets in
|
||||
signed size type. This is possible because pointer arithmetic is
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2006-12-31 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
PR middle-end/30137
|
||||
* testsuite/gcc.dg/pr30137-1.c: New testcase.
|
||||
* testsuite/gcc.dg/pr30137-2.c: Likewise.
|
||||
|
||||
2006-12-31 Roger Sayle <roger@eyesopen.com>
|
||||
|
||||
PR middle-end/30322
|
||||
|
|
23
gcc/testsuite/gcc.dg/pr30137-1.c
Normal file
23
gcc/testsuite/gcc.dg/pr30137-1.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-w -fdump-tree-gimple" } */
|
||||
|
||||
/* Things that should not be folded. */
|
||||
|
||||
struct { long base; int tail; void * volatile ptr; } *s;
|
||||
int foo3 (void) { return s == &s; }
|
||||
int foo5 (void) { return s->ptr == s->ptr; }
|
||||
|
||||
struct { union { int i; short s } u; } x;
|
||||
int foo6 (void) { return x.u.i == x.u.s; }
|
||||
|
||||
void **p;
|
||||
int foo8 (void) { return p == &p; }
|
||||
int foo9 (void) { return *p == p; }
|
||||
int foo10 (void) { return *p == &p; }
|
||||
int foo11 (void) { return p != &p; }
|
||||
int foo12 (void) { return *p != p; }
|
||||
int foo13 (void) { return *p != &p; }
|
||||
|
||||
/* { dg-final { scan-tree-dump-not "= 0;" "gimple" } } */
|
||||
/* { dg-final { scan-tree-dump-not "= 1;" "gimple" } } */
|
||||
/* { dg-final { cleanup-tree-dump "gimple" } } */
|
20
gcc/testsuite/gcc.dg/pr30137-2.c
Normal file
20
gcc/testsuite/gcc.dg/pr30137-2.c
Normal file
|
@ -0,0 +1,20 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-w -fdump-tree-gimple" } */
|
||||
|
||||
/* Things that should be folded. */
|
||||
|
||||
struct { long base; int tail; void * volatile ptr; } *s;
|
||||
int foo1a (void) { return (s == &s->base); }
|
||||
int foo1b (void) { return (&s->base == s); }
|
||||
int foo2 (void) { return ((void *)s == (void *) &s->base); }
|
||||
int foo4 (void) { return s->base == s->base; }
|
||||
int foo5 (void) { return &s->ptr == &s->ptr; }
|
||||
int foo6 (void) { return &s->ptr != &s->ptr; }
|
||||
int foo7 (void) { return &s->base != &s->ptr; }
|
||||
|
||||
struct { union { int i; short s } u; } x;
|
||||
int foo8 (void) { return &x.u.i == &x.u.s; }
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "= 0" 1 "gimple" } } */
|
||||
/* { dg-final { scan-tree-dump-times "= 1" 7 "gimple" } } */
|
||||
/* { dg-final { cleanup-tree-dump "gimple" } } */
|
Loading…
Add table
Reference in a new issue