Commit 150655ee by Aldy Hernandez Committed by Aldy Hernandez

wide-int-range.cc (wide_int_range_convert): New.

	* wide-int-range.cc (wide_int_range_convert): New.
	* wide-int-range.h (wide_int_range_convert): New.
	* tree-vrp.c (extract_range_from_unary_expr): Abstract wide int
	code into wide_int_range_convert.
	(extract_range_into_wide_ints): Do not munge anti range constants
	into the entire domain.  Just return the range back.

From-SVN: r264085
parent 8fcfe047
2018-09-04 Aldy Hernandez <aldyh@redhat.com>
* wide-int-range.cc (wide_int_range_convert): New.
* wide-int-range.h (wide_int_range_convert): New.
* tree-vrp.c (extract_range_from_unary_expr): Abstract wide int
code into wide_int_range_convert.
(extract_range_into_wide_ints): Do not munge anti range constants
into the entire domain. Just return the range back.
2018-09-04 Martin Liska <mliska@suse.cz> 2018-09-04 Martin Liska <mliska@suse.cz>
* genmatch.c (output_line_directive): Add new argument * genmatch.c (output_line_directive): Add new argument
......
...@@ -995,7 +995,7 @@ ranges_from_anti_range (const value_range *ar, ...@@ -995,7 +995,7 @@ ranges_from_anti_range (const value_range *ar,
/* Extract the components of a value range into a pair of wide ints in /* Extract the components of a value range into a pair of wide ints in
[WMIN, WMAX]. [WMIN, WMAX].
If the value range is anything but a VR_RANGE of constants, the If the value range is anything but a VR_*RANGE of constants, the
resulting wide ints are set to [-MIN, +MAX] for the type. */ resulting wide ints are set to [-MIN, +MAX] for the type. */
static void inline static void inline
...@@ -1003,7 +1003,10 @@ extract_range_into_wide_ints (const value_range *vr, ...@@ -1003,7 +1003,10 @@ extract_range_into_wide_ints (const value_range *vr,
signop sign, unsigned prec, signop sign, unsigned prec,
wide_int &wmin, wide_int &wmax) wide_int &wmin, wide_int &wmax)
{ {
if (range_int_cst_p (vr)) if ((vr->type == VR_RANGE
|| vr->type == VR_ANTI_RANGE)
&& TREE_CODE (vr->min) == INTEGER_CST
&& TREE_CODE (vr->max) == INTEGER_CST)
{ {
wmin = wi::to_wide (vr->min); wmin = wi::to_wide (vr->min);
wmax = wi::to_wide (vr->max); wmax = wi::to_wide (vr->max);
...@@ -1850,43 +1853,40 @@ extract_range_from_unary_expr (value_range *vr, ...@@ -1850,43 +1853,40 @@ extract_range_from_unary_expr (value_range *vr,
return; return;
} }
/* If VR0 is varying and we increase the type precision, assume /* We normalize everything to a VR_RANGE, but for constant
a full range for the following transformation. */ anti-ranges we must handle them by leaving the final result
if (vr0.type == VR_VARYING as an anti range. This allows us to convert things like
&& INTEGRAL_TYPE_P (inner_type) ~[0,5] seamlessly. */
&& TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type)) value_range_type vr_type = VR_RANGE;
{ if (vr0.type == VR_ANTI_RANGE
vr0.type = VR_RANGE;
vr0.min = TYPE_MIN_VALUE (inner_type);
vr0.max = TYPE_MAX_VALUE (inner_type);
}
/* If VR0 is a constant range or anti-range and the conversion is
not truncating we can convert the min and max values and
canonicalize the resulting range. Otherwise we can do the
conversion if the size of the range is less than what the
precision of the target type can represent and the range is
not an anti-range. */
if ((vr0.type == VR_RANGE
|| vr0.type == VR_ANTI_RANGE)
&& TREE_CODE (vr0.min) == INTEGER_CST && TREE_CODE (vr0.min) == INTEGER_CST
&& TREE_CODE (vr0.max) == INTEGER_CST && TREE_CODE (vr0.max) == INTEGER_CST)
&& (TYPE_PRECISION (outer_type) >= TYPE_PRECISION (inner_type) vr_type = VR_ANTI_RANGE;
|| (vr0.type == VR_RANGE
&& integer_zerop (int_const_binop (RSHIFT_EXPR, /* NOTES: Previously we were returning VARYING for all symbolics, but
int_const_binop (MINUS_EXPR, vr0.max, vr0.min), we can do better by treating them as [-MIN, +MAX]. For
size_int (TYPE_PRECISION (outer_type))))))) example, converting [SYM, SYM] from INT to LONG UNSIGNED,
{ we can return: ~[0x8000000, 0xffffffff7fffffff].
tree new_min, new_max;
new_min = force_fit_type (outer_type, wi::to_widest (vr0.min), We were also failing to convert ~[0,0] from char* to unsigned,
0, false); instead choosing to return VR_VARYING. Now we return ~[0,0]. */
new_max = force_fit_type (outer_type, wi::to_widest (vr0.max), wide_int vr0_min, vr0_max, wmin, wmax;
0, false); signop inner_sign = TYPE_SIGN (inner_type);
set_and_canonicalize_value_range (vr, vr0.type, signop outer_sign = TYPE_SIGN (outer_type);
new_min, new_max, NULL); unsigned inner_prec = TYPE_PRECISION (inner_type);
return; unsigned outer_prec = TYPE_PRECISION (outer_type);
extract_range_into_wide_ints (&vr0, inner_sign, inner_prec,
vr0_min, vr0_max);
if (wide_int_range_convert (wmin, wmax,
inner_sign, inner_prec,
outer_sign, outer_prec,
vr0_min, vr0_max))
{
tree min = wide_int_to_tree (outer_type, wmin);
tree max = wide_int_to_tree (outer_type, wmax);
set_and_canonicalize_value_range (vr, vr_type, min, max, NULL);
} }
else
set_value_range_to_varying (vr); set_value_range_to_varying (vr);
return; return;
} }
......
...@@ -735,6 +735,39 @@ wide_int_range_abs (wide_int &min, wide_int &max, ...@@ -735,6 +735,39 @@ wide_int_range_abs (wide_int &min, wide_int &max,
return true; return true;
} }
/* Convert range in [VR0_MIN, VR0_MAX] with INNER_SIGN and INNER_PREC,
to a range in [MIN, MAX] with OUTER_SIGN and OUTER_PREC.
Return TRUE if we were able to successfully calculate the new range.
Caller is responsible for canonicalizing the resulting range. */
bool
wide_int_range_convert (wide_int &min, wide_int &max,
signop inner_sign,
unsigned inner_prec,
signop outer_sign,
unsigned outer_prec,
const wide_int &vr0_min,
const wide_int &vr0_max)
{
/* If the conversion is not truncating we can convert the min and
max values and canonicalize the resulting range. Otherwise we
can do the conversion if the size of the range is less than what
the precision of the target type can represent. */
if (outer_prec >= inner_prec
|| wi::rshift (wi::sub (vr0_max, vr0_min),
wi::uhwi (outer_prec, inner_prec),
inner_sign) == 0)
{
min = wide_int::from (vr0_min, outer_prec, inner_sign);
max = wide_int::from (vr0_max, outer_prec, inner_sign);
return (!wi::eq_p (min, wi::min_value (outer_prec, outer_sign))
|| !wi::eq_p (max, wi::max_value (outer_prec, outer_sign)));
}
return false;
}
/* Calculate a division operation on two ranges and store the result in /* Calculate a division operation on two ranges and store the result in
[WMIN, WMAX] U [EXTRA_MIN, EXTRA_MAX]. [WMIN, WMAX] U [EXTRA_MIN, EXTRA_MAX].
......
...@@ -109,6 +109,13 @@ extern bool wide_int_range_abs (wide_int &min, wide_int &max, ...@@ -109,6 +109,13 @@ extern bool wide_int_range_abs (wide_int &min, wide_int &max,
const wide_int &vr0_min, const wide_int &vr0_min,
const wide_int &vr0_max, const wide_int &vr0_max,
bool overflow_undefined); bool overflow_undefined);
extern bool wide_int_range_convert (wide_int &min, wide_int &max,
signop inner_sign,
unsigned inner_prec,
signop outer_sign,
unsigned outer_prec,
const wide_int &vr0_min,
const wide_int &vr0_max);
extern bool wide_int_range_div (wide_int &wmin, wide_int &wmax, extern bool wide_int_range_div (wide_int &wmin, wide_int &wmax,
enum tree_code code, enum tree_code code,
signop sign, unsigned prec, signop sign, unsigned prec,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment