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 ()
|| 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
}
bool ret = m_props.union_ (r.m_props);
- normalize_kind ();
+ ret |= normalize_kind ();
if (flag_checking)
verify_range ();
}
bool ret = m_props.intersect (r.m_props);
- normalize_kind ();
+ ret |= normalize_kind ();
if (flag_checking)
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 ());
}
FRANGE_PROP_ACCESSOR(ninf)
private:
void verify_range ();
- void normalize_kind ();
+ bool normalize_kind ();
frange_props m_props;
tree m_type;
}
}
+// 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.
frange::frange ()
{
m_discriminator = VR_FRANGE;
- m_type = nullptr;
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