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.
This commit is contained in:
Aldy Hernandez 2022-07-31 13:43:36 +02:00
parent 7e029e067d
commit 3f05605364
2 changed files with 105 additions and 67 deletions

View File

@ -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 ();
// Mark NANness.
if (real_isnan (TREE_REAL_CST_PTR (min))
|| real_isnan (TREE_REAL_CST_PTR (max)))
{
gcc_checking_assert (operand_equal_p (min, max));
m_props.nan_set_yes ();
}
else
m_props.nan_set_no ();
if (real_isinf (cst))
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))
{
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 ();
}
}
else
{
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 ());
}

View File

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