// Implement fold for a cast from float to an int.
bool
-operator_cast::fold_range (irange &, tree, const frange &,
+operator_cast::fold_range (irange &r, tree type, const frange &op1,
const irange &, relation_trio) const
{
- return false;
+ if (empty_range_varying (r, type, op1, op1))
+ return true;
+ if (op1.maybe_isnan () || op1.maybe_isinf ())
+ {
+ r.set_varying (type);
+ return true;
+ }
+ REAL_VALUE_TYPE lb, ub;
+ real_trunc (&lb, VOIDmode, &op1.lower_bound ());
+ real_trunc (&ub, VOIDmode, &op1.upper_bound ());
+ REAL_VALUE_TYPE l, u;
+ l = real_value_from_int_cst (NULL_TREE, TYPE_MIN_VALUE (type));
+ if (real_less (&lb, &l))
+ {
+ r.set_varying (type);
+ return true;
+ }
+ u = real_value_from_int_cst (NULL_TREE, TYPE_MAX_VALUE (type));
+ if (real_less (&u, &ub))
+ {
+ r.set_varying (type);
+ return true;
+ }
+ bool fail = false;
+ wide_int wlb = real_to_integer (&lb, &fail, TYPE_PRECISION (type));
+ wide_int wub = real_to_integer (&ub, &fail, TYPE_PRECISION (type));
+ if (fail)
+ {
+ r.set_varying (type);
+ return true;
+ }
+ r.set (type, wlb, wub);
+ return true;
}
// Implement op1_range for a cast from float to an int.
bool
-operator_cast::op1_range (frange &, tree, const irange &,
- const irange &, relation_trio) const
+operator_cast::op1_range (frange &r, tree type, const irange &lhs,
+ const frange &, relation_trio) const
{
- return false;
+ if (lhs.undefined_p ())
+ return false;
+ REAL_VALUE_TYPE lb, lbo, ub, ubo;
+ wide_int lhs_lb = lhs.lower_bound ();
+ wide_int lhs_ub = lhs.upper_bound ();
+ tree lhs_type = lhs.type ();
+ enum machine_mode mode = TYPE_MODE (type);
+ real_from_integer (&lbo, VOIDmode, lhs_lb, TYPE_SIGN (lhs_type));
+ real_from_integer (&ubo, VOIDmode, lhs_ub, TYPE_SIGN (lhs_type));
+ real_convert (&lb, mode, &lbo);
+ real_convert (&ub, mode, &ubo);
+ if (real_identical (&lb, &lbo))
+ {
+ /* If low bound is exactly representable in type,
+ use nextafter (lb - 1., +inf). */
+ real_arithmetic (&lb, PLUS_EXPR, &lbo, &dconstm1);
+ real_convert (&lb, mode, &lb);
+ if (!real_identical (&lb, &lbo))
+ frange_nextafter (mode, lb, dconstinf);
+ if (real_identical (&lb, &lbo))
+ frange_nextafter (mode, lb, dconstninf);
+ }
+ else if (real_less (&lbo, &lb))
+ frange_nextafter (mode, lb, dconstninf);
+ if (real_identical (&ub, &ubo))
+ {
+ /* If upper bound is exactly representable in type,
+ use nextafter (ub + 1., -inf). */
+ real_arithmetic (&ub, PLUS_EXPR, &ubo, &dconst1);
+ real_convert (&ub, mode, &ub);
+ if (!real_identical (&ub, &ubo))
+ frange_nextafter (mode, ub, dconstninf);
+ if (real_identical (&ub, &ubo))
+ frange_nextafter (mode, ub, dconstinf);
+ }
+ else if (real_less (&ub, &ubo))
+ frange_nextafter (mode, ub, dconstinf);
+ r.set (type, lb, ub, nan_state (false));
+ return true;
}
// Implement fold for a cast from int to a float.
bool
-operator_cast::fold_range (frange &, tree, const irange &,
+operator_cast::fold_range (frange &r, tree type, const irange &op1,
const frange &, relation_trio) const
{
- return false;
+ if (empty_range_varying (r, type, op1, op1))
+ return true;
+ REAL_VALUE_TYPE lb, ub;
+ wide_int op1_lb = op1.lower_bound ();
+ wide_int op1_ub = op1.upper_bound ();
+ tree op1_type = op1.type ();
+ enum machine_mode mode = flag_rounding_math ? VOIDmode : TYPE_MODE (type);
+ real_from_integer (&lb, mode, op1_lb, TYPE_SIGN (op1_type));
+ real_from_integer (&ub, mode, op1_ub, TYPE_SIGN (op1_type));
+ if (flag_rounding_math)
+ {
+ REAL_VALUE_TYPE lbo = lb, ubo = ub;
+ mode = TYPE_MODE (type);
+ real_convert (&lb, mode, &lb);
+ real_convert (&ub, mode, &ub);
+ if (real_less (&lbo, &lb))
+ frange_nextafter (mode, lb, dconstninf);
+ if (real_less (&ub, &ubo))
+ frange_nextafter (mode, ub, dconstinf);
+ }
+ r.set (type, lb, ub, nan_state (false));
+ frange_drop_infs (r, type);
+ if (r.undefined_p ())
+ r.set_varying (type);
+ return true;
}
// Implement op1_range for a cast from int to a float.
bool
-operator_cast::op1_range (irange &, tree, const frange &,
- const frange &, relation_trio) const
+operator_cast::op1_range (irange &r, tree type, const frange &lhs,
+ const irange &, relation_trio) const
{
- return false;
+ if (lhs.undefined_p ())
+ return false;
+ if (lhs.known_isnan ())
+ {
+ r.set_varying (type);
+ return true;
+ }
+ REAL_VALUE_TYPE lb = lhs.lower_bound ();
+ REAL_VALUE_TYPE ub = lhs.upper_bound ();
+ enum machine_mode mode = TYPE_MODE (lhs.type ());
+ frange_nextafter (mode, lb, dconstninf);
+ frange_nextafter (mode, ub, dconstinf);
+ if (flag_rounding_math)
+ {
+ real_floor (&lb, mode, &lb);
+ real_ceil (&ub, mode, &ub);
+ }
+ else
+ {
+ real_trunc (&lb, mode, &lb);
+ real_trunc (&ub, mode, &ub);
+ }
+ REAL_VALUE_TYPE l, u;
+ wide_int wlb, wub;
+ l = real_value_from_int_cst (NULL_TREE, TYPE_MIN_VALUE (type));
+ if (real_less (&lb, &l))
+ wlb = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type));
+ else
+ {
+ bool fail = false;
+ wlb = real_to_integer (&lb, &fail, TYPE_PRECISION (type));
+ if (fail)
+ wlb = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type));
+ }
+ u = real_value_from_int_cst (NULL_TREE, TYPE_MAX_VALUE (type));
+ if (real_less (&u, &ub))
+ wub = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
+ else
+ {
+ bool fail = false;
+ wub = real_to_integer (&ub, &fail, TYPE_PRECISION (type));
+ if (fail)
+ wub = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
+ }
+ r.set (type, wlb, wub);
+ return true;
}
// Initialize any float operators to the primary table
set (INTEGER_CST, op_cst);
set (NOP_EXPR, op_cast);
set (CONVERT_EXPR, op_cast);
+ set (FLOAT_EXPR, op_cast);
+ set (FIX_TRUNC_EXPR, op_cast);
set (PLUS_EXPR, op_plus);
set (ABS_EXPR, op_abs);
set (MINUS_EXPR, op_minus);
// of the routines in range_operator. Note the last 3 characters are
// shorthand for the LHS, OP1, and OP2 range discriminator class.
// Reminder, single operand instructions use the LHS type for op2, even if
-// unused. so FLOAT = INT would be RO_FIF.
+// unused. So FLOAT = INT would be RO_FIF.
const unsigned RO_III = dispatch_trio (VR_IRANGE, VR_IRANGE, VR_IRANGE);
const unsigned RO_IFI = dispatch_trio (VR_IRANGE, VR_FRANGE, VR_IRANGE);
return m_operator->op1_range (as_a <irange> (r), type,
as_a <irange> (lhs),
as_a <irange> (op2), rel);
- case RO_IFF:
+ case RO_IFI:
return m_operator->op1_range (as_a <irange> (r), type,
as_a <frange> (lhs),
- as_a <frange> (op2), rel);
+ as_a <irange> (op2), rel);
case RO_PPP:
return m_operator->op1_range (as_a <prange> (r), type,
as_a <prange> (lhs),
return m_operator->op1_range (as_a <frange> (r), type,
as_a <irange> (lhs),
as_a <frange> (op2), rel);
- case RO_FII:
- return m_operator->op1_range (as_a <frange> (r), type,
- as_a <irange> (lhs),
- as_a <irange> (op2), rel);
case RO_FFF:
return m_operator->op1_range (as_a <frange> (r), type,
as_a <frange> (lhs),
bool
range_operator::op1_range (irange &, tree, const frange &,
- const frange &, relation_trio) const
-{
- return false;
-}
-
-bool
-range_operator::op1_range (frange &, tree, const irange &,
const irange &, relation_trio) const
{
return false;