diff options
author | Aldy Hernandez <aldyh@redhat.com> | 2018-09-04 14:52:41 +0000 |
---|---|---|
committer | Aldy Hernandez <aldyh@gcc.gnu.org> | 2018-09-04 14:52:41 +0000 |
commit | 150655ee3f7d67672e2cc809f8abe56923491c62 (patch) | |
tree | fab8d76e903fd48987f1fdd63ff2b52124196a9a /gcc | |
parent | 8fcfe0474aed3d43f16d14c92216ec68f35895fd (diff) | |
download | gcc-150655ee3f7d67672e2cc809f8abe56923491c62.zip gcc-150655ee3f7d67672e2cc809f8abe56923491c62.tar.gz gcc-150655ee3f7d67672e2cc809f8abe56923491c62.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/tree-vrp.c | 74 | ||||
-rw-r--r-- | gcc/wide-int-range.cc | 33 | ||||
-rw-r--r-- | gcc/wide-int-range.h | 7 |
4 files changed, 86 insertions, 37 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8cba029..9b0d2d1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +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> * genmatch.c (output_line_directive): Add new argument diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index d29a2c9..8f16713 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -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 [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. */ static void inline @@ -1003,7 +1003,10 @@ extract_range_into_wide_ints (const value_range *vr, signop sign, unsigned prec, 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); wmax = wi::to_wide (vr->max); @@ -1850,44 +1853,41 @@ extract_range_from_unary_expr (value_range *vr, return; } - /* If VR0 is varying and we increase the type precision, assume - a full range for the following transformation. */ - if (vr0.type == VR_VARYING - && INTEGRAL_TYPE_P (inner_type) - && TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type)) - { - 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) + /* We normalize everything to a VR_RANGE, but for constant + anti-ranges we must handle them by leaving the final result + as an anti range. This allows us to convert things like + ~[0,5] seamlessly. */ + value_range_type vr_type = VR_RANGE; + if (vr0.type == VR_ANTI_RANGE && TREE_CODE (vr0.min) == INTEGER_CST - && TREE_CODE (vr0.max) == INTEGER_CST - && (TYPE_PRECISION (outer_type) >= TYPE_PRECISION (inner_type) - || (vr0.type == VR_RANGE - && integer_zerop (int_const_binop (RSHIFT_EXPR, - int_const_binop (MINUS_EXPR, vr0.max, vr0.min), - size_int (TYPE_PRECISION (outer_type))))))) + && TREE_CODE (vr0.max) == INTEGER_CST) + vr_type = VR_ANTI_RANGE; + + /* NOTES: Previously we were returning VARYING for all symbolics, but + we can do better by treating them as [-MIN, +MAX]. For + example, converting [SYM, SYM] from INT to LONG UNSIGNED, + we can return: ~[0x8000000, 0xffffffff7fffffff]. + + We were also failing to convert ~[0,0] from char* to unsigned, + instead choosing to return VR_VARYING. Now we return ~[0,0]. */ + wide_int vr0_min, vr0_max, wmin, wmax; + signop inner_sign = TYPE_SIGN (inner_type); + signop outer_sign = TYPE_SIGN (outer_type); + unsigned inner_prec = TYPE_PRECISION (inner_type); + 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 new_min, new_max; - new_min = force_fit_type (outer_type, wi::to_widest (vr0.min), - 0, false); - new_max = force_fit_type (outer_type, wi::to_widest (vr0.max), - 0, false); - set_and_canonicalize_value_range (vr, vr0.type, - new_min, new_max, NULL); - return; + 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); } - - set_value_range_to_varying (vr); + else + set_value_range_to_varying (vr); return; } else if (code == ABS_EXPR) diff --git a/gcc/wide-int-range.cc b/gcc/wide-int-range.cc index 04d391b..8a3dfd2 100644 --- a/gcc/wide-int-range.cc +++ b/gcc/wide-int-range.cc @@ -735,6 +735,39 @@ wide_int_range_abs (wide_int &min, wide_int &max, 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 [WMIN, WMAX] U [EXTRA_MIN, EXTRA_MAX]. diff --git a/gcc/wide-int-range.h b/gcc/wide-int-range.h index eaf47bc..589fdea 100644 --- a/gcc/wide-int-range.h +++ b/gcc/wide-int-range.h @@ -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_max, 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, enum tree_code code, signop sign, unsigned prec, |