[libclc] 1373135 - [libclc] Fix exponent overflow and subnormal rounding in __clc_ldexp (#233823)

via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 25 15:25:33 PDT 2026


Author: Romaric Jodin
Date: 2026-10-26T06:25:27+08:00
New Revision: 13731359fd502d90d6522eb80b9bb422ebaae2b2

URL: https://github.com/llvm/llvm-project/commit/13731359fd502d90d6522eb80b9bb422ebaae2b2
DIFF: https://github.com/llvm/llvm-project/commit/13731359fd502d90d6522eb80b9bb422ebaae2b2.diff

LOG: [libclc] Fix exponent overflow and subnormal rounding in __clc_ldexp (#233823)

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.

Added: 
    

Modified: 
    libclc/clc/lib/generic/math/clc_ldexp.cl

Removed: 
    


################################################################################
diff  --git a/libclc/clc/lib/generic/math/clc_ldexp.cl b/libclc/clc/lib/generic/math/clc_ldexp.cl
index 59db94cf047fa8..dcd7ecdf48b6b8 100644
--- a/libclc/clc/lib/generic/math/clc_ldexp.cl
+++ b/libclc/clc/lib/generic/math/clc_ldexp.cl
@@ -51,32 +51,21 @@ _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 + ((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*/
   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 +88,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;


        


More information about the cfe-commits mailing list