Hello,here is a slight improvement to VRP for sum and difference of intervals. There are some things I left because I didn't understand them enough:
* range_int_cst_p (&vr0): I thought it was always true by that time, but it isn't obvious
* TYPE_PRECISION (expr_type) <= HOST_BITS_PER_DOUBLE_INT: the __int256 patch scared me (though I would love to have larger types, especially with a proper range analysis to use only 2 or 3 of the 4 64-bit integers that make up an __int256 when it is enough, see PR 53100 for the __int128 version)
* when is the value range of a type smaller than the one given by its precision? Is it for enum?
2012-07-25 Marc Glisse <marc.gli...@inria.fr> PR tree-optimization/30318 * tree-vrp.c (extract_range_from_binary_expr_1) [PLUS_EXPR]: Handle __int128. [MINUS_EXPR] merge with PLUS_EXPR. bootstrapped just c and c++ and ran the testsuite with no new regression. -- Marc Glisse
Index: tree-vrp.c =================================================================== --- tree-vrp.c (revision 189779) +++ tree-vrp.c (working copy) @@ -2345,157 +2345,194 @@ extract_range_from_binary_expr_1 (value_ set_value_range_to_varying (vr); } else set_value_range_to_varying (vr); return; } /* For integer ranges, apply the operation to each end of the range and see what we end up with. */ - if (code == PLUS_EXPR) + if (code == PLUS_EXPR || code == MINUS_EXPR) { /* 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) + /* We need as many bits as the possibly unsigned inputs. */ + && TYPE_PRECISION (expr_type) <= HOST_BITS_PER_DOUBLE_INT) { 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; + int min_ovf = 0; + int max_ovf = 0; - dmin = double_int_add (min0, min1); - dmax = double_int_add (max0, max1); + if (code == PLUS_EXPR) + { + dmin = double_int_add (min0, min1); + dmax = double_int_add (max0, max1); + + /* Check for overflow in double_int. */ + if (double_int_cmp (min1, double_int_zero, uns) + != double_int_cmp (dmin, min0, uns)) + min_ovf = double_int_cmp (min0, dmin, uns); + if (double_int_cmp (max1, double_int_zero, uns) + != double_int_cmp (dmax, max0, uns)) + max_ovf = double_int_cmp (max0, dmax, uns); + } + else /* if (code == MINUS_EXPR) */ + { + dmin = double_int_sub (min0, max1); + dmax = double_int_sub (max0, min1); + + if (double_int_cmp (double_int_zero, max1, uns) + != double_int_cmp (dmin, min0, uns)) + min_ovf = double_int_cmp (min0, max1, uns); + if (double_int_cmp (double_int_zero, min1, uns) + != double_int_cmp (dmax, max0, uns)) + max_ovf = double_int_cmp (max0, min1, uns); + } + + /* For non-wrapping arithmetic look at possibly smaller + value-ranges of the type. */ + if (!TYPE_OVERFLOW_WRAPS (expr_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)); + } + + /* Check for type overflow. */ + if (min_ovf == 0) + { + if (double_int_cmp (dmin, type_min, uns) == -1) + min_ovf = -1; + else if (double_int_cmp (dmin, type_max, uns) == 1) + min_ovf = 1; + } + if (max_ovf == 0) + { + if (double_int_cmp (dmax, type_min, uns) == -1) + max_ovf = -1; + else if (double_int_cmp (dmax, type_max, uns) == 1) + max_ovf = 1; + } 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)) + if (min_ovf == max_ovf) { /* 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) + else if (min_ovf == -1 + && max_ovf == 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)); + gcc_assert ((min_ovf == -1 && max_ovf == 0) + || (max_ovf == 1 && min_ovf == 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 (min_ovf == -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) + else if (min_ovf == 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 (max_ovf == -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) + else if (max_ovf == 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)) + || (code == PLUS_EXPR + ? is_negative_overflow_infinity (vr1.min) + : is_positive_overflow_infinity (vr1.max))) min = negative_overflow_infinity (expr_type); if (is_positive_overflow_infinity (vr0.max) - || is_positive_overflow_infinity (vr1.max)) + || (code == PLUS_EXPR + ? is_positive_overflow_infinity (vr1.max) + : is_negative_overflow_infinity (vr1.min))) 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 @@ -2710,40 +2747,20 @@ extract_range_from_binary_expr_1 (value_ max = vr1.max; max = int_const_binop (MINUS_EXPR, max, integer_one_node); /* If the dividend is non-negative the modulus will be non-negative as well. */ if (TYPE_UNSIGNED (expr_type) || value_range_nonnegative_p (&vr0)) min = build_int_cst (TREE_TYPE (max), 0); else min = fold_unary_to_constant (NEGATE_EXPR, expr_type, max); } - else if (code == MINUS_EXPR) - { - /* If we have a MINUS_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 difference is in - ~[0,0]. Note that we are guaranteed to have - vr0.type == vr1.type at this point. */ - if (vr0.type == VR_ANTI_RANGE) - { - set_value_range_to_varying (vr); - return; - } - - /* For MINUS_EXPR, apply the operation to the opposite ends of - each range. */ - min = vrp_int_const_binop (code, vr0.min, vr1.max); - max = vrp_int_const_binop (code, vr0.max, vr1.min); - } else if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR) { bool int_cst_range0, int_cst_range1; double_int may_be_nonzero0, may_be_nonzero1; double_int must_be_nonzero0, must_be_nonzero1; int_cst_range0 = zero_nonzero_bits_from_vr (&vr0, &may_be_nonzero0, &must_be_nonzero0); int_cst_range1 = zero_nonzero_bits_from_vr (&vr1, &may_be_nonzero1, &must_be_nonzero1);