https://github.com/Lurie97 created 
https://github.com/llvm/llvm-project/pull/225351

#222369 classifies the NaN/Inf/zero edge cases with __clc_isnan and 
__clc_isfinite, which lower to __builtin_isfpclass. Some targets misclassify 
subnormals there when denormals are supported, so a subnormal x with a normal y 
(|x| < |y|, which must return x unchanged) yields NaN:

  fmod(-0x1.26e13p-128, -0x1.2afc64p+16) -> nan, expected -0x1.26e13p-128

Classify with plain bit arithmetic as the pre-#222369 code did. The reduction 
loop is unchanged.

Fixes OpenCL-CTS math_brute_force fmod on a device advertising CL_FP_DENORM 
(i.MX95 Mali-G310, Panfrost/Rusticl).

>From e9873f20ca939f3d6a04f06f2051ebe6b7d1f5af Mon Sep 17 00:00:00 2001
From: jiajia Qian <[email protected]>
Date: Wed, 23 Sep 2026 17:14:31 +0800
Subject: [PATCH] [libclc] Fix fmod returning NaN for subnormal inputs

#222369 classifies the NaN/Inf/zero edge cases with __clc_isnan and
__clc_isfinite, which lower to __builtin_isfpclass. Some targets
misclassify subnormals there when denormals are supported, so a subnormal
x with a normal y (|x| < |y|, which must return x unchanged) yields NaN:

  fmod(-0x1.26e13p-128, -0x1.2afc64p+16) -> nan, expected -0x1.26e13p-128

Classify with plain bit arithmetic as the pre-#222369 code did. The
reduction loop is unchanged.

Fixes OpenCL-CTS math_brute_force fmod on a device advertising
CL_FP_DENORM (i.MX95 Mali-G310, Panfrost/Rusticl).

Signed-off-by: jiajia Qian <[email protected]>
---
 libclc/clc/lib/generic/math/clc_fmod.cl | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/libclc/clc/lib/generic/math/clc_fmod.cl 
b/libclc/clc/lib/generic/math/clc_fmod.cl
index 699d95485b71e9..64d52e40a042a7 100644
--- a/libclc/clc/lib/generic/math/clc_fmod.cl
+++ b/libclc/clc/lib/generic/math/clc_fmod.cl
@@ -17,8 +17,6 @@
 #include <clc/math/clc_recip_fast.h>
 #include <clc/math/clc_rint.h>
 #include <clc/math/math.h>
-#include <clc/relational/clc_isfinite.h>
-#include <clc/relational/clc_isnan.h>
 
 _CLC_DEF _CLC_OVERLOAD float __clc_fmod(float x, float y) {
   // How many bits of the quotient to resolve per iteration.
@@ -69,9 +67,15 @@ _CLC_DEF _CLC_OVERLOAD float __clc_fmod(float x, float y) {
   }
 
   // fmod(x, 0) is NaN; fmod(Inf, y) is NaN; fmod(x, NaN)/fmod(NaN, y) is NaN.
-  ret = y == 0.0f ? FLT_NAN : ret;
-  int c = !__clc_isnan(y) && __clc_isfinite(x);
-  ret = c ? ret : FLT_NAN;
+  // Classify with plain bit arithmetic rather than __clc_isnan/__clc_isfinite:
+  // those lower to __builtin_isfpclass, which some targets implement in a way
+  // that misclassifies subnormal inputs when denormals are supported, turning
+  // the |x| < |y| result (a subnormal x) into a NaN.
+  int axbits = __clc_as_int(x) & EXSIGNBIT_SP32;
+  int aybits = __clc_as_int(y) & EXSIGNBIT_SP32;
+  int c = axbits > PINFBITPATT_SP32 | aybits > PINFBITPATT_SP32 |
+          axbits == PINFBITPATT_SP32 | aybits == 0;
+  ret = c ? __clc_as_float(QNANBITPATT_SP32) : ret;
 
   return ret;
 }
@@ -136,9 +140,12 @@ _CLC_DEF _CLC_OVERLOAD double __clc_fmod(double x, double 
y) {
   }
 
   // fmod(x, 0) is NaN; fmod(Inf, y) is NaN; fmod(x, NaN)/fmod(NaN, y) is NaN.
-  ret = y == 0.0 ? DBL_NAN : ret;
-  int c = !__clc_isnan(y) && __clc_isfinite(x);
-  ret = c ? ret : DBL_NAN;
+  // See the FP32 version for why this avoids __clc_isnan/__clc_isfinite.
+  ulong axbits = __clc_as_ulong(x) & ~SIGNBIT_DP64;
+  ulong aybits = __clc_as_ulong(y) & ~SIGNBIT_DP64;
+  int c = axbits > PINFBITPATT_DP64 || aybits > PINFBITPATT_DP64 ||
+          axbits == PINFBITPATT_DP64 || aybits == 0;
+  ret = c ? __clc_as_double(QNANBITPATT_DP64) : ret;
 
   return ret;
 }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to