Skip to content

Commit 606a997

Browse files
authored
[flang] Fix SCALE() folding with big scale factors (#85576)
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.
1 parent 0007d7e commit 606a997

File tree

2 files changed

+23
-9
lines changed

2 files changed

+23
-9
lines changed

flang/include/flang/Evaluate/real.h

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -221,20 +221,33 @@ class Real : public common::RealDetails<PREC> {
221221
// Normalize a fraction with just its LSB set and then multiply.
222222
// (Set the LSB, not the MSB, in case the scale factor needs to
223223
// be subnormal.)
224-
auto adjust{exponentBias + binaryPrecision - 1};
224+
constexpr auto adjust{exponentBias + binaryPrecision - 1};
225+
constexpr auto maxCoeffExpo{maxExponent + binaryPrecision - 1};
225226
auto expo{adjust + by.ToInt64()};
226-
Real twoPow;
227227
RealFlags flags;
228228
int rMask{1};
229229
if (IsZero()) {
230230
expo = exponentBias; // ignore by, don't overflow
231-
} else if (by > INT{maxExponent}) {
232-
expo = maxExponent + binaryPrecision - 1;
233-
} else if (by < INT{-adjust}) { // underflow
234-
expo = 0;
235-
rMask = 0;
236-
flags.set(RealFlag::Underflow);
231+
} else if (expo > maxCoeffExpo) {
232+
if (Exponent() < exponentBias) {
233+
// Must implement with two multiplications
234+
return SCALE(INT{exponentBias})
235+
.value.SCALE(by.SubtractSigned(INT{exponentBias}).value, rounding);
236+
} else { // overflow
237+
expo = maxCoeffExpo;
238+
}
239+
} else if (expo < 0) {
240+
if (Exponent() > exponentBias) {
241+
// Must implement with two multiplications
242+
return SCALE(INT{-exponentBias})
243+
.value.SCALE(by.AddSigned(INT{exponentBias}).value, rounding);
244+
} else { // underflow to zero
245+
expo = 0;
246+
rMask = 0;
247+
flags.set(RealFlag::Underflow);
248+
}
237249
}
250+
Real twoPow;
238251
flags |=
239252
twoPow.Normalize(false, static_cast<int>(expo), Fraction::MASKR(rMask));
240253
ValueWithRealFlags<Real> result{Multiply(twoPow, rounding)};

flang/test/Evaluate/fold-scale.f90

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ module m
77
logical, parameter :: test_4 = sign(1.0, scale(0.0, 0)) == 1.0
88
logical, parameter :: test_5 = scale(1.0, -1) == 0.5
99
logical, parameter :: test_6 = scale(2.0, -1) == 1.0
10+
logical, parameter :: test_7 = scale(huge(0.d0), -1200) == 1.0440487148797638d-53
11+
logical, parameter :: test_8 = scale(tiny(0.d0), 1200) == 3.8312388521647221d053
1012
end module
11-

0 commit comments

Comments
 (0)