From 9fb1e98d482b9d26cdc0865c287a1ae0c5a45e29 Mon Sep 17 00:00:00 2001 From: "Meszaros, Gergely" Date: Wed, 2 Sep 2026 08:39:01 +0000 Subject: [PATCH] [SYCL][libdevice] return qNaN for (float/double)sNaN to bfloat16 conversion https://github.com/intel/llvm/pull/22114 introduced a fix to return NaN for some specific float or double sNaN bit patterns when converting to bfloat16. Together with that change it also changed the behavior and added a test specifically for the case of converting sNaN to bfloat16. The new behaviour in that PR is to return sNaN for all sNaN inputs. This is not the correct behaviour, IEEE 754 specifies conversions should signal and then return a quiet NaN. We do not implement raising exceptions in the device library, so we cannot signal, but we should still return a quiet NaN for all sNaN inputs. The new behaviour matches the host conversion (from glibc/compiler-rt), see this example on compiler explorer: https://godbolt.org/z/E7ezaPxEd (assisted by Claude Opus 5 ). --- libdevice/imf_bf16.hpp | 7 ++++--- sycl/test-e2e/DeviceLib/imf/double2bfloat16.cpp | 4 ++-- sycl/test-e2e/DeviceLib/imf/float2bfloat16.cpp | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libdevice/imf_bf16.hpp b/libdevice/imf_bf16.hpp index a7345658a8b37..721c930a0f1a5 100644 --- a/libdevice/imf_bf16.hpp +++ b/libdevice/imf_bf16.hpp @@ -39,7 +39,8 @@ __float2bfloat16(float f, __iml_rounding_mode rounding_mode) { return bf16_sign ? 0xFF80 : 0x7F80; else { // input fp32 val is Nan. - bf16_mant = (f_mant & 0x400000) ? 0x40 : 0x3F; + // returns a quiet NaN + bf16_mant = 0x40; return (bf16_sign << 15) | (bf16_exp << 7) | bf16_mant; } } @@ -90,8 +91,8 @@ static _iml_bf16_internal __double2bfloat16(double d) { if (!fp64_mant) { return bf16_sign ? 0xFF80 : 0x7F80; } else { - // returns a signaling or quiet Nan - return (fp64_mant & 0x8'0000'0000'0000) ? 0x7FC0 : 0x7F81; + // returns a quiet Nan + return 0x7FC0; } } diff --git a/sycl/test-e2e/DeviceLib/imf/double2bfloat16.cpp b/sycl/test-e2e/DeviceLib/imf/double2bfloat16.cpp index f0b445094db4d..060182472e6e8 100644 --- a/sycl/test-e2e/DeviceLib/imf/double2bfloat16.cpp +++ b/sycl/test-e2e/DeviceLib/imf/double2bfloat16.cpp @@ -10,11 +10,11 @@ int check_nan_convert(std::initializer_list Inputs, const std::vector &Outputs) { assert(Inputs.size() == Outputs.size()); size_t Idx = 0; - bool Signaling = false; + bool Signaling = true; for (const double *It = Inputs.begin(); It != Inputs.end(); ++It) { uint16_t bf16_bits = Outputs[Idx]; if (is_bfloat16_nan(bf16_bits, Signaling)) { - if (Signaling != is_signaling_nan(*It)) + if (Signaling) return 1; } else return 1; diff --git a/sycl/test-e2e/DeviceLib/imf/float2bfloat16.cpp b/sycl/test-e2e/DeviceLib/imf/float2bfloat16.cpp index 3ff81529703ea..ea0eb894ea6a4 100644 --- a/sycl/test-e2e/DeviceLib/imf/float2bfloat16.cpp +++ b/sycl/test-e2e/DeviceLib/imf/float2bfloat16.cpp @@ -10,11 +10,11 @@ int check_nan_convert(std::initializer_list Inputs, const std::vector &Outputs) { assert(Inputs.size() == Outputs.size()); size_t Idx = 0; - bool Signaling = false; + bool Signaling = true; for (const float *It = Inputs.begin(); It != Inputs.end(); ++It) { uint16_t bf16_bits = Outputs[Idx]; if (is_bfloat16_nan(bf16_bits, Signaling)) { - if (Signaling != is_signaling_nan(*It)) + if (Signaling) return 1; } else return 1;