forked from OSchip/llvm-project
[flang] Handle subnormals while folding SCALE, SET_EXPONENT, & FRACTION
The implementations of folding for the intrinsic functions SCALE and SET_EXPONENT do not cope correctly with numbers in the subnormal range. Fix SCALE, then modify SET_EXPONENT to be a special case of SCALE. Differential Revision: https://reviews.llvm.org/D131099
This commit is contained in:
parent
d1bb3016dd
commit
1d1f5a5251
|
@ -177,17 +177,21 @@ public:
|
|||
template <typename INT>
|
||||
ValueWithRealFlags<Real> SCALE(const INT &by,
|
||||
Rounding rounding = TargetCharacteristics::defaultRounding) const {
|
||||
auto expo{exponentBias + by.ToInt64()};
|
||||
// Normalize a fraction with just its LSB set and then multiply.
|
||||
// (Set the LSB, not the MSB, in case the scale factor needs to
|
||||
// be subnormal.)
|
||||
auto adjust{exponentBias + binaryPrecision - 1};
|
||||
auto expo{adjust + by.ToInt64()};
|
||||
if (IsZero()) {
|
||||
expo = exponentBias; // ignore by, don't overflow
|
||||
} else if (by > INT{maxExponent}) {
|
||||
expo = maxExponent;
|
||||
} else if (by < INT{-exponentBias}) {
|
||||
expo = maxExponent + binaryPrecision - 1;
|
||||
} else if (by < INT{-adjust}) {
|
||||
expo = -1;
|
||||
}
|
||||
Real twoPow;
|
||||
RealFlags flags{
|
||||
twoPow.Normalize(false, static_cast<int>(expo), Fraction::MASKL(1))};
|
||||
twoPow.Normalize(false, static_cast<int>(expo), Fraction::MASKR(1))};
|
||||
ValueWithRealFlags<Real> result{Multiply(twoPow, rounding)};
|
||||
result.flags |= flags;
|
||||
return result;
|
||||
|
|
|
@ -765,9 +765,7 @@ Real<W, P> Real<W, P>::SET_EXPONENT(int expo) const {
|
|||
} else if (IsZero()) {
|
||||
return *this;
|
||||
} else {
|
||||
Real result;
|
||||
result.Normalize(IsNegative(), expo + exponentBias - 1, GetFraction());
|
||||
return result;
|
||||
return SCALE(Integer<32>(expo - UnbiasedExponent() - 1)).value;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -280,5 +280,6 @@ module m
|
|||
logical, parameter :: test_set_exponent_0 = set_exponent(1., 0) == 0.5
|
||||
logical, parameter :: test_set_exponent_1 = set_exponent(1., 1) == 1.
|
||||
logical, parameter :: test_set_exponent_2 = set_exponent(1., 2) == 2.
|
||||
logical, parameter :: test_set_exponent_min = set_exponent(1., -149) == 1.40129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125e-45_4
|
||||
|
||||
end module
|
||||
|
|
Loading…
Reference in New Issue