re PR tree-optimization/30318 (VRP does not create ANTI_RANGEs on overflow)

2012-06-20  Richard Guenther  <rguenther@suse.de>

	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
This commit is contained in:
Richard Guenther 2012-06-20 12:00:20 +00:00 committed by Richard Biener
parent 942ee09149
commit a75f501709
4 changed files with 227 additions and 36 deletions

View File

@ -1,3 +1,15 @@
2012-06-20 Richard Guenther <rguenther@suse.de>
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 <ubizjak@gmail.com>
* config/i386/i386.md (rounding_insn): New int attribute.

View File

@ -1,3 +1,8 @@
2012-06-20 Richard Guenther <rguenther@suse.de>
PR tree-optimization/30318
* gcc.dg/tree-ssa/vrp69.c: New testcase.
2012-06-20 Richard Earnshaw <rearnsha@arm.com>
* g++.dg/debug/dwarf2/nested-3.C: Add ARM comment character to regexp.

View File

@ -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" } } */

View File

@ -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)