Skip to content

Commit

Permalink
[flang] Fix SCALE() folding with big scale factors (#85576)
Browse files Browse the repository at this point in the history
The folding of the SCALE() intrinsic function is implemented via
multiplication by a power of two; this simplifies handling of
exceptional cases. But sometimes scaling by a power of two requires an
exponent larger or smaller than a floating-point format can represent,
and two multiplications are required.
  • Loading branch information
klausler committed Mar 18, 2024
1 parent 0007d7e commit 606a997
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 9 deletions.
29 changes: 21 additions & 8 deletions flang/include/flang/Evaluate/real.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,20 +221,33 @@ class Real : public common::RealDetails<PREC> {
// 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};
constexpr auto adjust{exponentBias + binaryPrecision - 1};
constexpr auto maxCoeffExpo{maxExponent + binaryPrecision - 1};
auto expo{adjust + by.ToInt64()};
Real twoPow;
RealFlags flags;
int rMask{1};
if (IsZero()) {
expo = exponentBias; // ignore by, don't overflow
} else if (by > INT{maxExponent}) {
expo = maxExponent + binaryPrecision - 1;
} else if (by < INT{-adjust}) { // underflow
expo = 0;
rMask = 0;
flags.set(RealFlag::Underflow);
} else if (expo > maxCoeffExpo) {
if (Exponent() < exponentBias) {
// Must implement with two multiplications
return SCALE(INT{exponentBias})
.value.SCALE(by.SubtractSigned(INT{exponentBias}).value, rounding);
} else { // overflow
expo = maxCoeffExpo;
}
} else if (expo < 0) {
if (Exponent() > exponentBias) {
// Must implement with two multiplications
return SCALE(INT{-exponentBias})
.value.SCALE(by.AddSigned(INT{exponentBias}).value, rounding);
} else { // underflow to zero
expo = 0;
rMask = 0;
flags.set(RealFlag::Underflow);
}
}
Real twoPow;
flags |=
twoPow.Normalize(false, static_cast<int>(expo), Fraction::MASKR(rMask));
ValueWithRealFlags<Real> result{Multiply(twoPow, rounding)};
Expand Down
3 changes: 2 additions & 1 deletion flang/test/Evaluate/fold-scale.f90
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ module m
logical, parameter :: test_4 = sign(1.0, scale(0.0, 0)) == 1.0
logical, parameter :: test_5 = scale(1.0, -1) == 0.5
logical, parameter :: test_6 = scale(2.0, -1) == 1.0
logical, parameter :: test_7 = scale(huge(0.d0), -1200) == 1.0440487148797638d-53
logical, parameter :: test_8 = scale(tiny(0.d0), 1200) == 3.8312388521647221d053
end module

0 comments on commit 606a997

Please sign in to comment.