diff --git a/flang/include/flang/Runtime/cpp-type.h b/flang/include/flang/Runtime/cpp-type.h index 5141d0691c5c6..fe21dd544cf7d 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 #include #include +#if __cplusplus >= 202302 +#include +#endif #include +#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 struct CppTypeForHelper { using type = common::HostSignedIntType<8 * KIND>; }; -// TODO: REAL/COMPLEX(2 & 3) +#if HAS_FP16 +template <> struct CppTypeForHelper { + using type = std::float16_t; +}; +#endif +#if HAS_BF16 +template <> struct CppTypeForHelper { + using type = std::bfloat16_t; +}; +#endif template <> struct CppTypeForHelper { +#if __STDCPP_FLOAT32_T__ + using type = std::float32_t; +#else using type = float; +#endif }; template <> struct CppTypeForHelper { +#if __STDCPP_FLOAT64_T__ + using type = std::float64_t; +#else using type = double; +#endif }; #if LDBL_MANT_DIG == 64 template <> struct CppTypeForHelper { 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 { using type = CppFloat128Type; }; diff --git a/flang/include/flang/Runtime/numeric.h b/flang/include/flang/Runtime/numeric.h index 6e1979790e3c6..84a5a7cd7a361 100644 --- a/flang/include/flang/Runtime/numeric.h +++ b/flang/include/flang/Runtime/numeric.h @@ -391,6 +391,21 @@ CppTypeFor 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 RTDECL(Spacing2)( + CppTypeFor); +#endif +CppTypeFor RTDECL(Spacing2By4)( + CppTypeFor); +#if HAS_BF16 +CppTypeFor RTDECL(Spacing3)( + CppTypeFor); +#endif +CppTypeFor RTDECL(Spacing3By4)( + CppTypeFor); CppTypeFor RTDECL(Spacing4)( CppTypeFor); CppTypeFor RTDECL(Spacing8)( diff --git a/flang/runtime/numeric-templates.h b/flang/runtime/numeric-templates.h index 1b5395df94519..1b43498a6bfd1 100644 --- a/flang/runtime/numeric-templates.h +++ b/flang/runtime/numeric-templates.h @@ -343,10 +343,15 @@ template inline RT_API_ATTRS T Spacing(T x) { return x; // NaN -> same NaN } else if (ISINFTy::compute(x)) { return QNANTy::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::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::compute(); + } } else { T result{LDEXPTy::compute( static_cast(1.0), ILOGBTy::compute(x) + 1 - PREC)}; // 2**(e-p) diff --git a/flang/runtime/numeric.cpp b/flang/runtime/numeric.cpp index b5e0851a16cd1..9a8ddc6615564 100644 --- a/flang/runtime/numeric.cpp +++ b/flang/runtime/numeric.cpp @@ -848,6 +848,26 @@ CppTypeFor RTDEF(SelectedRealKindMasked)( return SelectedRealKind(p, r, d, mask); } +#if HAS_FP16 +CppTypeFor RTDEF(Spacing2)( + CppTypeFor x) { + return Spacing<11>(x); +} +#endif +CppTypeFor RTDEF(Spacing2By4)( + CppTypeFor x) { + return Spacing<11>(x); +} +#if HAS_BF16 +CppTypeFor RTDEF(Spacing3)( + CppTypeFor x) { + return Spacing<8>(x); +} +#endif +CppTypeFor RTDEF(Spacing3By4)( + CppTypeFor x) { + return Spacing<8>(x); +} CppTypeFor RTDEF(Spacing4)( CppTypeFor x) { return Spacing<24>(x); diff --git a/flang/unittests/Runtime/Numeric.cpp b/flang/unittests/Runtime/Numeric.cpp index 9f77e16570783..799756aab3839 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>::infinity()))); EXPECT_TRUE( std::isnan(RTNAME(Spacing8)(std::numeric_limits>::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>::min()); } TEST(Numeric, FPowI) {