[flang-commits] [flang] d56fdc8 - [flang][msvc] Avoid dependence on long double

peter klausler via flang-commits flang-commits at lists.llvm.org
Wed Oct 7 15:12:43 PDT 2020


Author: peter klausler
Date: 2020-10-07T15:12:08-07:00
New Revision: d56fdc8e95df3431b67d33fe4b03a08406897339

URL: https://github.com/llvm/llvm-project/commit/d56fdc8e95df3431b67d33fe4b03a08406897339
DIFF: https://github.com/llvm/llvm-project/commit/d56fdc8e95df3431b67d33fe4b03a08406897339.diff

LOG: [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

Added: 
    

Modified: 
    flang/include/flang/Common/real.h
    flang/include/flang/Decimal/binary-floating-point.h
    flang/include/flang/Evaluate/type.h
    flang/runtime/descriptor-io.h
    flang/runtime/edit-input.cpp
    flang/runtime/edit-input.h
    flang/runtime/edit-output.cpp
    flang/runtime/edit-output.h

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Common/real.h b/flang/include/flang/Common/real.h
index 6ff9e441f2ce..036f665d3da6 100644
--- a/flang/include/flang/Common/real.h
+++ b/flang/include/flang/Common/real.h
@@ -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

diff  --git a/flang/include/flang/Decimal/binary-floating-point.h b/flang/include/flang/Decimal/binary-floating-point.h
index 24c23b0ce5ce..b2ff4197ce70 100644
--- a/flang/include/flang/Decimal/binary-floating-point.h
+++ b/flang/include/flang/Decimal/binary-floating-point.h
@@ -48,6 +48,7 @@ class BinaryFloatingPointNumber : public common::RealDetails<BINARY_PRECISION> {
       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
index 183cb6de2781..0619f9290cbf 100644
--- 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 <cinttypes>
 #include <optional>
@@ -235,51 +236,13 @@ class Type<TypeCategory::Integer, KIND>
   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> {
-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> {
+template <int KIND>
+class Type<TypeCategory::Real, KIND>
+    : public TypeBase<TypeCategory::Real, KIND> {
 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.

diff  --git a/flang/runtime/descriptor-io.h b/flang/runtime/descriptor-io.h
index 22552f27c169..f98797d78b50 100644
--- a/flang/runtime/descriptor-io.h
+++ b/flang/runtime/descriptor-io.h
@@ -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",

diff  --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp
index da281aa68e43..08693f251b07 100644
--- a/flang/runtime/edit-input.cpp
+++ b/flang/runtime/edit-input.cpp
@@ -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

diff  --git a/flang/runtime/edit-input.h b/flang/runtime/edit-input.h
index c628b9c7e673..a8b0e76cfefd 100644
--- a/flang/runtime/edit-input.h
+++ b/flang/runtime/edit-input.h
@@ -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<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-output.cpp b/flang/runtime/edit-output.cpp
index 145e01044144..31ba9f152d74 100644
--- a/flang/runtime/edit-output.cpp
+++ b/flang/runtime/edit-output.cpp
@@ -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

diff  --git a/flang/runtime/edit-output.h b/flang/runtime/edit-output.h
index d819c1007caf..251dc797f5e0 100644
--- a/flang/runtime/edit-output.h
+++ b/flang/runtime/edit-output.h
@@ -60,18 +60,17 @@ class RealOutputEditingBase {
   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_


        


More information about the flang-commits mailing list