https://github.com/rjodinchr created https://github.com/llvm/llvm-project/pull/233787
In fp32 `__clc_erfc`, inputs with large magnitude (`|x| >= 2^64` or `inf`) overflow `-x * x` to `-inf`, causing `__clc_fma(-x, x, -x2h)` and `__clc_erfc_scaled(ax)` to produce `NaN` prior to the `ax > 0x1.41bbf8p+3f ? 0.0f : ret` clamp. On some target where vector `select(cond, ret, 0.0f)` is lowered to `ret * (cond ? 1.0f : 0.0f)`, `NaN * 0.0f` propagates `NaN` instead of returning `0.0f` (for `x > 0`) or `2.0f` (for `x < 0`), failing vector erfc in OpenCL CTS bruteforce. Clamp `ax` before evaluating the polynomial so `ret` remains finite for out-of-range inputs while preserving `NaN` propagation when `x` is `NaN`. >From 2cafdc1607ed8ecfb32da12f76cc6b3771cc3138 Mon Sep 17 00:00:00 2001 From: Romaric Jodin <[email protected]> Date: Tue, 20 Oct 2026 11:13:50 +0200 Subject: [PATCH] [libclc] Avoid intermediate NaN for large inputs in fp32 erfc In fp32 `__clc_erfc`, inputs with large magnitude (`|x| >= 2^64` or `inf`) overflow `-x * x` to `-inf`, causing `__clc_fma(-x, x, -x2h)` and `__clc_erfc_scaled(ax)` to produce `NaN` prior to the `ax > 0x1.41bbf8p+3f ? 0.0f : ret` clamp. On some target where vector `select(cond, ret, 0.0f)` is lowered to `ret * (cond ? 1.0f : 0.0f)`, `NaN * 0.0f` propagates `NaN` instead of returning `0.0f` (for `x > 0`) or `2.0f` (for `x < 0`), failing vector erfc in OpenCL CTS bruteforce. Clamp `ax` before evaluating the polynomial so `ret` remains finite for out-of-range inputs while preserving `NaN` propagation when `x` is `NaN`. Change-Id: I2660139949901c115cca82e87ae91363241bbd8d --- libclc/clc/lib/generic/math/clc_erfc.inc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libclc/clc/lib/generic/math/clc_erfc.inc b/libclc/clc/lib/generic/math/clc_erfc.inc index 8472a819d36609..796fb27de5dc00 100644 --- a/libclc/clc/lib/generic/math/clc_erfc.inc +++ b/libclc/clc/lib/generic/math/clc_erfc.inc @@ -146,11 +146,12 @@ __clc_erfc_scaled(__CLC_FLOATN x) { _CLC_DEF _CLC_OVERLOAD _CLC_CONST __CLC_FLOATN __clc_erfc(__CLC_FLOATN x) { __CLC_FLOATN ax = __clc_fabs(x); - __CLC_FLOATN x2h = -x * x; - __CLC_FLOATN x2l = __clc_fma(-x, x, -x2h); + __CLC_FLOATN cx = ax > 0x1.41bbf8p+3f ? 0x1.41bbfcp+3f : ax; + __CLC_FLOATN x2h = -cx * cx; + __CLC_FLOATN x2l = __clc_fma(-cx, cx, -x2h); __CLC_FLOATN e = __clc_exp(x2h); e = __clc_fma(e, x2l, e); - __CLC_FLOATN ret = e * __clc_erfc_scaled(ax); + __CLC_FLOATN ret = e * __clc_erfc_scaled(cx); ret = ax > 0x1.41bbf8p+3f ? 0.0f : ret; __CLC_FLOATN nret = 2.0f - ret; return x < 0.0f ? nret : ret; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
