[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