From 7d4d6e88bc01affa9774cc304123ca0369c77800 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 8 Mar 2024 13:48:31 -0800 Subject: [PATCH] convertDoubleTo: add FP16 support Currently unused. I've tested that GCC 13 and Clang 17 do compile this and do output reasonable assembly, with and without AVX512FP16 (I also tested AVX10.1 with GCC 14). Clang is unable to allocate a "v" (vector) register when T is qfloat16, so I could only implement the conversion using _Float16. Strictly speaking, Clang >= 16 always knows about _Float16, but I didn't want to have a different detection from qtypes.h. Change-Id: I6818d78a57394e37857bfffd17bae860f8055324 Reviewed-by: Edward Welbourne --- src/corelib/global/qnumeric_p.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h index 64fb69c8f3..d40e6b964b 100644 --- a/src/corelib/global/qnumeric_p.h +++ b/src/corelib/global/qnumeric_p.h @@ -339,6 +339,39 @@ convertDoubleTo(double v, T *value, bool allow_precision_upgrade = true) # endif return sse_check_result(*value); } + +# if defined(__F16C__) || defined(__AVX512FP16__) + if constexpr (sizeof(T) == 2 && std::numeric_limits::max_exponent == 16) { + // qfloat16 or std::float16_t, but not std::bfloat16_t or std::bfloat8_t + auto doConvert = [&](auto *out) { + asm ("vldmxcsr %[csr]\n\t" +# ifdef __AVX512FP16__ + // AVX512FP16 & AVX10 have an instruction for this + "vcvtsd2sh %[in], %[in], %[out]\n\t" +# else + "vcvtsd2ss %[in], %[in], %[out]\n\t" // sets DEST[MAXVL-1:128] := 0 + "vcvtps2ph %[rc], %[out], %[out]\n\t" +# endif + "vstmxcsr %[csr]" + : [csr] "+m" (csr), [out] "=v" (*out) + : [in] "v" (v), [rc] "i" (_MM_FROUND_CUR_DIRECTION) + ); + return sse_check_result(out); + }; + + if constexpr (std::is_same_v && !std::is_void_v) { + typename T::NativeType tmp; + bool b = doConvert(&tmp); + *value = tmp; + return b; + } else { +# ifndef Q_CC_CLANG + // Clang can only implement this if it has a native FP16 type + return doConvert(value); +# endif + } + } +# endif #endif // __SSE2__ && inline assembly if (!qt_is_finite(v) && std::numeric_limits::has_infinity) {