[flang-commits] [flang] 500f6cc - [flang][runtime] Support SPACING for REAL(2 & 3) (#106575)

via flang-commits flang-commits at lists.llvm.org
Wed Sep 4 10:53:25 PDT 2024


Author: Peter Klausler
Date: 2024-09-04T10:53:22-07:00
New Revision: 500f6cc25cb93607e9ea13732b791297acf8f97f

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

LOG: [flang][runtime] Support SPACING for REAL(2 & 3) (#106575)

Add runtime APIs for the intrinsic function SPACING for REAL kinds 2 & 3
in two ways: Spacing2 (& 3) for build environments with std::float16_t,
and Spacing2By4 (& 3By4) variants (for any build environment) which
compute SPACING for those types but accept and return their values as
32-bit floats.

SPACING for REAL(2) is needed by HDF5.

Added: 
    

Modified: 
    flang/include/flang/Runtime/cpp-type.h
    flang/include/flang/Runtime/numeric.h
    flang/runtime/numeric-templates.h
    flang/runtime/numeric.cpp
    flang/unittests/Runtime/Numeric.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Runtime/cpp-type.h b/flang/include/flang/Runtime/cpp-type.h
index 5141d0691c5c6c..fe21dd544cf7d8 100644
--- a/flang/include/flang/Runtime/cpp-type.h
+++ b/flang/include/flang/Runtime/cpp-type.h
@@ -14,11 +14,20 @@
 #include "flang/Common/Fortran.h"
 #include "flang/Common/float128.h"
 #include "flang/Common/uint128.h"
-#include <cfloat>
 #include <complex>
 #include <cstdint>
+#if __cplusplus >= 202302
+#include <stdfloat>
+#endif
 #include <type_traits>
 
+#if !defined HAS_FP16 && __STDCPP_FLOAT16_T__
+#define HAS_FP16 1
+#endif
+#if !defined HAS_BF16 && __STDCPP_BFLOAT16_T__
+#define HAS_BF16 1
+#endif
+
 namespace Fortran::runtime {
 
 using common::TypeCategory;
@@ -37,24 +46,43 @@ template <int KIND> struct CppTypeForHelper<TypeCategory::Integer, KIND> {
   using type = common::HostSignedIntType<8 * KIND>;
 };
 
-// TODO: REAL/COMPLEX(2 & 3)
+#if HAS_FP16
+template <> struct CppTypeForHelper<TypeCategory::Real, 2> {
+  using type = std::float16_t;
+};
+#endif
+#if HAS_BF16
+template <> struct CppTypeForHelper<TypeCategory::Real, 3> {
+  using type = std::bfloat16_t;
+};
+#endif
 template <> struct CppTypeForHelper<TypeCategory::Real, 4> {
+#if __STDCPP_FLOAT32_T__
+  using type = std::float32_t;
+#else
   using type = float;
+#endif
 };
 template <> struct CppTypeForHelper<TypeCategory::Real, 8> {
+#if __STDCPP_FLOAT64_T__
+  using type = std::float64_t;
+#else
   using type = double;
+#endif
 };
 #if LDBL_MANT_DIG == 64
 template <> struct CppTypeForHelper<TypeCategory::Real, 10> {
   using type = long double;
 };
 #endif
-#if LDBL_MANT_DIG == 113
+#if __STDCPP_FLOAT128_T__
+using CppFloat128Type = std::float128_t;
+#elif LDBL_MANT_DIG == 113
 using CppFloat128Type = long double;
 #elif HAS_FLOAT128
 using CppFloat128Type = __float128;
 #endif
-#if LDBL_MANT_DIG == 113 || HAS_FLOAT128
+#if __STDCPP_FLOAT128_t || LDBL_MANT_DIG == 113 || HAS_FLOAT128
 template <> struct CppTypeForHelper<TypeCategory::Real, 16> {
   using type = CppFloat128Type;
 };

diff  --git a/flang/include/flang/Runtime/numeric.h b/flang/include/flang/Runtime/numeric.h
index 6e1979790e3c61..84a5a7cd7a361c 100644
--- a/flang/include/flang/Runtime/numeric.h
+++ b/flang/include/flang/Runtime/numeric.h
@@ -391,6 +391,21 @@ CppTypeFor<TypeCategory::Integer, 4> RTDECL(SelectedRealKindMasked)(
     const char *, int, void *, int, void *, int, void *, int, int);
 
 // SPACING
+// The variants Spacing2By4 and Spacing3By4 compute SPACING for REAL(2/3)
+// but accept and return REAL(4) values, for use in environments where
+// std::float16_t or std::bfloat16_t are unavailable.
+#if HAS_FP16
+CppTypeFor<TypeCategory::Real, 2> RTDECL(Spacing2)(
+    CppTypeFor<TypeCategory::Real, 2>);
+#endif
+CppTypeFor<TypeCategory::Real, 4> RTDECL(Spacing2By4)(
+    CppTypeFor<TypeCategory::Real, 4>);
+#if HAS_BF16
+CppTypeFor<TypeCategory::Real, 3> RTDECL(Spacing3)(
+    CppTypeFor<TypeCategory::Real, 3>);
+#endif
+CppTypeFor<TypeCategory::Real, 4> RTDECL(Spacing3By4)(
+    CppTypeFor<TypeCategory::Real, 4>);
 CppTypeFor<TypeCategory::Real, 4> RTDECL(Spacing4)(
     CppTypeFor<TypeCategory::Real, 4>);
 CppTypeFor<TypeCategory::Real, 8> RTDECL(Spacing8)(

diff  --git a/flang/runtime/numeric-templates.h b/flang/runtime/numeric-templates.h
index 1b5395df945193..1b43498a6bfd12 100644
--- a/flang/runtime/numeric-templates.h
+++ b/flang/runtime/numeric-templates.h
@@ -343,10 +343,15 @@ template <int PREC, typename T> inline RT_API_ATTRS T Spacing(T x) {
     return x; // NaN -> same NaN
   } else if (ISINFTy<T>::compute(x)) {
     return QNANTy<T>::compute(); // +/-Inf -> NaN
-  } else if (x == 0) {
+  } else if (x == 0) { // 0 -> TINY(x)
     // The standard-mandated behavior seems broken, since TINY() can't be
     // subnormal.
-    return MINTy<T>::compute(); // 0 -> TINY(x)
+    if constexpr (PREC == 11) { // REAL(2)
+      return 0.00006103515625E-04; // TINY(0._2)
+    } else {
+      // N.B. TINY(0._3) == TINY(0._4) so this works even if no std::bfloat16_t.
+      return MINTy<T>::compute();
+    }
   } else {
     T result{LDEXPTy<T>::compute(
         static_cast<T>(1.0), ILOGBTy<T>::compute(x) + 1 - PREC)}; // 2**(e-p)

diff  --git a/flang/runtime/numeric.cpp b/flang/runtime/numeric.cpp
index b5e0851a16cd1e..9a8ddc6615564d 100644
--- a/flang/runtime/numeric.cpp
+++ b/flang/runtime/numeric.cpp
@@ -848,6 +848,26 @@ CppTypeFor<TypeCategory::Integer, 4> RTDEF(SelectedRealKindMasked)(
   return SelectedRealKind(p, r, d, mask);
 }
 
+#if HAS_FP16
+CppTypeFor<TypeCategory::Real, 2> RTDEF(Spacing2)(
+    CppTypeFor<TypeCategory::Real, 2> x) {
+  return Spacing<11>(x);
+}
+#endif
+CppTypeFor<TypeCategory::Real, 4> RTDEF(Spacing2By4)(
+    CppTypeFor<TypeCategory::Real, 4> x) {
+  return Spacing<11>(x);
+}
+#if HAS_BF16
+CppTypeFor<TypeCategory::Real, 3> RTDEF(Spacing3)(
+    CppTypeFor<TypeCategory::Real, 3> x) {
+  return Spacing<8>(x);
+}
+#endif
+CppTypeFor<TypeCategory::Real, 4> RTDEF(Spacing3By4)(
+    CppTypeFor<TypeCategory::Real, 4> x) {
+  return Spacing<8>(x);
+}
 CppTypeFor<TypeCategory::Real, 4> RTDEF(Spacing4)(
     CppTypeFor<TypeCategory::Real, 4> x) {
   return Spacing<24>(x);

diff  --git a/flang/unittests/Runtime/Numeric.cpp b/flang/unittests/Runtime/Numeric.cpp
index 9f77e165707834..799756aab3839a 100644
--- a/flang/unittests/Runtime/Numeric.cpp
+++ b/flang/unittests/Runtime/Numeric.cpp
@@ -259,6 +259,11 @@ TEST(Numeric, Spacing) {
       std::isnan(RTNAME(Spacing4)(std::numeric_limits<Real<4>>::infinity())));
   EXPECT_TRUE(
       std::isnan(RTNAME(Spacing8)(std::numeric_limits<Real<8>>::quiet_NaN())));
+  EXPECT_EQ(RTNAME(Spacing2By4)(Real<4>{3.0}), std::ldexp(Real<4>{1.0}, -9));
+  EXPECT_EQ(RTNAME(Spacing2By4)(Real<4>{0.0}), Real<4>{0.00006103515625E-04});
+  EXPECT_EQ(RTNAME(Spacing3By4)(Real<4>{3.0}), std::ldexp(Real<4>{1.0}, -6));
+  EXPECT_EQ(
+      RTNAME(Spacing3By4)(Real<4>{0.0}), std::numeric_limits<Real<4>>::min());
 }
 
 TEST(Numeric, FPowI) {


        


More information about the flang-commits mailing list