[libclc] [libclc] Fix exponent overflow and subnormal rounding in __clc_ldexp (PR #233823)
Romaric Jodin via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 23 02:45:59 PDT 2026
https://github.com/rjodinchr updated https://github.com/llvm/llvm-project/pull/233823
>From 0474d7b184987d0881c8e74bbece75265b468603 Mon Sep 17 00:00:00 2001
From: Romaric Jodin <rjodin at google.com>
Date: Tue, 20 Oct 2026 14:32:45 +0200
Subject: [PATCH 1/2] [libclc] Fix exponent overflow and subnormal rounding in
__clc_ldexp
When fp32 subnormals are
supported (`!__clc_denormals_are_zero_fp32()`), `__clc_ldexp`
previously added `n` to the exponent with plain signed integer
addition, overflowing 32-bit `int` when `n` is near `INT_MAX` or
`INT_MIN` (e.g. `n = INT_MAX` wrapped around to `< -24` and flushed to
zero instead of returning infinity). Additionally, subnormal fp32
results were formed with a truncating right shift instead of
round-to-nearest-even, and shift counts were not clamped to valid
ranges.
Normalize subnormal fp32 inputs before adding `n`, use
`__clc_add_sat(exponent, n)` in both fp32 and fp64 `__clc_ldexp` to
prevent signed integer overflow, clamp shift counts, and apply
round-to-nearest-even when right-shifting into a subnormal fp32
result.
Change-Id: I98b3412d6fd383e292aacb6a63028319fe3fda53
---
libclc/clc/lib/generic/math/clc_ldexp.cl | 37 +++++++++---------------
1 file changed, 14 insertions(+), 23 deletions(-)
diff --git a/libclc/clc/lib/generic/math/clc_ldexp.cl b/libclc/clc/lib/generic/math/clc_ldexp.cl
index 59db94cf047fa8..d5b181445300f9 100644
--- a/libclc/clc/lib/generic/math/clc_ldexp.cl
+++ b/libclc/clc/lib/generic/math/clc_ldexp.cl
@@ -51,32 +51,23 @@ _CLC_DEF _CLC_OVERLOAD float __clc_ldexp(float x, int n) {
127 -
(__clc_as_uint((float)(__clc_as_float(val_ui | 0x3f800000) - 1.0f)) >>
23);
- int dexponent = 25 - fbh;
- uint dval_ui = (((val_ui << fbh) & 0x007fffff) | (dexponent << 23));
- int ex = dexponent + n - multiplier;
- dexponent = ex;
- uint val = sign | (ex << 23) | (dval_ui & 0x007fffff);
- int ex1 = dexponent + multiplier;
- ex1 = -ex1 + 25;
- dval_ui = (((dval_ui & 0x007fffff) | 0x800000) >> ex1);
- dval_ui = dexponent > 0 ? val : dval_ui;
- dval_ui = dexponent > 254 ? 0x7f800000 : dval_ui; /*overflow*/
- dval_ui = dexponent < -multiplier ? 0 : dval_ui; /*underflow*/
- dval_ui = dval_ui | sign;
- val_f = __clc_as_float(dval_ui);
-
- exponent += n;
-
- val = sign | (exponent << 23) | (val_ui & 0x007fffff);
- ex1 = exponent + multiplier;
- ex1 = -ex1 + 25;
- val_ui = (((val_ui & 0x007fffff) | 0x800000) >> ex1);
+ fbh = dexp == 0 ? __clc_clamp(fbh, 1, 23) : 0;
+ exponent = dexp == 0 ? 1 - fbh : exponent;
+ uint mant = (val_ui << fbh) & 0x007fffff;
+
+ exponent = __clc_add_sat(exponent, n);
+
+ uint val = sign | ((uint)exponent << 23) | mant;
+ int ex1 = __clc_clamp(1 - exponent, 1, 25);
+ uint full_mant = mant | 0x00800000;
+ val_ui = full_mant >> ex1;
+ uint guard = (full_mant >> (ex1 - 1)) & 1u;
+ uint sticky = (full_mant & ((1u << (ex1 - 1)) - 1u)) != 0u;
+ val_ui += guard & (sticky | (val_ui & 1u));
val_ui = exponent > 0 ? val : val_ui;
val_ui = exponent > 254 ? 0x7f800000 : val_ui; /*overflow*/
val_ui = exponent < -multiplier ? 0 : val_ui; /*underflow*/
val_ui = val_ui | sign;
-
- val_ui = dexp == 0 ? dval_ui : val_ui;
val_f = __clc_as_float(val_ui);
val_f = (__clc_isnan(x) || __clc_isinf(x) || val_x == 0) ? x : val_f;
@@ -99,7 +90,7 @@ _CLC_DEF _CLC_OVERLOAD double __clc_ldexp(double x, int n) {
ux = c ? ux : l;
- int v = e + n;
+ int v = __clc_add_sat(e, n);
v = __clc_clamp(v, -0x7ff, 0x7ff);
ux &= ~EXPBITS_DP64;
>From b5cf0a22dcb1a97e773d9340974a7da9bce9911b Mon Sep 17 00:00:00 2001
From: Romaric Jodin <rjodin at google.com>
Date: Fri, 23 Oct 2026 11:45:31 +0200
Subject: [PATCH 2/2] applying wenju-he feedback
---
libclc/clc/lib/generic/math/clc_ldexp.cl | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/libclc/clc/lib/generic/math/clc_ldexp.cl b/libclc/clc/lib/generic/math/clc_ldexp.cl
index d5b181445300f9..dcd7ecdf48b6b8 100644
--- a/libclc/clc/lib/generic/math/clc_ldexp.cl
+++ b/libclc/clc/lib/generic/math/clc_ldexp.cl
@@ -60,10 +60,8 @@ _CLC_DEF _CLC_OVERLOAD float __clc_ldexp(float x, int n) {
uint val = sign | ((uint)exponent << 23) | mant;
int ex1 = __clc_clamp(1 - exponent, 1, 25);
uint full_mant = mant | 0x00800000;
- val_ui = full_mant >> ex1;
- uint guard = (full_mant >> (ex1 - 1)) & 1u;
- uint sticky = (full_mant & ((1u << (ex1 - 1)) - 1u)) != 0u;
- val_ui += guard & (sticky | (val_ui & 1u));
+ val_ui =
+ (full_mant + ((1u << (ex1 - 1)) - 1u) + ((full_mant >> ex1) & 1u)) >> ex1;
val_ui = exponent > 0 ? val : val_ui;
val_ui = exponent > 254 ? 0x7f800000 : val_ui; /*overflow*/
val_ui = exponent < -multiplier ? 0 : val_ui; /*underflow*/
More information about the cfe-commits
mailing list