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:
parent
942ee09149
commit
a75f501709
4 changed files with 227 additions and 36 deletions
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
38
gcc/testsuite/gcc.dg/tree-ssa/vrp69.c
Normal file
38
gcc/testsuite/gcc.dg/tree-ssa/vrp69.c
Normal 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" } } */
|
208
gcc/tree-vrp.c
208
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)
|
||||
|
|
Loading…
Add table
Reference in a new issue