diff options
author | Aldy Hernandez <aldyh@redhat.com> | 2022-07-31 13:43:36 +0200 |
---|---|---|
committer | Aldy Hernandez <aldyh@redhat.com> | 2022-08-01 08:16:03 +0200 |
commit | 3f05605364f6f17b84842a8a5960d465b4448bae (patch) | |
tree | f74fe9fd71c1f3bf256bd602b38066909f26ba26 /gcc | |
parent | 7e029e067d81f714419cd196fdd506b06881e0c9 (diff) | |
download | gcc-3f05605364f6f17b84842a8a5960d465b4448bae.zip gcc-3f05605364f6f17b84842a8a5960d465b4448bae.tar.gz gcc-3f05605364f6f17b84842a8a5960d465b4448bae.tar.bz2 |
Cleanups to frange.
These are some assorted cleanups to the frange class to make it easier
to drop in an implementation with FP endpoints:
* frange::set() had some asserts limiting the type of arguments
passed. There's no reason why we can't handle all the variants.
Worse comes to worse, we can always return a VARYING which is
conservative and correct.
* frange::normalize_kind() now returns a boolean that can be used in
union and intersection to indicate that the range changed.
* Implement vrp_val_max and vrp_val_min for floats. Also, move them
earlier in the header file so frange can use them.
Tested on x86-64 Linux.
gcc/ChangeLog:
* value-range.cc (tree_compare): New.
(frange::set): Make more general.
(frange::normalize_kind): Cleanup and return bool.
(frange::union_): Use normalize_kind return value.
(frange::intersect): Same.
(frange::verify_range): Remove unnecessary else.
* value-range.h (vrp_val_max): Move before frange class.
(vrp_val_min): Same.
(frange::frange): Remove set to m_type.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/value-range.cc | 102 | ||||
-rw-r--r-- | gcc/value-range.h | 70 |
2 files changed, 105 insertions, 67 deletions
diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 7adbf55..dc06f8b 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -260,66 +260,93 @@ frange::accept (const vrange_visitor &v) const v.visit (*this); } -// Setter for franges. Currently only singletons are supported. +// Helper function to compare floats. Returns TRUE if op1 .CODE. op2 +// is nonzero. + +static inline bool +tree_compare (tree_code code, tree op1, tree op2) +{ + return !integer_zerop (fold_build2 (code, integer_type_node, op1, op2)); +} + +// Setter for franges. void frange::set (tree min, tree max, value_range_kind kind) { - gcc_checking_assert (kind == VR_RANGE); - gcc_checking_assert (operand_equal_p (min, max)); gcc_checking_assert (TREE_CODE (min) == REAL_CST); + gcc_checking_assert (TREE_CODE (max) == REAL_CST); + + if (kind == VR_UNDEFINED) + { + set_undefined (); + return; + } + + // Treat VR_ANTI_RANGE and VR_VARYING as varying. + if (kind != VR_RANGE) + { + set_varying (TREE_TYPE (min)); + return; + } m_kind = kind; m_type = TREE_TYPE (min); - REAL_VALUE_TYPE *const cst = TREE_REAL_CST_PTR (min); - if (real_isnan (cst)) - m_props.nan_set_yes (); - else - m_props.nan_set_no (); - - if (real_isinf (cst)) + // Mark NANness. + if (real_isnan (TREE_REAL_CST_PTR (min)) + || real_isnan (TREE_REAL_CST_PTR (max))) { - if (real_isneg (cst)) - { - m_props.inf_set_no (); - m_props.ninf_set_yes (); - } - else - { - m_props.inf_set_yes (); - m_props.ninf_set_no (); - } + gcc_checking_assert (operand_equal_p (min, max)); + m_props.nan_set_yes (); } else + m_props.nan_set_no (); + + bool is_min = vrp_val_is_min (min); + bool is_max = vrp_val_is_max (max); + + // Mark when the endpoints can't be INF. + if (!is_min) + m_props.ninf_set_no (); + if (!is_max) + m_props.inf_set_no (); + + // Mark when the endpoints are definitely INF. + if (operand_equal_p (min, max)) { - m_props.inf_set_no (); - m_props.ninf_set_no (); + if (is_min) + m_props.ninf_set_yes (); + else if (is_max) + m_props.inf_set_yes (); } + // Check for swapped ranges. + gcc_checking_assert (m_props.nan_yes_p () + || tree_compare (LE_EXPR, min, max)); + if (flag_checking) verify_range (); } -// Normalize range to VARYING or UNDEFINED, or vice versa. +// Normalize range to VARYING or UNDEFINED, or vice versa. Return +// TRUE if anything changed. // // A range with no known properties can be dropped to VARYING. // Similarly, a VARYING with any properties should be dropped to a // VR_RANGE. Normalizing ranges upon changing them ensures there is // only one representation for a given range. -void +bool frange::normalize_kind () { if (m_kind == VR_RANGE) { // No FP properties set means varying. - if (m_props.nan_varying_p () - && m_props.inf_varying_p () - && m_props.ninf_varying_p ()) + if (m_props.varying_p ()) { set_varying (m_type); - return; + return true; } // Undefined is viral. if (m_props.nan_undefined_p () @@ -327,17 +354,19 @@ frange::normalize_kind () || m_props.ninf_undefined_p ()) { set_undefined (); - return; + return true; } } else if (m_kind == VR_VARYING) { // If a VARYING has any FP properties, it's no longer VARYING. - if (!m_props.nan_varying_p () - || !m_props.inf_varying_p () - || !m_props.ninf_varying_p ()) - m_kind = VR_RANGE; + if (!m_props.varying_p ()) + { + m_kind = VR_RANGE; + return true; + } } + return false; } bool @@ -354,7 +383,7 @@ frange::union_ (const vrange &v) } bool ret = m_props.union_ (r.m_props); - normalize_kind (); + ret |= normalize_kind (); if (flag_checking) verify_range (); @@ -380,7 +409,7 @@ frange::intersect (const vrange &v) } bool ret = m_props.intersect (r.m_props); - normalize_kind (); + ret |= normalize_kind (); if (flag_checking) verify_range (); @@ -429,12 +458,11 @@ frange::verify_range () gcc_checking_assert (m_props.undefined_p ()); return; } - else if (varying_p ()) + if (varying_p ()) { gcc_checking_assert (m_props.varying_p ()); return; } - gcc_checking_assert (m_kind == VR_RANGE); gcc_checking_assert (!m_props.varying_p () && !m_props.undefined_p ()); } diff --git a/gcc/value-range.h b/gcc/value-range.h index c6ab955..390fcb8 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -359,7 +359,7 @@ public: FRANGE_PROP_ACCESSOR(ninf) private: void verify_range (); - void normalize_kind (); + bool normalize_kind (); frange_props m_props; tree m_type; @@ -1010,6 +1010,45 @@ irange::normalize_kind () } } +// Return the maximum value for TYPE. + +inline tree +vrp_val_max (const_tree type) +{ + if (INTEGRAL_TYPE_P (type)) + return TYPE_MAX_VALUE (type); + if (POINTER_TYPE_P (type)) + { + wide_int max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)); + return wide_int_to_tree (const_cast<tree> (type), max); + } + if (frange::supports_p (type)) + { + REAL_VALUE_TYPE real; + real_inf (&real); + return build_real (const_cast <tree> (type), real); + } + return NULL_TREE; +} + +// Return the minimum value for TYPE. + +inline tree +vrp_val_min (const_tree type) +{ + if (INTEGRAL_TYPE_P (type)) + return TYPE_MIN_VALUE (type); + if (POINTER_TYPE_P (type)) + return build_zero_cst (const_cast<tree> (type)); + if (frange::supports_p (type)) + { + REAL_VALUE_TYPE real, real_ninf; + real_inf (&real); + real_ninf = real_value_negate (&real); + return build_real (const_cast <tree> (type), real_ninf); + } + return NULL_TREE; +} // Supporting methods for frange. @@ -1039,7 +1078,6 @@ inline frange::frange () { m_discriminator = VR_FRANGE; - m_type = nullptr; set_undefined (); } @@ -1072,32 +1110,4 @@ frange::set_undefined () m_props.set_undefined (); } - -// Return the maximum value for TYPE. - -inline tree -vrp_val_max (const_tree type) -{ - if (INTEGRAL_TYPE_P (type)) - return TYPE_MAX_VALUE (type); - if (POINTER_TYPE_P (type)) - { - wide_int max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)); - return wide_int_to_tree (const_cast<tree> (type), max); - } - return NULL_TREE; -} - -// Return the minimum value for TYPE. - -inline tree -vrp_val_min (const_tree type) -{ - if (INTEGRAL_TYPE_P (type)) - return TYPE_MIN_VALUE (type); - if (POINTER_TYPE_P (type)) - return build_zero_cst (const_cast<tree> (type)); - return NULL_TREE; -} - #endif // GCC_VALUE_RANGE_H |