Skip to content

Commit 1444e5a

Browse files
authored
[flang] Complete implementation of OUT_OF_RANGE() (#89334)
The intrinsic function OUT_OF_RANGE() lacks support in lowering and the runtime. This patch obviates a need for any such support by implementing OUT_OF_RANGE() via rewriting in semantics. This rewriting of OUT_OF_RANGE() calls replaces the existing code that folds OUT_OF_RANGE() calls with constant arguments. Some changes and fixes were necessary outside of OUT_OF_RANGE()'s folding code (now rewriting code), whose testing exposed some other issues worth fixing. - The common::RealDetails<> template class was recoded in terms of a new base class with a constexpr constructor, so that the the characteristics of the various REAL kinds could be queried dynamically as well. This affected some client usage. - There were bugs in the code that folds TRANSFER() when the type of X or MOLD was REAL(10) -- this is a type that occupies 16 bytes per element in execution memory but only 10 bytes (was 12) in the data of std::vector<Scalar<>> in a Constant<>. - Folds of REAL->REAL conversions weren't preserving infinities.
1 parent fde5e47 commit 1444e5a

File tree

13 files changed

+911
-185
lines changed

13 files changed

+911
-185
lines changed

flang/include/flang/Common/real.h

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,27 @@ static constexpr int PrecisionOfRealKind(int kind) {
108108
}
109109
}
110110

111-
template <int BINARY_PRECISION> class RealDetails {
111+
// RealCharacteristics is constexpr, but also useful when constructed
112+
// with a non-constant precision argument.
113+
class RealCharacteristics {
114+
public:
115+
explicit constexpr RealCharacteristics(int p) : binaryPrecision{p} {}
116+
117+
int binaryPrecision;
118+
int bits{BitsForBinaryPrecision(binaryPrecision)};
119+
bool isImplicitMSB{binaryPrecision != 64 /*x87*/};
120+
int significandBits{binaryPrecision - isImplicitMSB};
121+
int exponentBits{bits - significandBits - 1 /*sign*/};
122+
int maxExponent{(1 << exponentBits) - 1};
123+
int exponentBias{maxExponent / 2};
124+
int decimalPrecision{LogBaseTwoToLogBaseTen(binaryPrecision - 1)};
125+
int decimalRange{LogBaseTwoToLogBaseTen(exponentBias - 1)};
126+
// Number of significant decimal digits in the fraction of the
127+
// exact conversion of the least nonzero subnormal.
128+
int maxDecimalConversionDigits{MaxDecimalConversionDigits(binaryPrecision)};
129+
int maxHexadecimalConversionDigits{
130+
MaxHexadecimalConversionDigits(binaryPrecision)};
131+
112132
private:
113133
// Converts bit widths to whole decimal digits
114134
static constexpr int LogBaseTwoToLogBaseTen(int logb2) {
@@ -118,33 +138,6 @@ template <int BINARY_PRECISION> class RealDetails {
118138
(logb2 * LogBaseTenOfTwoTimesTenToThe12th) / TenToThe12th};
119139
return static_cast<int>(logb10);
120140
}
121-
122-
public:
123-
RT_OFFLOAD_VAR_GROUP_BEGIN
124-
static constexpr int binaryPrecision{BINARY_PRECISION};
125-
static constexpr int bits{BitsForBinaryPrecision(binaryPrecision)};
126-
static constexpr bool isImplicitMSB{binaryPrecision != 64 /*x87*/};
127-
static constexpr int significandBits{binaryPrecision - isImplicitMSB};
128-
static constexpr int exponentBits{bits - significandBits - 1 /*sign*/};
129-
static constexpr int maxExponent{(1 << exponentBits) - 1};
130-
static constexpr int exponentBias{maxExponent / 2};
131-
132-
static constexpr int decimalPrecision{
133-
LogBaseTwoToLogBaseTen(binaryPrecision - 1)};
134-
static constexpr int decimalRange{LogBaseTwoToLogBaseTen(exponentBias - 1)};
135-
136-
// Number of significant decimal digits in the fraction of the
137-
// exact conversion of the least nonzero subnormal.
138-
static constexpr int maxDecimalConversionDigits{
139-
MaxDecimalConversionDigits(binaryPrecision)};
140-
141-
static constexpr int maxHexadecimalConversionDigits{
142-
MaxHexadecimalConversionDigits(binaryPrecision)};
143-
RT_OFFLOAD_VAR_GROUP_END
144-
145-
static_assert(binaryPrecision > 0);
146-
static_assert(exponentBits > 1);
147-
static_assert(exponentBits <= 15);
148141
};
149142

150143
} // namespace Fortran::common

flang/include/flang/Decimal/binary-floating-point.h

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,20 @@ enum FortranRounding {
3030
RoundCompatible, /* RC: like RN, but ties go away from 0 */
3131
};
3232

33-
template <int BINARY_PRECISION>
34-
class BinaryFloatingPointNumber : public common::RealDetails<BINARY_PRECISION> {
33+
template <int BINARY_PRECISION> class BinaryFloatingPointNumber {
3534
public:
36-
using Details = common::RealDetails<BINARY_PRECISION>;
37-
using Details::binaryPrecision;
38-
using Details::bits;
39-
using Details::decimalPrecision;
40-
using Details::decimalRange;
41-
using Details::exponentBias;
42-
using Details::exponentBits;
43-
using Details::isImplicitMSB;
44-
using Details::maxDecimalConversionDigits;
45-
using Details::maxExponent;
46-
using Details::maxHexadecimalConversionDigits;
47-
using Details::significandBits;
35+
static constexpr common::RealCharacteristics realChars{BINARY_PRECISION};
36+
static constexpr int binaryPrecision{BINARY_PRECISION};
37+
static constexpr int bits{realChars.bits};
38+
static constexpr int isImplicitMSB{realChars.isImplicitMSB};
39+
static constexpr int significandBits{realChars.significandBits};
40+
static constexpr int exponentBits{realChars.exponentBits};
41+
static constexpr int exponentBias{realChars.exponentBias};
42+
static constexpr int maxExponent{realChars.maxExponent};
43+
static constexpr int decimalPrecision{realChars.decimalPrecision};
44+
static constexpr int decimalRange{realChars.decimalRange};
45+
static constexpr int maxDecimalConversionDigits{
46+
realChars.maxDecimalConversionDigits};
4847

4948
using RawType = common::HostUnsignedIntType<bits>;
5049
static_assert(CHAR_BIT * sizeof(RawType) >= bits);

flang/include/flang/Evaluate/complex.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ extern template class Complex<Real<Integer<16>, 11>>;
104104
extern template class Complex<Real<Integer<16>, 8>>;
105105
extern template class Complex<Real<Integer<32>, 24>>;
106106
extern template class Complex<Real<Integer<64>, 53>>;
107-
extern template class Complex<Real<Integer<80>, 64>>;
107+
extern template class Complex<Real<X87IntegerContainer, 64>>;
108108
extern template class Complex<Real<Integer<128>, 113>>;
109109
} // namespace Fortran::evaluate::value
110110
#endif // FORTRAN_EVALUATE_COMPLEX_H_

flang/include/flang/Evaluate/integer.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,12 @@ namespace Fortran::evaluate::value {
5050
// named accordingly in ALL CAPS so that they can be referenced easily in
5151
// the language standard.
5252
template <int BITS, bool IS_LITTLE_ENDIAN = isHostLittleEndian,
53-
int PARTBITS = BITS <= 32 ? BITS : 32,
53+
int PARTBITS = BITS <= 32 ? BITS
54+
: BITS % 32 == 0 ? 32
55+
: BITS % 16 == 0 ? 16
56+
: 8,
5457
typename PART = HostUnsignedInt<PARTBITS>,
55-
typename BIGPART = HostUnsignedInt<PARTBITS * 2>>
58+
typename BIGPART = HostUnsignedInt<PARTBITS * 2>, int ALIGNMENT = BITS>
5659
class Integer {
5760
public:
5861
static constexpr int bits{BITS};
@@ -79,6 +82,8 @@ class Integer {
7982
static_assert((parts - 1) * partBits + topPartBits == bits);
8083
static constexpr Part partMask{static_cast<Part>(~0) >> extraPartBits};
8184
static constexpr Part topPartMask{static_cast<Part>(~0) >> extraTopPartBits};
85+
static constexpr int partsWithAlignment{
86+
(ALIGNMENT + partBits - 1) / partBits};
8287

8388
public:
8489
// Some types used for member function results
@@ -1043,14 +1048,16 @@ class Integer {
10431048
}
10441049
}
10451050

1046-
Part part_[parts]{};
1051+
Part part_[partsWithAlignment]{};
10471052
};
10481053

10491054
extern template class Integer<8>;
10501055
extern template class Integer<16>;
10511056
extern template class Integer<32>;
10521057
extern template class Integer<64>;
1053-
extern template class Integer<80>;
1058+
using X87IntegerContainer =
1059+
Integer<80, true, 16, std::uint16_t, std::uint32_t, 128>;
1060+
extern template class Integer<80, true, 16, std::uint16_t, std::uint32_t, 128>;
10541061
extern template class Integer<128>;
10551062
} // namespace Fortran::evaluate::value
10561063
#endif // FORTRAN_EVALUATE_INTEGER_H_

flang/include/flang/Evaluate/real.h

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,19 @@ static constexpr std::int64_t ScaledLogBaseTenOfTwo{301029995664};
3535
// class template must be (or look like) an instance of Integer<>;
3636
// the second specifies the number of effective bits (binary precision)
3737
// in the fraction.
38-
template <typename WORD, int PREC>
39-
class Real : public common::RealDetails<PREC> {
38+
template <typename WORD, int PREC> class Real {
4039
public:
4140
using Word = WORD;
4241
static constexpr int binaryPrecision{PREC};
43-
using Details = common::RealDetails<PREC>;
44-
using Details::exponentBias;
45-
using Details::exponentBits;
46-
using Details::isImplicitMSB;
47-
using Details::maxExponent;
48-
using Details::significandBits;
42+
static constexpr common::RealCharacteristics realChars{PREC};
43+
static constexpr int exponentBias{realChars.exponentBias};
44+
static constexpr int exponentBits{realChars.exponentBits};
45+
static constexpr int isImplicitMSB{realChars.isImplicitMSB};
46+
static constexpr int maxExponent{realChars.maxExponent};
47+
static constexpr int significandBits{realChars.significandBits};
4948

5049
static constexpr int bits{Word::bits};
51-
static_assert(bits >= Details::bits);
50+
static_assert(bits >= realChars.bits);
5251
using Fraction = Integer<binaryPrecision>; // all bits made explicit
5352

5453
template <typename W, int P> friend class Real;
@@ -205,8 +204,8 @@ class Real : public common::RealDetails<PREC> {
205204
}
206205

207206
static constexpr int DIGITS{binaryPrecision};
208-
static constexpr int PRECISION{Details::decimalPrecision};
209-
static constexpr int RANGE{Details::decimalRange};
207+
static constexpr int PRECISION{realChars.decimalPrecision};
208+
static constexpr int RANGE{realChars.decimalRange};
210209
static constexpr int MAXEXPONENT{maxExponent - exponentBias};
211210
static constexpr int MINEXPONENT{2 - exponentBias};
212211
Real RRSPACING() const;
@@ -371,6 +370,10 @@ class Real : public common::RealDetails<PREC> {
371370
return result;
372371
}
373372
bool isNegative{x.IsNegative()};
373+
if (x.IsInfinite()) {
374+
result.value = Infinity(isNegative);
375+
return result;
376+
}
374377
A absX{x};
375378
if (isNegative) {
376379
absX = x.Negate();
@@ -493,7 +496,7 @@ extern template class Real<Integer<16>, 11>; // IEEE half format
493496
extern template class Real<Integer<16>, 8>; // the "other" half format
494497
extern template class Real<Integer<32>, 24>; // IEEE single
495498
extern template class Real<Integer<64>, 53>; // IEEE double
496-
extern template class Real<Integer<80>, 64>; // 80387 extended precision
499+
extern template class Real<X87IntegerContainer, 64>; // 80387 extended precision
497500
extern template class Real<Integer<128>, 113>; // IEEE quad
498501
// N.B. No "double-double" support.
499502
} // namespace Fortran::evaluate::value

flang/include/flang/Evaluate/type.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,10 @@ class Type<TypeCategory::Real, KIND>
296296
public:
297297
static constexpr int precision{common::PrecisionOfRealKind(KIND)};
298298
static constexpr int bits{common::BitsForBinaryPrecision(precision)};
299-
using Scalar = value::Real<value::Integer<bits>, precision>;
299+
using Scalar =
300+
value::Real<std::conditional_t<precision == 64,
301+
value::X87IntegerContainer, value::Integer<bits>>,
302+
precision>;
300303
};
301304

302305
// The KIND type parameter on COMPLEX is the kind of each of its components.

flang/lib/Decimal/big-radix-floating-point.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
8383
return *this;
8484
}
8585

86+
RT_API_ATTRS bool IsInteger() const { return exponent_ >= 0; }
87+
8688
// Converts decimal floating-point to binary.
8789
RT_API_ATTRS ConversionToBinaryResult<PREC> ConvertToBinary();
8890

flang/lib/Evaluate/complex.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,6 @@ template class Complex<Real<Integer<16>, 11>>;
120120
template class Complex<Real<Integer<16>, 8>>;
121121
template class Complex<Real<Integer<32>, 24>>;
122122
template class Complex<Real<Integer<64>, 53>>;
123-
template class Complex<Real<Integer<80>, 64>>;
123+
template class Complex<Real<X87IntegerContainer, 64>>;
124124
template class Complex<Real<Integer<128>, 113>>;
125125
} // namespace Fortran::evaluate::value

0 commit comments

Comments
 (0)