[libclc] [libclc] Fix fmod returning NaN for subnormal inputs (PR #225351)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 23 00:49:40 PDT 2026
https://github.com/Lurie97 updated https://github.com/llvm/llvm-project/pull/225351
>From 880a250ac09c6528837b1f2169b2b83e61391ecc Mon Sep 17 00:00:00 2001
From: jiajia Qian <jiajia.qian at nxp.com>
Date: Thu, 24 Sep 2026 14:24:50 +0800
Subject: [PATCH] [libclc] Implement isnan/isinf/isfinite without is_fpclass
#124145 changed these functions to use __builtin_isfpclass for better
vectorization. However, some targets mislower isfpclass for subnormals
when denormals are enabled, causing isfinite(subnormal) to return false.
This breaks fmod (#222369), whose |x| < |y| path can return NaN instead
of the subnormal input.
Replace is_fpclass with simple comparisons:
isnan(x) -> x != x
isinf(x) -> fabs(x) == INFINITY
isfinite(x) -> fabs(x) < INFINITY
These forms still vectorize while avoiding the isfpclass issue.
isnormal/issubnormal continue to use isfpclass because they need to
distinguish subnormal values.
Signed-off-by: jiajia Qian <jiajia.qian at nxp.com>
---
.../clc/include/clc/relational/relational.h | 25 +++++++++++++++++++
.../lib/generic/relational/clc_isfinite.cl | 11 +++++---
.../clc/lib/generic/relational/clc_isinf.cl | 11 +++++---
.../clc/lib/generic/relational/clc_isnan.cl | 7 +++---
4 files changed, 45 insertions(+), 9 deletions(-)
diff --git a/libclc/clc/include/clc/relational/relational.h b/libclc/clc/include/clc/relational/relational.h
index 32ed9f431ddbdf..74c91147cfa1c1 100644
--- a/libclc/clc/include/clc/relational/relational.h
+++ b/libclc/clc/include/clc/relational/relational.h
@@ -40,8 +40,33 @@
return _CLC_RELATIONAL_OP(x, y); \
}
+// Define a unary relational builtin from an ordinary expression in terms of x.
+// The scalar version returns 1/0 and the vector versions return -1/0, matching
+// the OpenCL relational convention that ordinary comparison operators already
+// produce, so EXPR should be a plain comparison rather than __builtin_isfpclass
+// (which some targets mislower for subnormals when denormals are supported).
+#define _CLC_DEFINE_RELATIONAL_UNARY(RET_TYPE, VEC_RET_TYPE, __CLC_FUNCTION, \
+ EXPR, ARG_TYPE) \
+ _CLC_DEF _CLC_OVERLOAD RET_TYPE __CLC_FUNCTION(ARG_TYPE x) { return EXPR; } \
+ _CLC_DEF _CLC_OVERLOAD VEC_RET_TYPE##2 __CLC_FUNCTION(ARG_TYPE##2 x) { \
+ return EXPR; \
+ } \
+ _CLC_DEF _CLC_OVERLOAD VEC_RET_TYPE##3 __CLC_FUNCTION(ARG_TYPE##3 x) { \
+ return EXPR; \
+ } \
+ _CLC_DEF _CLC_OVERLOAD VEC_RET_TYPE##4 __CLC_FUNCTION(ARG_TYPE##4 x) { \
+ return EXPR; \
+ } \
+ _CLC_DEF _CLC_OVERLOAD VEC_RET_TYPE##8 __CLC_FUNCTION(ARG_TYPE##8 x) { \
+ return EXPR; \
+ } \
+ _CLC_DEF _CLC_OVERLOAD VEC_RET_TYPE##16 __CLC_FUNCTION(ARG_TYPE##16 x) { \
+ return EXPR; \
+ }
+
#define fcNan (__FPCLASS_SNAN | __FPCLASS_QNAN)
#define fcInf (__FPCLASS_POSINF | __FPCLASS_NEGINF)
+
#define fcNormal (__FPCLASS_POSNORMAL | __FPCLASS_NEGNORMAL)
#define fcSubnormal (__FPCLASS_POSSUBNORMAL | __FPCLASS_NEGSUBNORMAL)
#define fcPosFinite \
diff --git a/libclc/clc/lib/generic/relational/clc_isfinite.cl b/libclc/clc/lib/generic/relational/clc_isfinite.cl
index dbd181e29aa172..3b9577b1029887 100644
--- a/libclc/clc/lib/generic/relational/clc_isfinite.cl
+++ b/libclc/clc/lib/generic/relational/clc_isfinite.cl
@@ -6,10 +6,13 @@
//
//===----------------------------------------------------------------------===//
+#include "clc/float/definitions.h"
#include "clc/internal/clc.h"
+#include "clc/math/clc_fabs.h"
#include "clc/relational/relational.h"
-_CLC_DEFINE_ISFPCLASS(int, int, __clc_isfinite, fcFinite, float)
+_CLC_DEFINE_RELATIONAL_UNARY(int, int, __clc_isfinite,
+ (__clc_fabs(x) < (float)INFINITY), float)
#ifdef cl_khr_fp64
@@ -17,7 +20,8 @@ _CLC_DEFINE_ISFPCLASS(int, int, __clc_isfinite, fcFinite, float)
// The scalar version of __clc_isfinite(double) returns an int, but the vector
// versions return long.
-_CLC_DEFINE_ISFPCLASS(int, long, __clc_isfinite, fcFinite, double)
+_CLC_DEFINE_RELATIONAL_UNARY(int, long, __clc_isfinite,
+ (__clc_fabs(x) < (double)INFINITY), double)
#endif
@@ -27,6 +31,7 @@ _CLC_DEFINE_ISFPCLASS(int, long, __clc_isfinite, fcFinite, double)
// The scalar version of __clc_isfinite(half) returns an int, but the vector
// versions return short.
-_CLC_DEFINE_ISFPCLASS(int, short, __clc_isfinite, fcFinite, half)
+_CLC_DEFINE_RELATIONAL_UNARY(int, short, __clc_isfinite,
+ (__clc_fabs(x) < (half)INFINITY), half)
#endif
diff --git a/libclc/clc/lib/generic/relational/clc_isinf.cl b/libclc/clc/lib/generic/relational/clc_isinf.cl
index 62bb8ed063459f..5aa88c88b4cc8d 100644
--- a/libclc/clc/lib/generic/relational/clc_isinf.cl
+++ b/libclc/clc/lib/generic/relational/clc_isinf.cl
@@ -6,10 +6,13 @@
//
//===----------------------------------------------------------------------===//
+#include "clc/float/definitions.h"
#include "clc/internal/clc.h"
+#include "clc/math/clc_fabs.h"
#include "clc/relational/relational.h"
-_CLC_DEFINE_ISFPCLASS(int, int, __clc_isinf, fcInf, float)
+_CLC_DEFINE_RELATIONAL_UNARY(int, int, __clc_isinf,
+ (__clc_fabs(x) == (float)INFINITY), float)
#ifdef cl_khr_fp64
@@ -17,7 +20,8 @@ _CLC_DEFINE_ISFPCLASS(int, int, __clc_isinf, fcInf, float)
// The scalar version of __clc_isinf(double) returns an int, but the vector
// versions return long.
-_CLC_DEFINE_ISFPCLASS(int, long, __clc_isinf, fcInf, double)
+_CLC_DEFINE_RELATIONAL_UNARY(int, long, __clc_isinf,
+ (__clc_fabs(x) == (double)INFINITY), double)
#endif
@@ -27,6 +31,7 @@ _CLC_DEFINE_ISFPCLASS(int, long, __clc_isinf, fcInf, double)
// The scalar version of __clc_isinf(half) returns an int, but the vector
// versions return short.
-_CLC_DEFINE_ISFPCLASS(int, short, __clc_isinf, fcInf, half)
+_CLC_DEFINE_RELATIONAL_UNARY(int, short, __clc_isinf,
+ (__clc_fabs(x) == (half)INFINITY), half)
#endif
diff --git a/libclc/clc/lib/generic/relational/clc_isnan.cl b/libclc/clc/lib/generic/relational/clc_isnan.cl
index ba97f88ce76f7b..dc7d691a050d0b 100644
--- a/libclc/clc/lib/generic/relational/clc_isnan.cl
+++ b/libclc/clc/lib/generic/relational/clc_isnan.cl
@@ -9,7 +9,7 @@
#include "clc/internal/clc.h"
#include "clc/relational/relational.h"
-_CLC_DEFINE_ISFPCLASS(int, int, __clc_isnan, fcNan, float)
+_CLC_DEFINE_RELATIONAL_UNARY(int, int, __clc_isnan, (x != x), float)
#ifdef cl_khr_fp64
@@ -17,7 +17,7 @@ _CLC_DEFINE_ISFPCLASS(int, int, __clc_isnan, fcNan, float)
// The scalar version of __clc_isnan(double) returns an int, but the vector
// versions return a long.
-_CLC_DEFINE_ISFPCLASS(int, long, __clc_isnan, fcNan, double)
+_CLC_DEFINE_RELATIONAL_UNARY(int, long, __clc_isnan, (x != x), double)
#endif
@@ -27,6 +27,7 @@ _CLC_DEFINE_ISFPCLASS(int, long, __clc_isnan, fcNan, double)
// The scalar version of __clc_isnan(half) returns an int, but the vector
// versions return a short.
-_CLC_DEFINE_ISFPCLASS(int, short, __clc_isnan, fcNan, half)
+_CLC_DEFINE_RELATIONAL_UNARY(int, short, __clc_isnan, (x != x), half)
#endif
+
More information about the cfe-commits
mailing list