[flang][msvc] Avoid dependence on long double
MSVC does not support a distinct 80-bit extended precision "long double" type. Rework the I/O runtime to avoid using native C/C++ type names. Centralize the mappings between the KIND= type parameters of REAL and their binary precisions in the common real.h header file, and use KIND type parameter values rather than binary precisions for clarity where appropriate. This patch, if successful, should obviate the need for Differential review D88511. (This patch anticipates a successful review of D88688, which fixes the function that maps each kind of real to its maximum number of significant decimal digits.) Differential revision: https://reviews.llvm.org/D88752
This commit is contained in:
parent
8da0df3d6d
commit
d56fdc8e95
|
@ -20,20 +20,20 @@ namespace Fortran::common {
|
|||
// 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 @@ static constexpr int BitsForBinaryPrecision(int binaryPrecision) {
|
|||
// 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 <int BINARY_PRECISION> class RealDetails {
|
||||
private:
|
||||
// Converts bit widths to whole decimal digits
|
||||
|
|
|
@ -48,6 +48,7 @@ public:
|
|||
const BinaryFloatingPointNumber &that) = default;
|
||||
constexpr BinaryFloatingPointNumber &operator=(
|
||||
BinaryFloatingPointNumber &&that) = default;
|
||||
constexpr explicit BinaryFloatingPointNumber(RawType raw) : raw_{raw} {}
|
||||
|
||||
RawType raw() const { return raw_; }
|
||||
|
||||
|
|
|
@ -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 <cinttypes>
|
||||
#include <optional>
|
||||
|
@ -235,51 +236,13 @@ public:
|
|||
using Scalar = value::Integer<8 * KIND>;
|
||||
};
|
||||
|
||||
// REAL(KIND=2) is IEEE half-precision (16 bits)
|
||||
template <>
|
||||
class Type<TypeCategory::Real, 2> : public TypeBase<TypeCategory::Real, 2> {
|
||||
template <int KIND>
|
||||
class Type<TypeCategory::Real, KIND>
|
||||
: public TypeBase<TypeCategory::Real, KIND> {
|
||||
public:
|
||||
using Scalar =
|
||||
value::Real<typename Type<TypeCategory::Integer, 2>::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<TypeCategory::Real, 3> : public TypeBase<TypeCategory::Real, 3> {
|
||||
public:
|
||||
using Scalar =
|
||||
value::Real<typename Type<TypeCategory::Integer, 2>::Scalar, 8>;
|
||||
};
|
||||
|
||||
// REAL(KIND=4) is IEEE-754 single precision (32 bits)
|
||||
template <>
|
||||
class Type<TypeCategory::Real, 4> : public TypeBase<TypeCategory::Real, 4> {
|
||||
public:
|
||||
using Scalar =
|
||||
value::Real<typename Type<TypeCategory::Integer, 4>::Scalar, 24>;
|
||||
};
|
||||
|
||||
// REAL(KIND=8) is IEEE double precision (64 bits)
|
||||
template <>
|
||||
class Type<TypeCategory::Real, 8> : public TypeBase<TypeCategory::Real, 8> {
|
||||
public:
|
||||
using Scalar =
|
||||
value::Real<typename Type<TypeCategory::Integer, 8>::Scalar, 53>;
|
||||
};
|
||||
|
||||
// REAL(KIND=10) is x87 FPU extended precision (80 bits, all explicit)
|
||||
template <>
|
||||
class Type<TypeCategory::Real, 10> : public TypeBase<TypeCategory::Real, 10> {
|
||||
public:
|
||||
using Scalar = value::Real<value::Integer<80>, 64>;
|
||||
};
|
||||
|
||||
// REAL(KIND=16) is IEEE quad precision (128 bits)
|
||||
template <>
|
||||
class Type<TypeCategory::Real, 16> : public TypeBase<TypeCategory::Real, 16> {
|
||||
public:
|
||||
using Scalar = value::Real<value::Integer<128>, 113>;
|
||||
static constexpr int precision{common::PrecisionOfRealKind(KIND)};
|
||||
static constexpr int bits{common::BitsForBinaryPrecision(precision)};
|
||||
using Scalar = value::Real<value::Integer<bits>, precision>;
|
||||
};
|
||||
|
||||
// The KIND type parameter on COMPLEX is the kind of each of its components.
|
||||
|
|
|
@ -61,21 +61,22 @@ inline bool FormattedIntegerIO(
|
|||
return true;
|
||||
}
|
||||
|
||||
template <int PREC, typename A, Direction DIR>
|
||||
template <int KIND, Direction DIR>
|
||||
inline bool FormattedRealIO(
|
||||
IoStatementState &io, const Descriptor &descriptor) {
|
||||
std::size_t numElements{descriptor.Elements()};
|
||||
SubscriptValue subscripts[maxRank];
|
||||
descriptor.GetLowerBounds(subscripts);
|
||||
using RawType = typename RealOutputEditing<KIND>::BinaryFloatingPoint;
|
||||
for (std::size_t j{0}; j < numElements; ++j) {
|
||||
if (auto edit{io.GetNextDataEdit()}) {
|
||||
A &x{ExtractElement<A>(io, descriptor, subscripts)};
|
||||
RawType &x{ExtractElement<RawType>(io, descriptor, subscripts)};
|
||||
if constexpr (DIR == Direction::Output) {
|
||||
if (!RealOutputEditing<PREC>{io, x}.Edit(*edit)) {
|
||||
if (!RealOutputEditing<KIND>{io, x}.Edit(*edit)) {
|
||||
return false;
|
||||
}
|
||||
} else if (edit->descriptor != DataEdit::ListDirectedNullValue) {
|
||||
if (!EditRealInput<PREC>(io, *edit, reinterpret_cast<void *>(&x))) {
|
||||
if (!EditRealInput<KIND>(io, *edit, reinterpret_cast<void *>(&x))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +91,7 @@ inline bool FormattedRealIO(
|
|||
return true;
|
||||
}
|
||||
|
||||
template <int PREC, typename A, Direction DIR>
|
||||
template <int KIND, Direction DIR>
|
||||
inline bool FormattedComplexIO(
|
||||
IoStatementState &io, const Descriptor &descriptor) {
|
||||
std::size_t numElements{descriptor.Elements()};
|
||||
|
@ -98,14 +99,15 @@ inline bool FormattedComplexIO(
|
|||
descriptor.GetLowerBounds(subscripts);
|
||||
bool isListOutput{
|
||||
io.get_if<ListDirectedStatementState<Direction::Output>>() != nullptr};
|
||||
using RawType = typename RealOutputEditing<KIND>::BinaryFloatingPoint;
|
||||
for (std::size_t j{0}; j < numElements; ++j) {
|
||||
A *x{&ExtractElement<A>(io, descriptor, subscripts)};
|
||||
RawType *x{&ExtractElement<RawType>(io, descriptor, subscripts)};
|
||||
if (isListOutput) {
|
||||
DataEdit rEdit, iEdit;
|
||||
rEdit.descriptor = DataEdit::ListDirectedRealPart;
|
||||
iEdit.descriptor = DataEdit::ListDirectedImaginaryPart;
|
||||
if (!RealOutputEditing<PREC>{io, x[0]}.Edit(rEdit) ||
|
||||
!RealOutputEditing<PREC>{io, x[1]}.Edit(iEdit)) {
|
||||
if (!RealOutputEditing<KIND>{io, x[0]}.Edit(rEdit) ||
|
||||
!RealOutputEditing<KIND>{io, x[1]}.Edit(iEdit)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
@ -114,12 +116,12 @@ inline bool FormattedComplexIO(
|
|||
if (!edit) {
|
||||
return false;
|
||||
} else if constexpr (DIR == Direction::Output) {
|
||||
if (!RealOutputEditing<PREC>{io, *x}.Edit(*edit)) {
|
||||
if (!RealOutputEditing<KIND>{io, *x}.Edit(*edit)) {
|
||||
return false;
|
||||
}
|
||||
} else if (edit->descriptor == DataEdit::ListDirectedNullValue) {
|
||||
break;
|
||||
} else if (!EditRealInput<PREC>(
|
||||
} else if (!EditRealInput<KIND>(
|
||||
io, *edit, reinterpret_cast<void *>(x))) {
|
||||
return false;
|
||||
}
|
||||
|
@ -275,18 +277,19 @@ static bool DescriptorIO(IoStatementState &io, const Descriptor &descriptor) {
|
|||
}
|
||||
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 @@ static bool DescriptorIO(IoStatementState &io, const Descriptor &descriptor) {
|
|||
}
|
||||
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",
|
||||
|
|
|
@ -260,8 +260,9 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
|
|||
return got;
|
||||
}
|
||||
|
||||
template <int binaryPrecision>
|
||||
template <int KIND>
|
||||
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 @@ bool EditCommonRealInput(IoStatementState &io, const DataEdit &edit, void *n) {
|
|||
return true;
|
||||
}
|
||||
|
||||
template <int binaryPrecision>
|
||||
template <int KIND>
|
||||
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 @@ bool EditRealInput(IoStatementState &io, const DataEdit &edit, void *n) {
|
|||
case 'E': // incl. EN, ES, & EX
|
||||
case 'D':
|
||||
case 'G':
|
||||
return EditCommonRealInput<binaryPrecision>(io, edit, n);
|
||||
return EditCommonRealInput<KIND>(io, edit, n);
|
||||
case 'B':
|
||||
return EditBOZInput(
|
||||
io, edit, n, 2, common::BitsForBinaryPrecision(binaryPrecision));
|
||||
|
@ -459,10 +461,11 @@ bool EditDefaultCharacterInput(
|
|||
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
|
||||
|
|
|
@ -17,24 +17,25 @@ namespace Fortran::runtime::io {
|
|||
|
||||
bool EditIntegerInput(IoStatementState &, const DataEdit &, void *, int kind);
|
||||
|
||||
template <int binaryPrecision>
|
||||
template <int KIND>
|
||||
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<2>(
|
||||
IoStatementState &, const DataEdit &, void *);
|
||||
extern template bool EditRealInput<3>(
|
||||
IoStatementState &, const DataEdit &, void *);
|
||||
extern template bool EditRealInput<4>(
|
||||
IoStatementState &, const DataEdit &, void *);
|
||||
extern template bool EditRealInput<8>(
|
||||
IoStatementState &, const DataEdit &, void *);
|
||||
extern template bool EditRealInput<11>(
|
||||
extern template bool EditRealInput<10>(
|
||||
IoStatementState &, const DataEdit &, void *);
|
||||
extern template bool EditRealInput<24>(
|
||||
IoStatementState &, const DataEdit &, void *);
|
||||
extern template bool EditRealInput<53>(
|
||||
IoStatementState &, const DataEdit &, void *);
|
||||
extern template bool EditRealInput<64>(
|
||||
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_
|
||||
|
|
|
@ -495,10 +495,11 @@ template bool EditIntegerOutput<std::int64_t, std::uint64_t>(
|
|||
template bool EditIntegerOutput<common::uint128_t, common::uint128_t>(
|
||||
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
|
||||
|
|
|
@ -60,18 +60,17 @@ protected:
|
|||
char exponent_[16];
|
||||
};
|
||||
|
||||
template <int binaryPrecision = 53>
|
||||
class RealOutputEditing : public RealOutputEditingBase {
|
||||
template <int KIND> class RealOutputEditing : public RealOutputEditingBase {
|
||||
public:
|
||||
static constexpr int binaryPrecision{common::PrecisionOfRealKind(KIND)};
|
||||
using BinaryFloatingPoint =
|
||||
decimal::BinaryFloatingPointNumber<binaryPrecision>;
|
||||
template <typename A>
|
||||
RealOutputEditing(IoStatementState &io, A x)
|
||||
: RealOutputEditingBase{io}, x_{x} {}
|
||||
bool Edit(const DataEdit &);
|
||||
|
||||
private:
|
||||
using BinaryFloatingPoint =
|
||||
decimal::BinaryFloatingPointNumber<binaryPrecision>;
|
||||
|
||||
// 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<std::int64_t, std::uint64_t>(
|
|||
extern template bool EditIntegerOutput<common::uint128_t, common::uint128_t>(
|
||||
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_
|
||||
|
|
Loading…
Reference in New Issue