Skip to content

Commit ba73946

Browse files
committed
[flang] Complete implementation of OUT_OF_RANGE()
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 adc11b3 commit ba73946

File tree

13 files changed

+997
-236
lines changed

13 files changed

+997
-236
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/initial-image.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ class InitialImage {
4646
if (offset < 0 || offset + bytes > data_.size()) {
4747
return OutOfRange;
4848
} else {
49-
auto elementBytes{ToInt64(x.GetType().MeasureSizeInBytes(context, true))};
49+
auto elementBytes{
50+
ToInt64(x.GetType().MeasureSizeInBytes(context, /*aligned=*/false))};
5051
if (!elementBytes ||
5152
bytes !=
5253
x.values().size() * static_cast<std::size_t>(*elementBytes)) {
@@ -115,7 +116,8 @@ class InitialImage {
115116
std::optional<Expr<SomeType>> AsConstant(FoldingContext &,
116117
const DynamicType &, std::optional<std::int64_t> charLength,
117118
const ConstantSubscripts &, bool padWithZero = false,
118-
ConstantSubscript offset = 0) const;
119+
ConstantSubscript offset = 0,
120+
std::optional<std::size_t> elementBytes = std::nullopt) const;
119121
std::optional<Expr<SomeType>> AsConstantPointer(
120122
ConstantSubscript offset = 0) const;
121123

flang/include/flang/Evaluate/integer.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ 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>,
5558
typename BIGPART = HostUnsignedInt<PARTBITS * 2>>
5659
class Integer {

flang/include/flang/Evaluate/real.h

Lines changed: 14 additions & 11 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();

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

0 commit comments

Comments
 (0)