-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[flang][runtime] Support SPACING for REAL(2 & 3) #106575
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-flang-runtime Author: Peter Klausler (klausler) ChangesAdd 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. Full diff: https://github.com/llvm/llvm-project/pull/106575.diff 4 Files Affected:
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);
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
Could you add a test so we can see what it gets lower to, or are more changes required in lowering?
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.
Done. |
Use APIs added in #106575 This is needed to fix HDF5 builds that are blocked by SPACING TODOs for REAL(2) and currently needs manual hacks.
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.