From a75f501709fc1562a96064688ca925d48562f131 Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Wed, 20 Jun 2012 12:00:20 +0000 Subject: [PATCH] re PR tree-optimization/30318 (VRP does not create ANTI_RANGEs on overflow) 2012-06-20 Richard Guenther PR tree-optimization/30318 * tree-vrp.c (range_int_cst_p): Do not reject overflowed constants here. (range_int_cst_singleton_p): But explicitely here. (zero_nonzero_bits_from_vr): And here. (extract_range_from_binary_expr_1): Re-implement PLUS_EXPR to cover all cases we can perform arbitrary precision arithmetic with double-ints. (intersect_ranges): Handle adjacent anti-ranges. * gcc.dg/tree-ssa/vrp69.c: New testcase. From-SVN: r188827 --- gcc/ChangeLog | 12 ++ gcc/testsuite/ChangeLog | 5 + gcc/testsuite/gcc.dg/tree-ssa/vrp69.c | 38 +++++ gcc/tree-vrp.c | 208 +++++++++++++++++++++----- 4 files changed, 227 insertions(+), 36 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp69.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d1fca42e264..ebcdf5a9664 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2012-06-20 Richard Guenther + + PR tree-optimization/30318 + * tree-vrp.c (range_int_cst_p): Do not reject overflowed + constants here. + (range_int_cst_singleton_p): But explicitely here. + (zero_nonzero_bits_from_vr): And here. + (extract_range_from_binary_expr_1): Re-implement PLUS_EXPR + to cover all cases we can perform arbitrary precision + arithmetic with double-ints. + (intersect_ranges): Handle adjacent anti-ranges. + 2012-06-20 Uros Bizjak * config/i386/i386.md (rounding_insn): New int attribute. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 43f85de5a2e..60b08280c04 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2012-06-20 Richard Guenther + + PR tree-optimization/30318 + * gcc.dg/tree-ssa/vrp69.c: New testcase. + 2012-06-20 Richard Earnshaw * g++.dg/debug/dwarf2/nested-3.C: Add ARM comment character to regexp. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp69.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp69.c new file mode 100644 index 00000000000..d7540c9e2f9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp69.c @@ -0,0 +1,38 @@ +/* { dg-do link } */ +/* { dg-options "-O2 -fdump-tree-vrp1" } */ + +#include "vrp.h" + +void test1(int i, int j) +{ + RANGE(i, 1, 5); + RANGE(j, 7, 10); + CHECK_RANGE(i + j, 8, 15); +} + +#define UINT_MAX 2*(unsigned)__INT_MAX__ + 1 +void test2(unsigned int i) +{ + RANGE(i, UINT_MAX - 0x4, UINT_MAX - 0x1); + CHECK_ANTI_RANGE(i + 0x2, 0x1, UINT_MAX - 0x3); +} +void test3(unsigned int i) +{ + RANGE(i, UINT_MAX - 0x4, UINT_MAX - 0x1); + CHECK_RANGE(i + 0x5, 0x0, 0x3); +} +void test4(unsigned int i) +{ + RANGE(i, 2, 4); + CHECK_ANTI_RANGE(i - 4, 1, UINT_MAX - 2); +} +void test5(unsigned int i) +{ + RANGE(i, 2, 4); + CHECK_RANGE(i - 8, UINT_MAX - 5, UINT_MAX - 3); +} + +int main() {} + +/* { dg-final { scan-tree-dump-times "link_error" 0 "vrp1" } } */ +/* { dg-final { cleanup-tree-dump "vrp1" } } */ diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 421c08e8e4d..32c5afa49c7 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -844,9 +844,7 @@ range_int_cst_p (value_range_t *vr) { return (vr->type == VR_RANGE && TREE_CODE (vr->max) == INTEGER_CST - && TREE_CODE (vr->min) == INTEGER_CST - && !TREE_OVERFLOW (vr->max) - && !TREE_OVERFLOW (vr->min)); + && TREE_CODE (vr->min) == INTEGER_CST); } /* Return true if VR is a INTEGER_CST singleton. */ @@ -855,6 +853,8 @@ static inline bool range_int_cst_singleton_p (value_range_t *vr) { return (range_int_cst_p (vr) + && !TREE_OVERFLOW (vr->min) + && !TREE_OVERFLOW (vr->max) && tree_int_cst_equal (vr->min, vr->max)); } @@ -1970,7 +1970,9 @@ zero_nonzero_bits_from_vr (value_range_t *vr, { *may_be_nonzero = double_int_minus_one; *must_be_nonzero = double_int_zero; - if (!range_int_cst_p (vr)) + if (!range_int_cst_p (vr) + || TREE_OVERFLOW (vr->min) + || TREE_OVERFLOW (vr->max)) return false; if (range_int_cst_singleton_p (vr)) @@ -2376,39 +2378,161 @@ extract_range_from_binary_expr_1 (value_range_t *vr, range and see what we end up with. */ if (code == PLUS_EXPR) { - /* If we have a PLUS_EXPR with two VR_ANTI_RANGEs, drop to - VR_VARYING. It would take more effort to compute a precise - range for such a case. For example, if we have op0 == 1 and - op1 == -1 with their ranges both being ~[0,0], we would have - op0 + op1 == 0, so we cannot claim that the sum is in ~[0,0]. - Note that we are guaranteed to have vr0.type == vr1.type at - this point. */ - if (vr0.type == VR_ANTI_RANGE) + /* If we have a PLUS_EXPR with two VR_RANGE integer constant + ranges compute the precise range for such case if possible. */ + if (range_int_cst_p (&vr0) + && range_int_cst_p (&vr1) + /* We attempt to do infinite precision signed integer arithmetic, + thus we need two more bits than the possibly unsigned inputs. */ + && TYPE_PRECISION (expr_type) < HOST_BITS_PER_DOUBLE_INT - 1) { + double_int min0 = tree_to_double_int (vr0.min); + double_int max0 = tree_to_double_int (vr0.max); + double_int min1 = tree_to_double_int (vr1.min); + double_int max1 = tree_to_double_int (vr1.max); + bool uns = TYPE_UNSIGNED (expr_type); + double_int type_min + = double_int_min_value (TYPE_PRECISION (expr_type), uns); + double_int type_max + = double_int_max_value (TYPE_PRECISION (expr_type), uns); + double_int dmin, dmax; + + dmin = double_int_add (min0, min1); + dmax = double_int_add (max0, max1); + + if (TYPE_OVERFLOW_WRAPS (expr_type)) + { + /* If overflow wraps, truncate the values and adjust the + range kind and bounds appropriately. */ + double_int tmin + = double_int_ext (dmin, TYPE_PRECISION (expr_type), uns); + double_int tmax + = double_int_ext (dmax, TYPE_PRECISION (expr_type), uns); + gcc_assert (double_int_scmp (dmin, dmax) <= 0); + if ((double_int_scmp (dmin, type_min) == -1 + && double_int_scmp (dmax, type_min) == -1) + || (double_int_scmp (dmin, type_max) == 1 + && double_int_scmp (dmax, type_max) == 1) + || (double_int_scmp (type_min, dmin) <= 0 + && double_int_scmp (dmax, type_max) <= 0)) + { + /* No overflow or both overflow or underflow. The + range kind stays VR_RANGE. */ + min = double_int_to_tree (expr_type, tmin); + max = double_int_to_tree (expr_type, tmax); + } + else if (double_int_scmp (dmin, type_min) == -1 + && double_int_scmp (dmax, type_max) == 1) + { + /* Underflow and overflow, drop to VR_VARYING. */ + set_value_range_to_varying (vr); + return; + } + else + { + /* Min underflow or max overflow. The range kind + changes to VR_ANTI_RANGE. */ + double_int tem = tmin; + gcc_assert ((double_int_scmp (dmin, type_min) == -1 + && double_int_scmp (dmax, type_min) >= 0 + && double_int_scmp (dmax, type_max) <= 0) + || (double_int_scmp (dmax, type_max) == 1 + && double_int_scmp (dmin, type_min) >= 0 + && double_int_scmp (dmin, type_max) <= 0)); + type = VR_ANTI_RANGE; + tmin = double_int_add (tmax, double_int_one); + tmax = double_int_add (tem, double_int_minus_one); + /* If the anti-range would cover nothing, drop to varying. + Likewise if the anti-range bounds are outside of the + types values. */ + if (double_int_cmp (tmin, tmax, uns) > 0 + || double_int_cmp (tmin, type_min, uns) < 0 + || double_int_cmp (tmax, type_max, uns) > 0) + { + set_value_range_to_varying (vr); + return; + } + min = double_int_to_tree (expr_type, tmin); + max = double_int_to_tree (expr_type, tmax); + } + } + else + { + /* For non-wrapping arithmetic look at possibly smaller + value-ranges of the type. */ + if (vrp_val_min (expr_type)) + type_min = tree_to_double_int (vrp_val_min (expr_type)); + if (vrp_val_max (expr_type)) + type_max = tree_to_double_int (vrp_val_max (expr_type)); + + /* If overflow does not wrap, saturate to the types min/max + value. */ + if (double_int_scmp (dmin, type_min) == -1) + { + if (needs_overflow_infinity (expr_type) + && supports_overflow_infinity (expr_type)) + min = negative_overflow_infinity (expr_type); + else + min = double_int_to_tree (expr_type, type_min); + } + else if (double_int_scmp (dmin, type_max) == 1) + { + if (needs_overflow_infinity (expr_type) + && supports_overflow_infinity (expr_type)) + min = positive_overflow_infinity (expr_type); + else + min = double_int_to_tree (expr_type, type_max); + } + else + min = double_int_to_tree (expr_type, dmin); + + if (double_int_scmp (dmax, type_min) == -1) + { + if (needs_overflow_infinity (expr_type) + && supports_overflow_infinity (expr_type)) + max = negative_overflow_infinity (expr_type); + else + max = double_int_to_tree (expr_type, type_min); + } + else if (double_int_scmp (dmax, type_max) == 1) + { + if (needs_overflow_infinity (expr_type) + && supports_overflow_infinity (expr_type)) + max = positive_overflow_infinity (expr_type); + else + max = double_int_to_tree (expr_type, type_max); + } + else + max = double_int_to_tree (expr_type, dmax); + } + if (needs_overflow_infinity (expr_type) + && supports_overflow_infinity (expr_type)) + { + if (is_negative_overflow_infinity (vr0.min) + || is_negative_overflow_infinity (vr1.min)) + min = negative_overflow_infinity (expr_type); + if (is_positive_overflow_infinity (vr0.max) + || is_positive_overflow_infinity (vr1.max)) + max = positive_overflow_infinity (expr_type); + } + } + else + { + /* For other cases, for example if we have a PLUS_EXPR with two + VR_ANTI_RANGEs, drop to VR_VARYING. It would take more effort + to compute a precise range for such a case. + ??? General even mixed range kind operations can be expressed + by for example transforming ~[3, 5] + [1, 2] to range-only + operations and a union primitive: + [-INF, 2] + [1, 2] U [5, +INF] + [1, 2] + [-INF+1, 4] U [6, +INF(OVF)] + though usually the union is not exactly representable with + a single range or anti-range as the above is + [-INF+1, +INF(OVF)] intersected with ~[5, 5] + but one could use a scheme similar to equivalences for this. */ set_value_range_to_varying (vr); return; } - - /* For operations that make the resulting range directly - proportional to the original ranges, apply the operation to - the same end of each range. */ - min = vrp_int_const_binop (code, vr0.min, vr1.min); - max = vrp_int_const_binop (code, vr0.max, vr1.max); - - /* If both additions overflowed the range kind is still correct. - This happens regularly with subtracting something in unsigned - arithmetic. - ??? See PR30318 for all the cases we do not handle. */ - if ((TREE_OVERFLOW (min) && !is_overflow_infinity (min)) - && (TREE_OVERFLOW (max) && !is_overflow_infinity (max))) - { - min = build_int_cst_wide (TREE_TYPE (min), - TREE_INT_CST_LOW (min), - TREE_INT_CST_HIGH (min)); - max = build_int_cst_wide (TREE_TYPE (max), - TREE_INT_CST_LOW (max), - TREE_INT_CST_HIGH (max)); - } } else if (code == MIN_EXPR || code == MAX_EXPR) @@ -7067,8 +7191,7 @@ intersect_ranges (enum value_range_type *vr0type, /* [ ] ( ) or ( ) [ ] If the ranges have an empty intersection, the result of the intersect operation is the range for intersecting an - anti-range with a range or empty when intersecting two ranges. - For intersecting two anti-ranges simply choose vr0. */ + anti-range with a range or empty when intersecting two ranges. */ if (*vr0type == VR_RANGE && vr1type == VR_ANTI_RANGE) ; @@ -7089,7 +7212,20 @@ intersect_ranges (enum value_range_type *vr0type, else if (*vr0type == VR_ANTI_RANGE && vr1type == VR_ANTI_RANGE) { - /* Take VR0. */ + /* If the anti-ranges are adjacent to each other merge them. */ + if (TREE_CODE (*vr0max) == INTEGER_CST + && TREE_CODE (vr1min) == INTEGER_CST + && operand_less_p (*vr0max, vr1min) == 1 + && integer_onep (int_const_binop (MINUS_EXPR, + vr1min, *vr0max))) + *vr0max = vr1max; + else if (TREE_CODE (vr1max) == INTEGER_CST + && TREE_CODE (*vr0min) == INTEGER_CST + && operand_less_p (vr1max, *vr0min) == 1 + && integer_onep (int_const_binop (MINUS_EXPR, + *vr0min, vr1max))) + *vr0min = vr1min; + /* Else arbitrarily take VR0. */ } } else if ((maxeq || operand_less_p (vr1max, *vr0max) == 1)