diff options
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/fold-const.c | 63 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/loop-17.c | 19 |
4 files changed, 67 insertions, 28 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 977f32a..fd3d122 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2006-06-04 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/27039 + * fold-const.c (fold_comparison): Handle pointer comparison + again for all comparison codes. Compare offsets in signed + size type. + (fold_binary): Move code from here. + 2006-06-03 Roger Sayle <roger@eyesopen.com> PR target/26223 diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 7930bb4..3c8575e 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -7764,6 +7764,41 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1) return fold_build2 (code, type, variable, lhs); } + /* 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 + 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. */ + if (POINTER_TYPE_P (TREE_TYPE (arg0)) + && !flag_wrapv && !flag_trapv) + { + tree base0, offset0, base1, offset1; + + if (extract_array_ref (arg0, &base0, &offset0) + && extract_array_ref (arg1, &base1, &offset1) + && operand_equal_p (base0, base1, 0)) + { + 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 (FLOAT_TYPE_P (TREE_TYPE (arg0))) { tree targ0 = strip_float_extensions (arg0); @@ -10539,34 +10574,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) tem, build_int_cst (TREE_TYPE (tem), 0)); } - /* 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. This is only safe for - EQ_EXPR and NE_EXPR because of overflow issues. */ - { - tree base0, offset0, base1, offset1; - - if (extract_array_ref (arg0, &base0, &offset0) - && extract_array_ref (arg1, &base1, &offset1) - && operand_equal_p (base0, base1, 0)) - { - /* Handle no offsets on both sides specially. */ - if (offset0 == NULL_TREE && offset1 == NULL_TREE) - return fold_build2 (code, type, integer_zero_node, - integer_zero_node); - - if (!offset0 || !offset1 - || TREE_TYPE (offset0) == TREE_TYPE (offset1)) - { - if (offset0 == NULL_TREE) - offset0 = build_int_cst (TREE_TYPE (offset1), 0); - if (offset1 == NULL_TREE) - offset1 = build_int_cst (TREE_TYPE (offset0), 0); - return fold_build2 (code, type, offset0, offset1); - } - } - } - if (integer_zerop (arg1) && tree_expr_nonzero_p (arg0)) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1553c98..21fa273 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2006-06-04 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/27039 + * gcc.dg/tree-ssa/loop-17.c: New testcase. + 2006-06-03 Roger Sayle <roger@eyesopen.com> PR target/26223 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loop-17.c b/gcc/testsuite/gcc.dg/tree-ssa/loop-17.c new file mode 100644 index 0000000..26e4986 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/loop-17.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-sccp-details" } */ + +/* To determine the number of iterations in this loop we need to fold + p_4 + 4B > p_4 + 8B to false. This transformation has caused + troubles in the past due to overflow issues. */ + +int foo (int *p) +{ + int i = 0, *x; + + for (x = p; x < p + 2; x++) + i++; + + return i; +} + +/* { dg-final { scan-tree-dump "set_nb_iterations_in_loop = 2" "sccp" } } */ +/* { dg-final { cleanup-tree-dump "sccp" } } */ |