Skip to content

[flang] Complete implementation of OUT_OF_RANGE() #89334

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 21 additions & 28 deletions flang/include/flang/Common/real.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,27 @@ static constexpr int PrecisionOfRealKind(int kind) {
}
}

template <int BINARY_PRECISION> class RealDetails {
// RealCharacteristics is constexpr, but also useful when constructed
// with a non-constant precision argument.
class RealCharacteristics {
public:
explicit constexpr RealCharacteristics(int p) : binaryPrecision{p} {}

int binaryPrecision;
int bits{BitsForBinaryPrecision(binaryPrecision)};
bool isImplicitMSB{binaryPrecision != 64 /*x87*/};
int significandBits{binaryPrecision - isImplicitMSB};
int exponentBits{bits - significandBits - 1 /*sign*/};
int maxExponent{(1 << exponentBits) - 1};
int exponentBias{maxExponent / 2};
int decimalPrecision{LogBaseTwoToLogBaseTen(binaryPrecision - 1)};
int decimalRange{LogBaseTwoToLogBaseTen(exponentBias - 1)};
// Number of significant decimal digits in the fraction of the
// exact conversion of the least nonzero subnormal.
int maxDecimalConversionDigits{MaxDecimalConversionDigits(binaryPrecision)};
int maxHexadecimalConversionDigits{
MaxHexadecimalConversionDigits(binaryPrecision)};

private:
// Converts bit widths to whole decimal digits
static constexpr int LogBaseTwoToLogBaseTen(int logb2) {
Expand All @@ -118,33 +138,6 @@ template <int BINARY_PRECISION> class RealDetails {
(logb2 * LogBaseTenOfTwoTimesTenToThe12th) / TenToThe12th};
return static_cast<int>(logb10);
}

public:
RT_OFFLOAD_VAR_GROUP_BEGIN
static constexpr int binaryPrecision{BINARY_PRECISION};
static constexpr int bits{BitsForBinaryPrecision(binaryPrecision)};
static constexpr bool isImplicitMSB{binaryPrecision != 64 /*x87*/};
static constexpr int significandBits{binaryPrecision - isImplicitMSB};
static constexpr int exponentBits{bits - significandBits - 1 /*sign*/};
static constexpr int maxExponent{(1 << exponentBits) - 1};
static constexpr int exponentBias{maxExponent / 2};

static constexpr int decimalPrecision{
LogBaseTwoToLogBaseTen(binaryPrecision - 1)};
static constexpr int decimalRange{LogBaseTwoToLogBaseTen(exponentBias - 1)};

// Number of significant decimal digits in the fraction of the
// exact conversion of the least nonzero subnormal.
static constexpr int maxDecimalConversionDigits{
MaxDecimalConversionDigits(binaryPrecision)};

static constexpr int maxHexadecimalConversionDigits{
MaxHexadecimalConversionDigits(binaryPrecision)};
RT_OFFLOAD_VAR_GROUP_END

static_assert(binaryPrecision > 0);
static_assert(exponentBits > 1);
static_assert(exponentBits <= 15);
};

} // namespace Fortran::common
Expand Down
27 changes: 13 additions & 14 deletions flang/include/flang/Decimal/binary-floating-point.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,20 @@ enum FortranRounding {
RoundCompatible, /* RC: like RN, but ties go away from 0 */
};

template <int BINARY_PRECISION>
class BinaryFloatingPointNumber : public common::RealDetails<BINARY_PRECISION> {
template <int BINARY_PRECISION> class BinaryFloatingPointNumber {
public:
using Details = common::RealDetails<BINARY_PRECISION>;
using Details::binaryPrecision;
using Details::bits;
using Details::decimalPrecision;
using Details::decimalRange;
using Details::exponentBias;
using Details::exponentBits;
using Details::isImplicitMSB;
using Details::maxDecimalConversionDigits;
using Details::maxExponent;
using Details::maxHexadecimalConversionDigits;
using Details::significandBits;
static constexpr common::RealCharacteristics realChars{BINARY_PRECISION};
static constexpr int binaryPrecision{BINARY_PRECISION};
static constexpr int bits{realChars.bits};
static constexpr int isImplicitMSB{realChars.isImplicitMSB};
static constexpr int significandBits{realChars.significandBits};
static constexpr int exponentBits{realChars.exponentBits};
static constexpr int exponentBias{realChars.exponentBias};
static constexpr int maxExponent{realChars.maxExponent};
static constexpr int decimalPrecision{realChars.decimalPrecision};
static constexpr int decimalRange{realChars.decimalRange};
static constexpr int maxDecimalConversionDigits{
realChars.maxDecimalConversionDigits};

using RawType = common::HostUnsignedIntType<bits>;
static_assert(CHAR_BIT * sizeof(RawType) >= bits);
Expand Down
2 changes: 1 addition & 1 deletion flang/include/flang/Evaluate/complex.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ extern template class Complex<Real<Integer<16>, 11>>;
extern template class Complex<Real<Integer<16>, 8>>;
extern template class Complex<Real<Integer<32>, 24>>;
extern template class Complex<Real<Integer<64>, 53>>;
extern template class Complex<Real<Integer<80>, 64>>;
extern template class Complex<Real<X87IntegerContainer, 64>>;
extern template class Complex<Real<Integer<128>, 113>>;
} // namespace Fortran::evaluate::value
#endif // FORTRAN_EVALUATE_COMPLEX_H_
15 changes: 11 additions & 4 deletions flang/include/flang/Evaluate/integer.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,12 @@ namespace Fortran::evaluate::value {
// named accordingly in ALL CAPS so that they can be referenced easily in
// the language standard.
template <int BITS, bool IS_LITTLE_ENDIAN = isHostLittleEndian,
int PARTBITS = BITS <= 32 ? BITS : 32,
int PARTBITS = BITS <= 32 ? BITS
: BITS % 32 == 0 ? 32
: BITS % 16 == 0 ? 16
: 8,
typename PART = HostUnsignedInt<PARTBITS>,
typename BIGPART = HostUnsignedInt<PARTBITS * 2>>
typename BIGPART = HostUnsignedInt<PARTBITS * 2>, int ALIGNMENT = BITS>
class Integer {
public:
static constexpr int bits{BITS};
Expand All @@ -79,6 +82,8 @@ class Integer {
static_assert((parts - 1) * partBits + topPartBits == bits);
static constexpr Part partMask{static_cast<Part>(~0) >> extraPartBits};
static constexpr Part topPartMask{static_cast<Part>(~0) >> extraTopPartBits};
static constexpr int partsWithAlignment{
(ALIGNMENT + partBits - 1) / partBits};

public:
// Some types used for member function results
Expand Down Expand Up @@ -1043,14 +1048,16 @@ class Integer {
}
}

Part part_[parts]{};
Part part_[partsWithAlignment]{};
};

extern template class Integer<8>;
extern template class Integer<16>;
extern template class Integer<32>;
extern template class Integer<64>;
extern template class Integer<80>;
using X87IntegerContainer =
Integer<80, true, 16, std::uint16_t, std::uint32_t, 128>;
extern template class Integer<80, true, 16, std::uint16_t, std::uint32_t, 128>;
extern template class Integer<128>;
} // namespace Fortran::evaluate::value
#endif // FORTRAN_EVALUATE_INTEGER_H_
27 changes: 15 additions & 12 deletions flang/include/flang/Evaluate/real.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,19 @@ static constexpr std::int64_t ScaledLogBaseTenOfTwo{301029995664};
// class template must be (or look like) an instance of Integer<>;
// the second specifies the number of effective bits (binary precision)
// in the fraction.
template <typename WORD, int PREC>
class Real : public common::RealDetails<PREC> {
template <typename WORD, int PREC> class Real {
public:
using Word = WORD;
static constexpr int binaryPrecision{PREC};
using Details = common::RealDetails<PREC>;
using Details::exponentBias;
using Details::exponentBits;
using Details::isImplicitMSB;
using Details::maxExponent;
using Details::significandBits;
static constexpr common::RealCharacteristics realChars{PREC};
static constexpr int exponentBias{realChars.exponentBias};
static constexpr int exponentBits{realChars.exponentBits};
static constexpr int isImplicitMSB{realChars.isImplicitMSB};
static constexpr int maxExponent{realChars.maxExponent};
static constexpr int significandBits{realChars.significandBits};

static constexpr int bits{Word::bits};
static_assert(bits >= Details::bits);
static_assert(bits >= realChars.bits);
using Fraction = Integer<binaryPrecision>; // all bits made explicit

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

static constexpr int DIGITS{binaryPrecision};
static constexpr int PRECISION{Details::decimalPrecision};
static constexpr int RANGE{Details::decimalRange};
static constexpr int PRECISION{realChars.decimalPrecision};
static constexpr int RANGE{realChars.decimalRange};
static constexpr int MAXEXPONENT{maxExponent - exponentBias};
static constexpr int MINEXPONENT{2 - exponentBias};
Real RRSPACING() const;
Expand Down Expand Up @@ -371,6 +370,10 @@ class Real : public common::RealDetails<PREC> {
return result;
}
bool isNegative{x.IsNegative()};
if (x.IsInfinite()) {
result.value = Infinity(isNegative);
return result;
}
A absX{x};
if (isNegative) {
absX = x.Negate();
Expand Down Expand Up @@ -493,7 +496,7 @@ extern template class Real<Integer<16>, 11>; // IEEE half format
extern template class Real<Integer<16>, 8>; // the "other" half format
extern template class Real<Integer<32>, 24>; // IEEE single
extern template class Real<Integer<64>, 53>; // IEEE double
extern template class Real<Integer<80>, 64>; // 80387 extended precision
extern template class Real<X87IntegerContainer, 64>; // 80387 extended precision
extern template class Real<Integer<128>, 113>; // IEEE quad
// N.B. No "double-double" support.
} // namespace Fortran::evaluate::value
Expand Down
5 changes: 4 additions & 1 deletion flang/include/flang/Evaluate/type.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,10 @@ class Type<TypeCategory::Real, KIND>
public:
static constexpr int precision{common::PrecisionOfRealKind(KIND)};
static constexpr int bits{common::BitsForBinaryPrecision(precision)};
using Scalar = value::Real<value::Integer<bits>, precision>;
using Scalar =
value::Real<std::conditional_t<precision == 64,
value::X87IntegerContainer, value::Integer<bits>>,
precision>;
};

// The KIND type parameter on COMPLEX is the kind of each of its components.
Expand Down
2 changes: 2 additions & 0 deletions flang/lib/Decimal/big-radix-floating-point.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
return *this;
}

RT_API_ATTRS bool IsInteger() const { return exponent_ >= 0; }

// Converts decimal floating-point to binary.
RT_API_ATTRS ConversionToBinaryResult<PREC> ConvertToBinary();

Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Evaluate/complex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,6 @@ template class Complex<Real<Integer<16>, 11>>;
template class Complex<Real<Integer<16>, 8>>;
template class Complex<Real<Integer<32>, 24>>;
template class Complex<Real<Integer<64>, 53>>;
template class Complex<Real<Integer<80>, 64>>;
template class Complex<Real<X87IntegerContainer, 64>>;
template class Complex<Real<Integer<128>, 113>>;
} // namespace Fortran::evaluate::value
Loading
Loading