From e015f578884bce00d4fe8d7b8d14b94b11879ba3 Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Sun, 31 Dec 2006 17:27:35 +0000 Subject: [PATCH] re PR tree-optimization/30137 (Missed folding of pointer comparison) 2006-12-31 Richard Guenther 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 --- gcc/ChangeLog | 6 ++ gcc/fold-const.c | 104 +++++++++++++++++++++++++++++++ gcc/testsuite/ChangeLog | 6 ++ gcc/testsuite/gcc.dg/pr30137-1.c | 23 +++++++ gcc/testsuite/gcc.dg/pr30137-2.c | 20 ++++++ 5 files changed, 159 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/pr30137-1.c create mode 100644 gcc/testsuite/gcc.dg/pr30137-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index be1f4fba5628..168c19599763 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2006-12-31 Richard Guenther + + PR middle-end/30137 + * fold-const.c (fold_comparison): Fold comparison of addresses + of components. + 2006-12-31 Roger Sayle PR middle-end/30322 diff --git a/gcc/fold-const.c b/gcc/fold-const.c index da9579e6b4e5..071ddcd6e7df 100644 --- a/gcc/fold-const.c +++ b/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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 30d25ea11dd4..7b2dbcdc6263 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2006-12-31 Richard Guenther + + PR middle-end/30137 + * testsuite/gcc.dg/pr30137-1.c: New testcase. + * testsuite/gcc.dg/pr30137-2.c: Likewise. + 2006-12-31 Roger Sayle PR middle-end/30322 diff --git a/gcc/testsuite/gcc.dg/pr30137-1.c b/gcc/testsuite/gcc.dg/pr30137-1.c new file mode 100644 index 000000000000..cf1b4063496e --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr30137-1.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/pr30137-2.c b/gcc/testsuite/gcc.dg/pr30137-2.c new file mode 100644 index 000000000000..53be1633b7be --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr30137-2.c @@ -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" } } */ -- 2.47.2