[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