diff --git a/flang/include/flang/Common/real.h b/flang/include/flang/Common/real.h --- a/flang/include/flang/Common/real.h +++ b/flang/include/flang/Common/real.h @@ -20,20 +20,20 @@ // Total representation size in bits for each type static constexpr int BitsForBinaryPrecision(int binaryPrecision) { switch (binaryPrecision) { - case 8: - return 16; // IEEE single (truncated): 1+8+7 - case 11: - return 16; // IEEE half precision: 1+5+10 - case 24: - return 32; // IEEE single precision: 1+8+23 - case 53: - return 64; // IEEE double precision: 1+11+52 - case 64: - return 80; // x87 extended precision: 1+15+64 - case 106: - return 128; // "double-double": 2*(1+11+52) - case 113: - return 128; // IEEE quad precision: 1+15+112 + case 8: // IEEE single (truncated): 1+8+7 with implicit bit + return 16; + case 11: // IEEE half precision: 1+5+10 with implicit bit + return 16; + case 24: // IEEE single precision: 1+8+23 with implicit bit + return 32; + case 53: // IEEE double precision: 1+11+52 with implicit bit + return 64; + case 64: // x87 extended precision: 1+15+64, no implicit bit + return 80; + case 106: // "double-double": 2*(1+11+52 with implicit bit) + return 128; + case 113: // IEEE quad precision: 1+15+112 with implicit bit + return 128; default: return -1; } @@ -44,25 +44,65 @@ // with the minimum exponent (biased to 1) and all fractional bits set. static constexpr int MaxDecimalConversionDigits(int binaryPrecision) { switch (binaryPrecision) { - case 8: + case 8: // IEEE single (truncated): 1+8+7 with implicit bit return 96; - case 11: + case 11: // IEEE half precision: 1+5+10 with implicit bit return 21; - case 24: + case 24: // IEEE single precision: 1+8+23 with implicit bit return 112; - case 53: + case 53: // IEEE double precision: 1+11+52 with implicit bit return 767; - case 64: + case 64: // x87 extended precision: 1+15+64, no implicit bit return 11514; - case 106: + case 106: // "double-double": 2*(1+11+52 with implicit bit) return 2 * 767; - case 113: + case 113: // IEEE quad precision: 1+15+112 with implicit bit return 11563; default: return -1; } } +static constexpr int RealKindForPrecision(int binaryPrecision) { + switch (binaryPrecision) { + case 8: // IEEE single (truncated): 1+8+7 with implicit bit + return 3; + case 11: // IEEE half precision: 1+5+10 with implicit bit + return 2; + case 24: // IEEE single precision: 1+8+23 with implicit bit + return 4; + case 53: // IEEE double precision: 1+11+52 with implicit bit + return 8; + case 64: // x87 extended precision: 1+15+64, no implicit bit + return 10; + // TODO: case 106: return kind for double/double + case 113: // IEEE quad precision: 1+15+112 with implicit bit + return 16; + default: + return -1; + } +} + +static constexpr int PrecisionOfRealKind(int kind) { + switch (kind) { + case 2: // IEEE half precision: 1+5+10 with implicit bit + return 11; + case 3: // IEEE single (truncated): 1+8+7 with implicit bit + return 8; + case 4: // IEEE single precision: 1+8+23 with implicit bit + return 24; + case 8: // IEEE double precision: 1+11+52 with implicit bit + return 53; + case 10: // x87 extended precision: 1+15+64, no implicit bit + return 64; + // TODO: case kind for double/double: return 106; + case 16: // IEEE quad precision: 1+15+112 with implicit bit + return 113; + default: + return -1; + } +} + template class RealDetails { private: // Converts bit widths to whole decimal digits diff --git a/flang/include/flang/Decimal/binary-floating-point.h b/flang/include/flang/Decimal/binary-floating-point.h --- a/flang/include/flang/Decimal/binary-floating-point.h +++ b/flang/include/flang/Decimal/binary-floating-point.h @@ -48,6 +48,7 @@ const BinaryFloatingPointNumber &that) = default; constexpr BinaryFloatingPointNumber &operator=( BinaryFloatingPointNumber &&that) = default; + constexpr explicit BinaryFloatingPointNumber(RawType raw) : raw_{raw} {} RawType raw() const { return raw_; } diff --git a/flang/include/flang/Evaluate/type.h b/flang/include/flang/Evaluate/type.h --- a/flang/include/flang/Evaluate/type.h +++ b/flang/include/flang/Evaluate/type.h @@ -24,6 +24,7 @@ #include "real.h" #include "flang/Common/Fortran.h" #include "flang/Common/idioms.h" +#include "flang/Common/real.h" #include "flang/Common/template.h" #include #include @@ -235,51 +236,13 @@ using Scalar = value::Integer<8 * KIND>; }; -// REAL(KIND=2) is IEEE half-precision (16 bits) -template <> -class Type : public TypeBase { -public: - using Scalar = - value::Real::Scalar, 11>; -}; - -// REAL(KIND=3) identifies the "other" half-precision format, which is -// basically REAL(4) without its least-order 16 fraction bits. -template <> -class Type : public TypeBase { -public: - using Scalar = - value::Real::Scalar, 8>; -}; - -// REAL(KIND=4) is IEEE-754 single precision (32 bits) -template <> -class Type : public TypeBase { -public: - using Scalar = - value::Real::Scalar, 24>; -}; - -// REAL(KIND=8) is IEEE double precision (64 bits) -template <> -class Type : public TypeBase { -public: - using Scalar = - value::Real::Scalar, 53>; -}; - -// REAL(KIND=10) is x87 FPU extended precision (80 bits, all explicit) -template <> -class Type : public TypeBase { -public: - using Scalar = value::Real, 64>; -}; - -// REAL(KIND=16) is IEEE quad precision (128 bits) -template <> -class Type : public TypeBase { +template +class Type + : public TypeBase { public: - using Scalar = value::Real, 113>; + static constexpr int precision{common::PrecisionOfRealKind(KIND)}; + static constexpr int bits{common::BitsForBinaryPrecision(precision)}; + using Scalar = value::Real, precision>; }; // The KIND type parameter on COMPLEX is the kind of each of its components. diff --git a/flang/runtime/descriptor-io.h b/flang/runtime/descriptor-io.h --- a/flang/runtime/descriptor-io.h +++ b/flang/runtime/descriptor-io.h @@ -61,21 +61,22 @@ return true; } -template +template inline bool FormattedRealIO( IoStatementState &io, const Descriptor &descriptor) { std::size_t numElements{descriptor.Elements()}; SubscriptValue subscripts[maxRank]; descriptor.GetLowerBounds(subscripts); + using RawType = typename RealOutputEditing::BinaryFloatingPoint; for (std::size_t j{0}; j < numElements; ++j) { if (auto edit{io.GetNextDataEdit()}) { - A &x{ExtractElement(io, descriptor, subscripts)}; + RawType &x{ExtractElement(io, descriptor, subscripts)}; if constexpr (DIR == Direction::Output) { - if (!RealOutputEditing{io, x}.Edit(*edit)) { + if (!RealOutputEditing{io, x}.Edit(*edit)) { return false; } } else if (edit->descriptor != DataEdit::ListDirectedNullValue) { - if (!EditRealInput(io, *edit, reinterpret_cast(&x))) { + if (!EditRealInput(io, *edit, reinterpret_cast(&x))) { return false; } } @@ -90,7 +91,7 @@ return true; } -template +template inline bool FormattedComplexIO( IoStatementState &io, const Descriptor &descriptor) { std::size_t numElements{descriptor.Elements()}; @@ -98,14 +99,15 @@ descriptor.GetLowerBounds(subscripts); bool isListOutput{ io.get_if>() != nullptr}; + using RawType = typename RealOutputEditing::BinaryFloatingPoint; for (std::size_t j{0}; j < numElements; ++j) { - A *x{&ExtractElement(io, descriptor, subscripts)}; + RawType *x{&ExtractElement(io, descriptor, subscripts)}; if (isListOutput) { DataEdit rEdit, iEdit; rEdit.descriptor = DataEdit::ListDirectedRealPart; iEdit.descriptor = DataEdit::ListDirectedImaginaryPart; - if (!RealOutputEditing{io, x[0]}.Edit(rEdit) || - !RealOutputEditing{io, x[1]}.Edit(iEdit)) { + if (!RealOutputEditing{io, x[0]}.Edit(rEdit) || + !RealOutputEditing{io, x[1]}.Edit(iEdit)) { return false; } } else { @@ -114,12 +116,12 @@ if (!edit) { return false; } else if constexpr (DIR == Direction::Output) { - if (!RealOutputEditing{io, *x}.Edit(*edit)) { + if (!RealOutputEditing{io, *x}.Edit(*edit)) { return false; } } else if (edit->descriptor == DataEdit::ListDirectedNullValue) { break; - } else if (!EditRealInput( + } else if (!EditRealInput( io, *edit, reinterpret_cast(x))) { return false; } @@ -275,18 +277,19 @@ } case TypeCategory::Real: switch (kind) { + case 2: + return FormattedRealIO<2, DIR>(io, descriptor); + case 3: + return FormattedRealIO<3, DIR>(io, descriptor); case 4: - return FormattedRealIO<24, float, DIR>(io, descriptor); + return FormattedRealIO<4, DIR>(io, descriptor); case 8: - return FormattedRealIO<53, double, DIR>(io, descriptor); -#if __x86_64__ + return FormattedRealIO<8, DIR>(io, descriptor); case 10: - return FormattedRealIO<64, long double, DIR>(io, descriptor); -#else + return FormattedRealIO<10, DIR>(io, descriptor); + // TODO: case double/double case 16: - return FormattedRealIO<113, long double, DIR>(io, descriptor); -#endif - // TODO cases 2, 3 + return FormattedRealIO<16, DIR>(io, descriptor); default: io.GetIoErrorHandler().Crash( "DescriptorIO: Unimplemented REAL kind (%d) in descriptor", kind); @@ -294,18 +297,19 @@ } case TypeCategory::Complex: switch (kind) { + case 2: + return FormattedComplexIO<2, DIR>(io, descriptor); + case 3: + return FormattedComplexIO<3, DIR>(io, descriptor); case 4: - return FormattedComplexIO<24, float, DIR>(io, descriptor); + return FormattedComplexIO<4, DIR>(io, descriptor); case 8: - return FormattedComplexIO<53, double, DIR>(io, descriptor); -#if __x86_64__ + return FormattedComplexIO<8, DIR>(io, descriptor); case 10: - return FormattedComplexIO<64, long double, DIR>(io, descriptor); -#else + return FormattedComplexIO<10, DIR>(io, descriptor); + // TODO: case double/double case 16: - return FormattedComplexIO<113, long double, DIR>(io, descriptor); -#endif - // TODO cases 2, 3 + return FormattedComplexIO<16, DIR>(io, descriptor); default: io.GetIoErrorHandler().Crash( "DescriptorIO: Unimplemented COMPLEX kind (%d) in descriptor", diff --git a/flang/runtime/edit-input.h b/flang/runtime/edit-input.h --- a/flang/runtime/edit-input.h +++ b/flang/runtime/edit-input.h @@ -17,24 +17,25 @@ bool EditIntegerInput(IoStatementState &, const DataEdit &, void *, int kind); -template +template bool EditRealInput(IoStatementState &, const DataEdit &, void *); bool EditLogicalInput(IoStatementState &, const DataEdit &, bool &); bool EditDefaultCharacterInput( IoStatementState &, const DataEdit &, char *, std::size_t); -extern template bool EditRealInput<8>( +extern template bool EditRealInput<2>( IoStatementState &, const DataEdit &, void *); -extern template bool EditRealInput<11>( +extern template bool EditRealInput<3>( IoStatementState &, const DataEdit &, void *); -extern template bool EditRealInput<24>( +extern template bool EditRealInput<4>( IoStatementState &, const DataEdit &, void *); -extern template bool EditRealInput<53>( +extern template bool EditRealInput<8>( IoStatementState &, const DataEdit &, void *); -extern template bool EditRealInput<64>( +extern template bool EditRealInput<10>( IoStatementState &, const DataEdit &, void *); -extern template bool EditRealInput<113>( +// TODO: double/double +extern template bool EditRealInput<16>( IoStatementState &, const DataEdit &, void *); } // namespace Fortran::runtime::io #endif // FORTRAN_RUNTIME_EDIT_INPUT_H_ diff --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp --- a/flang/runtime/edit-input.cpp +++ b/flang/runtime/edit-input.cpp @@ -260,8 +260,9 @@ return got; } -template +template bool EditCommonRealInput(IoStatementState &io, const DataEdit &edit, void *n) { + constexpr int binaryPrecision{common::PrecisionOfRealKind(KIND)}; static constexpr int maxDigits{ common::MaxDecimalConversionDigits(binaryPrecision)}; static constexpr int bufferSize{maxDigits + 18}; @@ -294,8 +295,9 @@ return true; } -template +template bool EditRealInput(IoStatementState &io, const DataEdit &edit, void *n) { + constexpr int binaryPrecision{common::PrecisionOfRealKind(KIND)}; switch (edit.descriptor) { case DataEdit::ListDirected: case DataEdit::ListDirectedRealPart: @@ -304,7 +306,7 @@ case 'E': // incl. EN, ES, & EX case 'D': case 'G': - return EditCommonRealInput(io, edit, n); + return EditCommonRealInput(io, edit, n); case 'B': return EditBOZInput( io, edit, n, 2, common::BitsForBinaryPrecision(binaryPrecision)); @@ -459,10 +461,11 @@ return true; } +template bool EditRealInput<2>(IoStatementState &, const DataEdit &, void *); +template bool EditRealInput<3>(IoStatementState &, const DataEdit &, void *); +template bool EditRealInput<4>(IoStatementState &, const DataEdit &, void *); template bool EditRealInput<8>(IoStatementState &, const DataEdit &, void *); -template bool EditRealInput<11>(IoStatementState &, const DataEdit &, void *); -template bool EditRealInput<24>(IoStatementState &, const DataEdit &, void *); -template bool EditRealInput<53>(IoStatementState &, const DataEdit &, void *); -template bool EditRealInput<64>(IoStatementState &, const DataEdit &, void *); -template bool EditRealInput<113>(IoStatementState &, const DataEdit &, void *); +template bool EditRealInput<10>(IoStatementState &, const DataEdit &, void *); +// TODO: double/double +template bool EditRealInput<16>(IoStatementState &, const DataEdit &, void *); } // namespace Fortran::runtime::io diff --git a/flang/runtime/edit-output.h b/flang/runtime/edit-output.h --- a/flang/runtime/edit-output.h +++ b/flang/runtime/edit-output.h @@ -60,18 +60,17 @@ char exponent_[16]; }; -template -class RealOutputEditing : public RealOutputEditingBase { +template class RealOutputEditing : public RealOutputEditingBase { public: + static constexpr int binaryPrecision{common::PrecisionOfRealKind(KIND)}; + using BinaryFloatingPoint = + decimal::BinaryFloatingPointNumber; template RealOutputEditing(IoStatementState &io, A x) : RealOutputEditingBase{io}, x_{x} {} bool Edit(const DataEdit &); private: - using BinaryFloatingPoint = - decimal::BinaryFloatingPointNumber; - // The DataEdit arguments here are const references or copies so that // the original DataEdit can safely serve multiple array elements when // it has a repeat count. @@ -104,12 +103,13 @@ extern template bool EditIntegerOutput( IoStatementState &, const DataEdit &, common::uint128_t); +extern template class RealOutputEditing<2>; +extern template class RealOutputEditing<3>; +extern template class RealOutputEditing<4>; extern template class RealOutputEditing<8>; -extern template class RealOutputEditing<11>; -extern template class RealOutputEditing<24>; -extern template class RealOutputEditing<53>; -extern template class RealOutputEditing<64>; -extern template class RealOutputEditing<113>; +extern template class RealOutputEditing<10>; +// TODO: double/double +extern template class RealOutputEditing<16>; } // namespace Fortran::runtime::io #endif // FORTRAN_RUNTIME_EDIT_OUTPUT_H_ diff --git a/flang/runtime/edit-output.cpp b/flang/runtime/edit-output.cpp --- a/flang/runtime/edit-output.cpp +++ b/flang/runtime/edit-output.cpp @@ -495,10 +495,11 @@ template bool EditIntegerOutput( IoStatementState &, const DataEdit &, common::uint128_t); +template class RealOutputEditing<2>; +template class RealOutputEditing<3>; +template class RealOutputEditing<4>; template class RealOutputEditing<8>; -template class RealOutputEditing<11>; -template class RealOutputEditing<24>; -template class RealOutputEditing<53>; -template class RealOutputEditing<64>; -template class RealOutputEditing<113>; +template class RealOutputEditing<10>; +// TODO: double/double +template class RealOutputEditing<16>; } // namespace Fortran::runtime::io