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

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Thu Aug 29 08:49:32 PDT 2024


https://github.com/klausler created https://github.com/llvm/llvm-project/pull/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.

>From 78ae03fc5baf1f2c7338c42706525ce1bff10c6e Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Wed, 28 Aug 2024 15:15:33 -0700
Subject: [PATCH] [flang][runtime] Support SPACING for REAL(2 & 3)

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.
---
 flang/include/flang/Runtime/cpp-type.h | 36 +++++++++++++++++++++++---
 flang/include/flang/Runtime/numeric.h  | 15 +++++++++++
 flang/runtime/numeric-templates.h      | 10 +++++--
 flang/runtime/numeric.cpp              | 20 ++++++++++++++
 4 files changed, 75 insertions(+), 6 deletions(-)

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..6d2191f8f77ac2 100644
--- a/flang/runtime/numeric-templates.h
+++ b/flang/runtime/numeric-templates.h
@@ -343,10 +343,16 @@ 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)
+#ifndef __STDCPP_FLOAT16_T__
+    if constexpr (PREC == 11) {
+      return 0.00006103515625E-04; // REAL(TINY(0._2))
+    }
+#endif
+    // 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);



More information about the flang-commits mailing list