From 5077f20f278f03c7ee16feb24dd904af836854fd Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 01:11:36 -0800 Subject: [PATCH 01/21] Fuse xfcosh.cpp into xcosh.cpp. --- stl/CMakeLists.txt | 1 - .../stl_base/stl.files.settings.targets | 1 - stl/src/xcosh.cpp | 31 +++++++++++++++ stl/src/xfcosh.cpp | 39 ------------------- 4 files changed, 31 insertions(+), 41 deletions(-) delete mode 100644 stl/src/xfcosh.cpp diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 1f08f33bb36..a088c1ffae3 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -284,7 +284,6 @@ set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/xdateord.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xdtest.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xexp.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfcosh.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfdnorm.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfdscale.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfdtest.cpp diff --git a/stl/msbuild/stl_base/stl.files.settings.targets b/stl/msbuild/stl_base/stl.files.settings.targets index 95fd85f8970..4db62e56d46 100644 --- a/stl/msbuild/stl_base/stl.files.settings.targets +++ b/stl/msbuild/stl_base/stl.files.settings.targets @@ -78,7 +78,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - diff --git a/stl/src/xcosh.cpp b/stl/src/xcosh.cpp index 16447fca0fd..01c70ca4eaf 100644 --- a/stl/src/xcosh.cpp +++ b/stl/src/xcosh.cpp @@ -40,4 +40,35 @@ _CRTIMP2_PURE long double __CLRCALL_PURE_OR_CDECL _LCosh(long double x, long dou return _Cosh(static_cast(x), static_cast(y)); } +_CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FCosh(float x, float y) noexcept { // compute y * cosh(x), |y| <= 1 + switch (_FDtest(&x)) { // test for special codes + case _NANCODE: + case _INFCODE: + return x; + case 0: + return y; + default: // finite + if (y == 0.0) { + return y; + } + + if (x < 0.0) { + x = -x; + } + + if (x < _FXbig) { // worth adding in exp(-x) + _FExp(&x, 1.0F, -1); + return y * (x + 0.25F / x); + } + switch (_FExp(&x, y, -1)) { // report over/underflow + case 0: + _Feraise(_FE_UNDERFLOW); + break; + case _INFCODE: + _Feraise(_FE_OVERFLOW); + } + return x; + } +} + _END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xfcosh.cpp b/stl/src/xfcosh.cpp deleted file mode 100644 index 5fb3ce51814..00000000000 --- a/stl/src/xfcosh.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include "xmath.hpp" - -_EXTERN_C_UNLESS_PURE - -_CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FCosh(float x, float y) noexcept { // compute y * cosh(x), |y| <= 1 - switch (_FDtest(&x)) { // test for special codes - case _NANCODE: - case _INFCODE: - return x; - case 0: - return y; - default: // finite - if (y == 0.0) { - return y; - } - - if (x < 0.0) { - x = -x; - } - - if (x < _FXbig) { // worth adding in exp(-x) - _FExp(&x, 1.0F, -1); - return y * (x + 0.25F / x); - } - switch (_FExp(&x, y, -1)) { // report over/underflow - case 0: - _Feraise(_FE_UNDERFLOW); - break; - case _INFCODE: - _Feraise(_FE_OVERFLOW); - } - return x; - } -} - -_END_EXTERN_C_UNLESS_PURE From ffcaac125d18f87912e48b13e01b34c169aed9cc Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 01:13:29 -0800 Subject: [PATCH 02/21] Fuse xfsinh.cpp into xsinh.cpp. --- stl/CMakeLists.txt | 1 - .../stl_base/stl.files.settings.targets | 1 - stl/src/xfsinh.cpp | 60 ------------------- stl/src/xsinh.cpp | 52 ++++++++++++++++ 4 files changed, 52 insertions(+), 62 deletions(-) delete mode 100644 stl/src/xfsinh.cpp diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index a088c1ffae3..0e0cfa3b215 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -289,7 +289,6 @@ set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/xfdtest.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xferaise.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfexp.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfsinh.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xgetwctype.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlgamma.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlocale.cpp diff --git a/stl/msbuild/stl_base/stl.files.settings.targets b/stl/msbuild/stl_base/stl.files.settings.targets index 4db62e56d46..f6d81af70f2 100644 --- a/stl/msbuild/stl_base/stl.files.settings.targets +++ b/stl/msbuild/stl_base/stl.files.settings.targets @@ -83,7 +83,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - diff --git a/stl/src/xfsinh.cpp b/stl/src/xfsinh.cpp deleted file mode 100644 index 4e551083f6e..00000000000 --- a/stl/src/xfsinh.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include "xmath.hpp" - -_EXTERN_C_UNLESS_PURE - -_CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float x, float y) noexcept { - // compute y * sinh(x), |y| <= 1 - - // coefficients - static constexpr float p[] = {0.00020400F, 0.00832983F, 0.16666737F, 0.99999998F}; - - short neg; - - switch (_FDtest(&x)) { // test for special codes - case _NANCODE: - return x; - case _INFCODE: - return y != 0.0F ? x : FSIGN(x) ? -y : y; - case 0: - return x * y; - default: // finite - if (y == 0.0F) { - return x < 0.0F ? -y : y; - } - - if (x < 0.0F) { - x = -x; - neg = 1; - } else { - neg = 0; - } - - constexpr float rteps = 0x1p-12f; - if (x < rteps) { - x *= y; // x tiny - } else if (x < 1.0F) { - float w = x * x; - - x += ((p[0] * w + p[1]) * w + p[2]) * w * x; - x *= y; - } else if (x < _FXbig) { // worth adding in exp(-x) - _FExp(&x, 1.0F, -1); - x = y * (x - 0.25F / x); - } else { - switch (_FExp(&x, y, -1)) { // report over/underflow - case 0: - _Feraise(_FE_UNDERFLOW); - break; - case _INFCODE: - _Feraise(_FE_OVERFLOW); - } - } - - return neg ? -x : x; - } -} - -_END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xsinh.cpp b/stl/src/xsinh.cpp index 1def63635b0..5e38691a044 100644 --- a/stl/src/xsinh.cpp +++ b/stl/src/xsinh.cpp @@ -77,4 +77,56 @@ _CRTIMP2_PURE long double __CLRCALL_PURE_OR_CDECL _LSinh(long double x, long dou return _Sinh(static_cast(x), static_cast(y)); } +_CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float x, float y) noexcept { + // compute y * sinh(x), |y| <= 1 + + // coefficients + static constexpr float p[] = {0.00020400F, 0.00832983F, 0.16666737F, 0.99999998F}; + + short neg; + + switch (_FDtest(&x)) { // test for special codes + case _NANCODE: + return x; + case _INFCODE: + return y != 0.0F ? x : FSIGN(x) ? -y : y; + case 0: + return x * y; + default: // finite + if (y == 0.0F) { + return x < 0.0F ? -y : y; + } + + if (x < 0.0F) { + x = -x; + neg = 1; + } else { + neg = 0; + } + + constexpr float rteps = 0x1p-12f; + if (x < rteps) { + x *= y; // x tiny + } else if (x < 1.0F) { + float w = x * x; + + x += ((p[0] * w + p[1]) * w + p[2]) * w * x; + x *= y; + } else if (x < _FXbig) { // worth adding in exp(-x) + _FExp(&x, 1.0F, -1); + x = y * (x - 0.25F / x); + } else { + switch (_FExp(&x, y, -1)) { // report over/underflow + case 0: + _Feraise(_FE_UNDERFLOW); + break; + case _INFCODE: + _Feraise(_FE_OVERFLOW); + } + } + + return neg ? -x : x; + } +} + _END_EXTERN_C_UNLESS_PURE From fdb8401959af2d2ee30109258d4b3310739323a4 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 02:36:02 -0800 Subject: [PATCH 03/21] Fuse xfdtest.cpp into xdtest.cpp. --- stl/CMakeLists.txt | 1 - .../stl_base/stl.files.settings.targets | 1 - stl/src/xdtest.cpp | 12 ++++++++++ stl/src/xfdtest.cpp | 22 ------------------- 4 files changed, 12 insertions(+), 24 deletions(-) delete mode 100644 stl/src/xfdtest.cpp diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 0e0cfa3b215..b9899b052c3 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -286,7 +286,6 @@ set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/xexp.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfdnorm.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfdscale.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfdtest.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xferaise.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfexp.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xgetwctype.cpp diff --git a/stl/msbuild/stl_base/stl.files.settings.targets b/stl/msbuild/stl_base/stl.files.settings.targets index f6d81af70f2..27e3bf8e663 100644 --- a/stl/msbuild/stl_base/stl.files.settings.targets +++ b/stl/msbuild/stl_base/stl.files.settings.targets @@ -80,7 +80,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - diff --git a/stl/src/xdtest.cpp b/stl/src/xdtest.cpp index caaa62f0851..d7220345380 100644 --- a/stl/src/xdtest.cpp +++ b/stl/src/xdtest.cpp @@ -24,4 +24,16 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LDtest(long double* px) noexcept { return _Dtest(reinterpret_cast(px)); } +_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FDtest(float* px) noexcept { // categorize *px + const auto ps = reinterpret_cast<_Fval*>(px); + + if ((ps->_Sh[_F0] & _FMASK) == _FMAX << _FOFF) { + return (ps->_Sh[_F0] & _FFRAC) != 0 || ps->_Sh[_F1] != 0 ? _NANCODE : _INFCODE; + } else if ((ps->_Sh[_F0] & ~_FSIGN) != 0 || ps->_Sh[_F1] != 0) { + return (ps->_Sh[_F0] & _FMASK) == 0 ? _DENORM : _FINITE; + } else { + return 0; + } +} + _END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xfdtest.cpp b/stl/src/xfdtest.cpp deleted file mode 100644 index 04556bca328..00000000000 --- a/stl/src/xfdtest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -// _FDtest function -- IEEE 754 version - -#include "xmath.hpp" - -_EXTERN_C_UNLESS_PURE - -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FDtest(float* px) noexcept { // categorize *px - const auto ps = reinterpret_cast<_Fval*>(px); - - if ((ps->_Sh[_F0] & _FMASK) == _FMAX << _FOFF) { - return (ps->_Sh[_F0] & _FFRAC) != 0 || ps->_Sh[_F1] != 0 ? _NANCODE : _INFCODE; - } else if ((ps->_Sh[_F0] & ~_FSIGN) != 0 || ps->_Sh[_F1] != 0) { - return (ps->_Sh[_F0] & _FMASK) == 0 ? _DENORM : _FINITE; - } else { - return 0; - } -} - -_END_EXTERN_C_UNLESS_PURE From e0ca27bc13b651a4152be4c82fd6f9664bc4e135 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 11 Dec 2025 02:47:29 -0800 Subject: [PATCH 04/21] Fuse xfexp.cpp into xexp.cpp. --- stl/CMakeLists.txt | 1 - .../stl_base/stl.files.settings.targets | 1 - stl/src/xexp.cpp | 55 ++++++++++++++++ stl/src/xfexp.cpp | 63 ------------------- 4 files changed, 55 insertions(+), 65 deletions(-) delete mode 100644 stl/src/xfexp.cpp diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index b9899b052c3..c51cc2098dd 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -287,7 +287,6 @@ set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/xfdnorm.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfdscale.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xferaise.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfexp.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xgetwctype.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlgamma.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlocale.cpp diff --git a/stl/msbuild/stl_base/stl.files.settings.targets b/stl/msbuild/stl_base/stl.files.settings.targets index 27e3bf8e663..72ddbb34f02 100644 --- a/stl/msbuild/stl_base/stl.files.settings.targets +++ b/stl/msbuild/stl_base/stl.files.settings.targets @@ -81,7 +81,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index 6b5a45ca5cb..4dd510b9eb7 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -160,4 +160,59 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LExp(long double* px, long double y return _Exp(reinterpret_cast(px), static_cast(y), eoff); } +_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FExp(float* px, float y, short eoff) noexcept { + // compute y * e^(*px), (*px) finite, |y| not huge + + static constexpr float p[] = {1.0F, 60.09114349F}; + static constexpr float q[] = {12.01517514F, 120.18228722F}; + constexpr float c1 = (22713.0F / 32768.0F); + constexpr float c2 = 1.4286068203094172321214581765680755e-6F; + constexpr float hugexp = static_cast(_FMAX * 900L / 1000); + constexpr float invln2 = 1.4426950408889634073599246810018921F; + + if (y == 0.0F) { // zero + *px = y; + return 0; + } else if (*px < -hugexp) { // certain underflow + *px = _Xfe_underflow(y); + return 0; + } else if (hugexp < *px) { // certain overflow + *px = _Xfe_overflow(y); + return _INFCODE; + } else { // xexp won't overflow + float g = *px * invln2; + short xexp = static_cast(g + (g < 0.0F ? -0.5F : +0.5F)); + + g = xexp; + g = static_cast((*px - g * c1) - g * c2); + + constexpr float eps = 0x1p-25f; + if (-eps < g && g < eps) { + *px = y; + } else { // g * g worth computing + const float z = g * g; + const float w = q[0] * z + q[1]; + + g *= z + p[1]; + *px = (w + g) / (w - g) * 2.0F * y; + --xexp; + } + + const short result_code = _FDscale(px, static_cast(xexp) + eoff); + + switch (result_code) { + case 0: + *px = _Xfe_underflow(y); + break; + case _INFCODE: + *px = _Xfe_overflow(y); + break; + default: + break; + } + + return result_code; + } +} + _END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xfexp.cpp b/stl/src/xfexp.cpp deleted file mode 100644 index cfe5b7776d5..00000000000 --- a/stl/src/xfexp.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include "xmath.hpp" - -_EXTERN_C_UNLESS_PURE - -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FExp(float* px, float y, short eoff) noexcept { - // compute y * e^(*px), (*px) finite, |y| not huge - - static constexpr float p[] = {1.0F, 60.09114349F}; - static constexpr float q[] = {12.01517514F, 120.18228722F}; - constexpr float c1 = (22713.0F / 32768.0F); - constexpr float c2 = 1.4286068203094172321214581765680755e-6F; - constexpr float hugexp = static_cast(_FMAX * 900L / 1000); - constexpr float invln2 = 1.4426950408889634073599246810018921F; - - if (y == 0.0F) { // zero - *px = y; - return 0; - } else if (*px < -hugexp) { // certain underflow - *px = _Xfe_underflow(y); - return 0; - } else if (hugexp < *px) { // certain overflow - *px = _Xfe_overflow(y); - return _INFCODE; - } else { // xexp won't overflow - float g = *px * invln2; - short xexp = static_cast(g + (g < 0.0F ? -0.5F : +0.5F)); - - g = xexp; - g = static_cast((*px - g * c1) - g * c2); - - constexpr float eps = 0x1p-25f; - if (-eps < g && g < eps) { - *px = y; - } else { // g * g worth computing - const float z = g * g; - const float w = q[0] * z + q[1]; - - g *= z + p[1]; - *px = (w + g) / (w - g) * 2.0F * y; - --xexp; - } - - const short result_code = _FDscale(px, static_cast(xexp) + eoff); - - switch (result_code) { - case 0: - *px = _Xfe_underflow(y); - break; - case _INFCODE: - *px = _Xfe_overflow(y); - break; - default: - break; - } - - return result_code; - } -} - -_END_EXTERN_C_UNLESS_PURE From cbf7497811ff62c00aa0a4abea3edce869ca5ebf Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 02:46:01 -0800 Subject: [PATCH 05/21] Fuse xfdscale.cpp into xexp.cpp. `_FDscale()` wasn't dllexported, so we can move it into an unnamed namespace. --- stl/CMakeLists.txt | 1 - .../stl_base/stl.files.settings.targets | 1 - stl/src/xexp.cpp | 57 ++++++++++++++++ stl/src/xfdscale.cpp | 67 ------------------- stl/src/xmath.hpp | 1 - 5 files changed, 57 insertions(+), 70 deletions(-) delete mode 100644 stl/src/xfdscale.cpp diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index c51cc2098dd..22ec61f1b4f 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -285,7 +285,6 @@ set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/xdtest.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xexp.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xfdnorm.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfdscale.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xferaise.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xgetwctype.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlgamma.cpp diff --git a/stl/msbuild/stl_base/stl.files.settings.targets b/stl/msbuild/stl_base/stl.files.settings.targets index 72ddbb34f02..76492989005 100644 --- a/stl/msbuild/stl_base/stl.files.settings.targets +++ b/stl/msbuild/stl_base/stl.files.settings.targets @@ -79,7 +79,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index 4dd510b9eb7..1e1d849d7d9 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -96,6 +96,63 @@ namespace { } } } + + short _FDscale(float* px, long lexp) noexcept { // scale *px by 2^xexp with checking + const auto ps = reinterpret_cast<_Fval*>(px); + short xchar = static_cast((ps->_Sh[_F0] & _FMASK) >> _FOFF); + + if (xchar == _FMAX) { + return (ps->_Sh[_F0] & _FFRAC) != 0 || ps->_Sh[_F1] != 0 ? _NANCODE : _INFCODE; + } else if (xchar == 0 && 0 < (xchar = _FDnorm(ps))) { + return 0; + } + + if (0 < lexp && _FMAX - xchar <= lexp) { // overflow, return +/-INF + constexpr float inf = _STD numeric_limits::infinity(); + + *px = ps->_Sh[_F0] & _FSIGN ? -inf : inf; + return _INFCODE; + } else if (-xchar < lexp) { // finite result, repack + ps->_Sh[_F0] = static_cast(ps->_Sh[_F0] & ~_FMASK | (lexp + xchar) << _FOFF); + return _FINITE; + } else { // denormalized, scale + unsigned short sign = static_cast(ps->_Sh[_F0] & _FSIGN); + + ps->_Sh[_F0] = static_cast(1 << _FOFF | ps->_Sh[_F0] & _FFRAC); + lexp += xchar - 1; + if (lexp < -(16 + 1 + _FOFF) || 0 <= lexp) { // underflow, return +/-0 + ps->_Sh[_F0] = sign; + ps->_Sh[_F1] = 0; + return 0; + } else { // nonzero, align fraction + short xexp = static_cast(lexp); + unsigned short psx = 0; + + if (xexp <= -16) { // scale by words + psx = ps->_Sh[_F1]; + ps->_Sh[_F1] = ps->_Sh[_F0]; + ps->_Sh[_F0] = 0; + xexp += 16; + } + + if (xexp != 0) { // scale by bits + xexp = -xexp; + psx = (ps->_Sh[_F1] << (16 - xexp)) | (psx != 0 ? 1 : 0); + ps->_Sh[_F1] = static_cast(ps->_Sh[_F1] >> xexp | ps->_Sh[_F0] << (16 - xexp)); + ps->_Sh[_F0] >>= xexp; + } + + ps->_Sh[_F0] |= sign; + if ((0x8000 < psx || 0x8000 == psx && (ps->_Sh[_F1] & 0x0001) != 0) && (++ps->_Sh[_F1] & 0xffff) == 0) { + ++ps->_Sh[_F0]; // round up + } else if (ps->_Sh[_F0] == sign && ps->_Sh[_F1] == 0) { + return 0; + } + + return _FINITE; + } + } + } } // unnamed namespace _EXTERN_C_UNLESS_PURE diff --git a/stl/src/xfdscale.cpp b/stl/src/xfdscale.cpp deleted file mode 100644 index cb5e27c2ef5..00000000000 --- a/stl/src/xfdscale.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -// _FDscale function -- IEEE 754 version - -#include "xmath.hpp" - -_EXTERN_C_UNLESS_PURE - -short _FDscale(float* px, long lexp) noexcept { // scale *px by 2^xexp with checking - const auto ps = reinterpret_cast<_Fval*>(px); - short xchar = static_cast((ps->_Sh[_F0] & _FMASK) >> _FOFF); - - if (xchar == _FMAX) { - return (ps->_Sh[_F0] & _FFRAC) != 0 || ps->_Sh[_F1] != 0 ? _NANCODE : _INFCODE; - } else if (xchar == 0 && 0 < (xchar = _FDnorm(ps))) { - return 0; - } - - if (0 < lexp && _FMAX - xchar <= lexp) { // overflow, return +/-INF - constexpr float inf = _STD numeric_limits::infinity(); - - *px = ps->_Sh[_F0] & _FSIGN ? -inf : inf; - return _INFCODE; - } else if (-xchar < lexp) { // finite result, repack - ps->_Sh[_F0] = static_cast(ps->_Sh[_F0] & ~_FMASK | (lexp + xchar) << _FOFF); - return _FINITE; - } else { // denormalized, scale - unsigned short sign = static_cast(ps->_Sh[_F0] & _FSIGN); - - ps->_Sh[_F0] = static_cast(1 << _FOFF | ps->_Sh[_F0] & _FFRAC); - lexp += xchar - 1; - if (lexp < -(16 + 1 + _FOFF) || 0 <= lexp) { // underflow, return +/-0 - ps->_Sh[_F0] = sign; - ps->_Sh[_F1] = 0; - return 0; - } else { // nonzero, align fraction - short xexp = static_cast(lexp); - unsigned short psx = 0; - - if (xexp <= -16) { // scale by words - psx = ps->_Sh[_F1]; - ps->_Sh[_F1] = ps->_Sh[_F0]; - ps->_Sh[_F0] = 0; - xexp += 16; - } - - if (xexp != 0) { // scale by bits - xexp = -xexp; - psx = (ps->_Sh[_F1] << (16 - xexp)) | (psx != 0 ? 1 : 0); - ps->_Sh[_F1] = static_cast(ps->_Sh[_F1] >> xexp | ps->_Sh[_F0] << (16 - xexp)); - ps->_Sh[_F0] >>= xexp; - } - - ps->_Sh[_F0] |= sign; - if ((0x8000 < psx || 0x8000 == psx && (ps->_Sh[_F1] & 0x0001) != 0) && (++ps->_Sh[_F1] & 0xffff) == 0) { - ++ps->_Sh[_F0]; // round up - } else if (ps->_Sh[_F0] == sign && ps->_Sh[_F1] == 0) { - return 0; - } - - return _FINITE; - } - } -} - -_END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index a884f145f89..609a744d513 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -52,7 +52,6 @@ union _Fval { // pun floating type as integer array }; short _FDnorm(_Fval*) noexcept; -short _FDscale(float*, long) noexcept; extern const float _FXbig; From 05e05ca60aa1adb7fed3251f953564fda788556e Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 02:49:57 -0800 Subject: [PATCH 06/21] Fuse xfdnorm.cpp into xexp.cpp. `_FDnorm()` wasn't dllexported, so we can move it into an unnamed namespace. --- stl/CMakeLists.txt | 1 - .../stl_base/stl.files.settings.targets | 1 - stl/src/xexp.cpp | 25 +++++++++++++ stl/src/xfdnorm.cpp | 35 ------------------- stl/src/xmath.hpp | 2 -- 5 files changed, 25 insertions(+), 39 deletions(-) delete mode 100644 stl/src/xfdnorm.cpp diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 22ec61f1b4f..44a3277e107 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -284,7 +284,6 @@ set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/xdateord.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xdtest.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xexp.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfdnorm.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xferaise.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xgetwctype.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlgamma.cpp diff --git a/stl/msbuild/stl_base/stl.files.settings.targets b/stl/msbuild/stl_base/stl.files.settings.targets index 76492989005..9cf3a843f67 100644 --- a/stl/msbuild/stl_base/stl.files.settings.targets +++ b/stl/msbuild/stl_base/stl.files.settings.targets @@ -78,7 +78,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index 1e1d849d7d9..e2f3b1885a2 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -97,6 +97,31 @@ namespace { } } + short _FDnorm(_Fval* ps) noexcept { // normalize float fraction + short xchar = 1; + unsigned short sign = static_cast(ps->_Sh[_F0] & _FSIGN); + + if ((ps->_Sh[_F0] &= _FFRAC) != 0 || ps->_Sh[_F1]) { // nonzero, scale + if (ps->_Sh[_F0] == 0) { + ps->_Sh[_F0] = ps->_Sh[_F1]; + ps->_Sh[_F1] = 0; + xchar -= 16; + } + + for (; ps->_Sh[_F0] < 1 << _FOFF; --xchar) { // shift left by 1 + ps->_Sh[_F0] = static_cast(ps->_Sh[_F0] << 1 | ps->_Sh[_F1] >> 15); + ps->_Sh[_F1] <<= 1; + } + for (; 1 << (_FOFF + 1) <= ps->_Sh[_F0]; ++xchar) { // shift right by 1 + ps->_Sh[_F1] = static_cast(ps->_Sh[_F1] >> 1 | ps->_Sh[_F0] << 15); + ps->_Sh[_F0] >>= 1; + } + ps->_Sh[_F0] &= _FFRAC; + } + ps->_Sh[_F0] |= sign; + return xchar; + } + short _FDscale(float* px, long lexp) noexcept { // scale *px by 2^xexp with checking const auto ps = reinterpret_cast<_Fval*>(px); short xchar = static_cast((ps->_Sh[_F0] & _FMASK) >> _FOFF); diff --git a/stl/src/xfdnorm.cpp b/stl/src/xfdnorm.cpp deleted file mode 100644 index 4ac5e671a0f..00000000000 --- a/stl/src/xfdnorm.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -// _FDnorm function -- IEEE 754 version - -#include "xmath.hpp" - -_EXTERN_C_UNLESS_PURE - -short _FDnorm(_Fval* ps) noexcept { // normalize float fraction - short xchar = 1; - unsigned short sign = static_cast(ps->_Sh[_F0] & _FSIGN); - - if ((ps->_Sh[_F0] &= _FFRAC) != 0 || ps->_Sh[_F1]) { // nonzero, scale - if (ps->_Sh[_F0] == 0) { - ps->_Sh[_F0] = ps->_Sh[_F1]; - ps->_Sh[_F1] = 0; - xchar -= 16; - } - - for (; ps->_Sh[_F0] < 1 << _FOFF; --xchar) { // shift left by 1 - ps->_Sh[_F0] = static_cast(ps->_Sh[_F0] << 1 | ps->_Sh[_F1] >> 15); - ps->_Sh[_F1] <<= 1; - } - for (; 1 << (_FOFF + 1) <= ps->_Sh[_F0]; ++xchar) { // shift right by 1 - ps->_Sh[_F1] = static_cast(ps->_Sh[_F1] >> 1 | ps->_Sh[_F0] << 15); - ps->_Sh[_F0] >>= 1; - } - ps->_Sh[_F0] &= _FFRAC; - } - ps->_Sh[_F0] |= sign; - return xchar; -} - -_END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index 609a744d513..78088c02b07 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -51,8 +51,6 @@ union _Fval { // pun floating type as integer array float _Val; }; -short _FDnorm(_Fval*) noexcept; - extern const float _FXbig; _END_EXTERN_C_UNLESS_PURE From 24d50a0b2a27925a0455545e881467d2f87cb06b Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 03:00:49 -0800 Subject: [PATCH 07/21] Replace `_Feraise()` with `errno = ERANGE;`. It had no other effect. I'm adding `// underflow` versus `// overflow` comments to preserve clarity. `_Feraise()` wasn't dllexported. It was marked `__CLRCALL_PURE_OR_CDECL` but not `_CRTIMP2_PURE`. Remove now-unused macros. --- stl/CMakeLists.txt | 1 - stl/msbuild/stl_base/stl.files.settings.targets | 1 - stl/src/xcosh.cpp | 8 ++++---- stl/src/xferaise.cpp | 16 ---------------- stl/src/xmath.hpp | 8 -------- stl/src/xsinh.cpp | 8 ++++---- 6 files changed, 8 insertions(+), 34 deletions(-) delete mode 100644 stl/src/xferaise.cpp diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 44a3277e107..f15d7ecbbfb 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -284,7 +284,6 @@ set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/xdateord.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xdtest.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xexp.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xferaise.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xgetwctype.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlgamma.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlocale.cpp diff --git a/stl/msbuild/stl_base/stl.files.settings.targets b/stl/msbuild/stl_base/stl.files.settings.targets index 9cf3a843f67..f4a9a133986 100644 --- a/stl/msbuild/stl_base/stl.files.settings.targets +++ b/stl/msbuild/stl_base/stl.files.settings.targets @@ -78,7 +78,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - diff --git a/stl/src/xcosh.cpp b/stl/src/xcosh.cpp index 01c70ca4eaf..f22bc105d9b 100644 --- a/stl/src/xcosh.cpp +++ b/stl/src/xcosh.cpp @@ -27,10 +27,10 @@ _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Cosh(double x, double y) noexcept } switch (_Exp(&x, y, -1)) { // report over/underflow case 0: - _Feraise(_FE_UNDERFLOW); + errno = ERANGE; // underflow break; case _INFCODE: - _Feraise(_FE_OVERFLOW); + errno = ERANGE; // overflow } return x; } @@ -62,10 +62,10 @@ _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FCosh(float x, float y) noexcept { } switch (_FExp(&x, y, -1)) { // report over/underflow case 0: - _Feraise(_FE_UNDERFLOW); + errno = ERANGE; // underflow break; case _INFCODE: - _Feraise(_FE_OVERFLOW); + errno = ERANGE; // overflow } return x; } diff --git a/stl/src/xferaise.cpp b/stl/src/xferaise.cpp deleted file mode 100644 index b973fc23824..00000000000 --- a/stl/src/xferaise.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include "xmath.hpp" - -_EXTERN_C_UNLESS_PURE - -void __CLRCALL_PURE_OR_CDECL _Feraise(int except) noexcept { // report floating-point exception - if ((except & (_FE_DIVBYZERO | _FE_INVALID)) != 0) { - errno = EDOM; - } else if ((except & (_FE_UNDERFLOW | _FE_OVERFLOW)) != 0) { - errno = ERANGE; - } -} - -_END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index 78088c02b07..086317f4d14 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -8,12 +8,6 @@ #include #include -// macros for _Feraise argument -#define _FE_DIVBYZERO 0x04 -#define _FE_INVALID 0x01 -#define _FE_OVERFLOW 0x08 -#define _FE_UNDERFLOW 0x10 - // float properties #define _D0 3 // little-endian, small long doubles #define _D1 2 @@ -32,8 +26,6 @@ _EXTERN_C_UNLESS_PURE -void __CLRCALL_PURE_OR_CDECL _Feraise(int) noexcept; - _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Dtest(double*) noexcept; _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FDtest(float*) noexcept; diff --git a/stl/src/xsinh.cpp b/stl/src/xsinh.cpp index 5e38691a044..d1cf5b954ef 100644 --- a/stl/src/xsinh.cpp +++ b/stl/src/xsinh.cpp @@ -62,10 +62,10 @@ _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Sinh(double x, double y) noexcept } else { switch (_Exp(&x, y, -1)) { // report over/underflow case 0: - _Feraise(_FE_UNDERFLOW); + errno = ERANGE; // underflow break; case _INFCODE: - _Feraise(_FE_OVERFLOW); + errno = ERANGE; // overflow } } @@ -118,10 +118,10 @@ _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float x, float y) noexcept { } else { switch (_FExp(&x, y, -1)) { // report over/underflow case 0: - _Feraise(_FE_UNDERFLOW); + errno = ERANGE; // underflow break; case _INFCODE: - _Feraise(_FE_OVERFLOW); + errno = ERANGE; // overflow } } From 0cf8a8b4d1973bfd67a99471b5b21b2e91ae68f6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 03:08:57 -0800 Subject: [PATCH 08/21] Fuse underflow/overflow cases, avoid missing `break;`. --- stl/src/xcosh.cpp | 18 ++++++++---------- stl/src/xsinh.cpp | 18 ++++++++---------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/stl/src/xcosh.cpp b/stl/src/xcosh.cpp index f22bc105d9b..9d43fe3d111 100644 --- a/stl/src/xcosh.cpp +++ b/stl/src/xcosh.cpp @@ -25,12 +25,11 @@ _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Cosh(double x, double y) noexcept _Exp(&x, 1.0, -1); return y * (x + 0.25 / x); } - switch (_Exp(&x, y, -1)) { // report over/underflow - case 0: - errno = ERANGE; // underflow + switch (_Exp(&x, y, -1)) { + case 0: // report underflow + case _INFCODE: // report overflow + errno = ERANGE; break; - case _INFCODE: - errno = ERANGE; // overflow } return x; } @@ -60,12 +59,11 @@ _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FCosh(float x, float y) noexcept { _FExp(&x, 1.0F, -1); return y * (x + 0.25F / x); } - switch (_FExp(&x, y, -1)) { // report over/underflow - case 0: - errno = ERANGE; // underflow + switch (_FExp(&x, y, -1)) { + case 0: // report underflow + case _INFCODE: // report overflow + errno = ERANGE; break; - case _INFCODE: - errno = ERANGE; // overflow } return x; } diff --git a/stl/src/xsinh.cpp b/stl/src/xsinh.cpp index d1cf5b954ef..3b8b44d1d6b 100644 --- a/stl/src/xsinh.cpp +++ b/stl/src/xsinh.cpp @@ -60,12 +60,11 @@ _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Sinh(double x, double y) noexcept _Exp(&x, 1.0, -1); x = y * (x - 0.25 / x); } else { - switch (_Exp(&x, y, -1)) { // report over/underflow - case 0: - errno = ERANGE; // underflow + switch (_Exp(&x, y, -1)) { + case 0: // report underflow + case _INFCODE: // report overflow + errno = ERANGE; break; - case _INFCODE: - errno = ERANGE; // overflow } } @@ -116,12 +115,11 @@ _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float x, float y) noexcept { _FExp(&x, 1.0F, -1); x = y * (x - 0.25F / x); } else { - switch (_FExp(&x, y, -1)) { // report over/underflow - case 0: - errno = ERANGE; // underflow + switch (_FExp(&x, y, -1)) { + case 0: // report underflow + case _INFCODE: // report overflow + errno = ERANGE; break; - case _INFCODE: - errno = ERANGE; // overflow } } From 1485cc920022a8ee5caff865af11cf8172d71b76 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 03:38:26 -0800 Subject: [PATCH 09/21] Preserve `_Dtest()` for bincompat, replaced with `fpclassify()`. They return the same values: C:\Temp>type meow.cpp #include #include #include using namespace std; static_assert(FP_SUBNORMAL == -2); // _DENORM static_assert(FP_NORMAL == -1); // _FINITE static_assert(FP_ZERO == 0); static_assert(FP_INFINITE == 1); // _INFCODE static_assert(FP_NAN == 2); // _NANCODE extern "C" _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Dtest(double*) noexcept; void classify(double dbl) { const short stl = _Dtest(&dbl); const int crt = fpclassify(dbl); println("dbl: {:6}; stl: {:2}; crt: {:2}; Equal: {}", dbl, stl, crt, stl == crt); } int main() { classify(numeric_limits::denorm_min()); classify(3.14); classify(0.0); classify(-0.0); classify(numeric_limits::infinity()); classify(numeric_limits::quiet_NaN()); } C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /MTd /Od meow.cpp meow.cpp C:\Temp>meow dbl: 5e-324; stl: -2; crt: -2; Equal: true dbl: 3.14; stl: -1; crt: -1; Equal: true dbl: 0; stl: 0; crt: 0; Equal: true dbl: -0; stl: 0; crt: 0; Equal: true dbl: inf; stl: 1; crt: 1; Equal: true dbl: nan; stl: 2; crt: 2; Equal: true --- stl/src/xcosh.cpp | 4 ++-- stl/src/xdtest.cpp | 32 ++++++++------------------------ stl/src/xmath.hpp | 3 --- stl/src/xsinh.cpp | 4 ++-- 4 files changed, 12 insertions(+), 31 deletions(-) diff --git a/stl/src/xcosh.cpp b/stl/src/xcosh.cpp index 9d43fe3d111..0cc4d3a6893 100644 --- a/stl/src/xcosh.cpp +++ b/stl/src/xcosh.cpp @@ -6,7 +6,7 @@ _EXTERN_C_UNLESS_PURE _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Cosh(double x, double y) noexcept { // compute y * cosh(x), |y| <= 1 - switch (_Dtest(&x)) { // test for special codes + switch (_STD fpclassify(x)) { // test for special codes case _NANCODE: case _INFCODE: return x; @@ -40,7 +40,7 @@ _CRTIMP2_PURE long double __CLRCALL_PURE_OR_CDECL _LCosh(long double x, long dou } _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FCosh(float x, float y) noexcept { // compute y * cosh(x), |y| <= 1 - switch (_FDtest(&x)) { // test for special codes + switch (_STD fpclassify(x)) { // test for special codes case _NANCODE: case _INFCODE: return x; diff --git a/stl/src/xdtest.cpp b/stl/src/xdtest.cpp index d7220345380..a9253d53d2f 100644 --- a/stl/src/xdtest.cpp +++ b/stl/src/xdtest.cpp @@ -1,39 +1,23 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// _Dtest function -- IEEE 754 version - #include "xmath.hpp" _EXTERN_C_UNLESS_PURE -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Dtest(double* px) noexcept { // categorize *px - const auto ps = reinterpret_cast<_Dval*>(px); - - if ((ps->_Sh[_D0] & _DMASK) == _DMAX << _DOFF) { - return (ps->_Sh[_D0] & _DFRAC) != 0 || ps->_Sh[_D1] != 0 || ps->_Sh[_D2] != 0 || ps->_Sh[_D3] != 0 ? _NANCODE - : _INFCODE; - } else if ((ps->_Sh[_D0] & ~_DSIGN) != 0 || ps->_Sh[_D1] != 0 || ps->_Sh[_D2] != 0 || ps->_Sh[_D3] != 0) { - return (ps->_Sh[_D0] & _DMASK) == 0 ? _DENORM : _FINITE; - } else { - return 0; - } +// TRANSITION, ABI: preserved for binary compatibility +_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Dtest(double* px) noexcept { + return static_cast(_STD fpclassify(*px)); } -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LDtest(long double* px) noexcept { // categorize *px -- 64-bit +// TRANSITION, ABI: preserved for binary compatibility +_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LDtest(long double* px) noexcept { return _Dtest(reinterpret_cast(px)); } -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FDtest(float* px) noexcept { // categorize *px - const auto ps = reinterpret_cast<_Fval*>(px); - - if ((ps->_Sh[_F0] & _FMASK) == _FMAX << _FOFF) { - return (ps->_Sh[_F0] & _FFRAC) != 0 || ps->_Sh[_F1] != 0 ? _NANCODE : _INFCODE; - } else if ((ps->_Sh[_F0] & ~_FSIGN) != 0 || ps->_Sh[_F1] != 0) { - return (ps->_Sh[_F0] & _FMASK) == 0 ? _DENORM : _FINITE; - } else { - return 0; - } +// TRANSITION, ABI: preserved for binary compatibility +_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FDtest(float* px) noexcept { + return static_cast(_STD fpclassify(*px)); } _END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index 086317f4d14..bce4e5d89b0 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -26,9 +26,6 @@ _EXTERN_C_UNLESS_PURE -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Dtest(double*) noexcept; -_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FDtest(float*) noexcept; - // double declarations union _Dval { // pun floating type as integer array unsigned short _Sh[8]; diff --git a/stl/src/xsinh.cpp b/stl/src/xsinh.cpp index 3b8b44d1d6b..e4227d229f1 100644 --- a/stl/src/xsinh.cpp +++ b/stl/src/xsinh.cpp @@ -29,7 +29,7 @@ _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Sinh(double x, double y) noexcept short neg; - switch (_Dtest(&x)) { // test for special codes + switch (_STD fpclassify(x)) { // test for special codes case _NANCODE: return x; case _INFCODE: @@ -84,7 +84,7 @@ _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float x, float y) noexcept { short neg; - switch (_FDtest(&x)) { // test for special codes + switch (_STD fpclassify(x)) { // test for special codes case _NANCODE: return x; case _INFCODE: From ec5d314d1381dfc8d777a7ad6f6aa3f209974020 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 03:39:06 -0800 Subject: [PATCH 10/21] `_FINITE` => `FP_NORMAL` --- stl/src/xexp.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index e2f3b1885a2..df6f0d203b2 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -52,7 +52,7 @@ namespace { return _INFCODE; } else if (-xchar < lexp) { // finite result, repack ps->_Sh[_D0] = static_cast(ps->_Sh[_D0] & ~_DMASK | (lexp + xchar) << _DOFF); - return _FINITE; + return FP_NORMAL; } else { // denormalized, scale unsigned short sign = static_cast(ps->_Sh[_D0] & _DSIGN); @@ -92,7 +92,7 @@ namespace { return 0; } - return _FINITE; + return FP_NORMAL; } } } @@ -139,7 +139,7 @@ namespace { return _INFCODE; } else if (-xchar < lexp) { // finite result, repack ps->_Sh[_F0] = static_cast(ps->_Sh[_F0] & ~_FMASK | (lexp + xchar) << _FOFF); - return _FINITE; + return FP_NORMAL; } else { // denormalized, scale unsigned short sign = static_cast(ps->_Sh[_F0] & _FSIGN); @@ -174,7 +174,7 @@ namespace { return 0; } - return _FINITE; + return FP_NORMAL; } } } From 067bf92fdd917e72b4f3feda38e3691f497efa32 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 03:40:33 -0800 Subject: [PATCH 11/21] `_INFCODE` => `FP_INFINITE` --- stl/inc/complex | 2 +- stl/src/xcosh.cpp | 8 ++++---- stl/src/xexp.cpp | 16 ++++++++-------- stl/src/xsinh.cpp | 8 ++++---- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index acd727f40c6..8017946e92c 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -547,7 +547,7 @@ public: static bool _Isinf(_Ty _Left) noexcept { // test for infinity #if defined(__LDBL_DIG__) && __LDBL_DIG__ == 18 - return _CSTD _LDtest(&_Left) == _INFCODE; + return _CSTD _LDtest(&_Left) == FP_INFINITE; #else // ^^^ 80-bit long double (not supported by MSVC in general, see GH-1316) / 64-bit long double vvv const auto _Uint = _Bit_cast(_Left); return (_Uint & 0x7fffffffffffffffU) == 0x7ff0000000000000U; diff --git a/stl/src/xcosh.cpp b/stl/src/xcosh.cpp index 0cc4d3a6893..153651a3ec7 100644 --- a/stl/src/xcosh.cpp +++ b/stl/src/xcosh.cpp @@ -8,7 +8,7 @@ _EXTERN_C_UNLESS_PURE _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Cosh(double x, double y) noexcept { // compute y * cosh(x), |y| <= 1 switch (_STD fpclassify(x)) { // test for special codes case _NANCODE: - case _INFCODE: + case FP_INFINITE: return x; case 0: return y; @@ -27,7 +27,7 @@ _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Cosh(double x, double y) noexcept } switch (_Exp(&x, y, -1)) { case 0: // report underflow - case _INFCODE: // report overflow + case FP_INFINITE: // report overflow errno = ERANGE; break; } @@ -42,7 +42,7 @@ _CRTIMP2_PURE long double __CLRCALL_PURE_OR_CDECL _LCosh(long double x, long dou _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FCosh(float x, float y) noexcept { // compute y * cosh(x), |y| <= 1 switch (_STD fpclassify(x)) { // test for special codes case _NANCODE: - case _INFCODE: + case FP_INFINITE: return x; case 0: return y; @@ -61,7 +61,7 @@ _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FCosh(float x, float y) noexcept { } switch (_FExp(&x, y, -1)) { case 0: // report underflow - case _INFCODE: // report overflow + case FP_INFINITE: // report overflow errno = ERANGE; break; } diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index df6f0d203b2..b556f84979e 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -40,7 +40,7 @@ namespace { if (xchar == _DMAX) { return (ps->_Sh[_D0] & _DFRAC) != 0 || ps->_Sh[_D1] != 0 || ps->_Sh[_D2] != 0 || ps->_Sh[_D3] != 0 ? _NANCODE - : _INFCODE; + : FP_INFINITE; } else if (xchar == 0 && 0 < (xchar = _Dnorm(ps))) { return 0; } @@ -49,7 +49,7 @@ namespace { constexpr double inf = _STD numeric_limits::infinity(); *px = ps->_Sh[_D0] & _DSIGN ? -inf : inf; - return _INFCODE; + return FP_INFINITE; } else if (-xchar < lexp) { // finite result, repack ps->_Sh[_D0] = static_cast(ps->_Sh[_D0] & ~_DMASK | (lexp + xchar) << _DOFF); return FP_NORMAL; @@ -127,7 +127,7 @@ namespace { short xchar = static_cast((ps->_Sh[_F0] & _FMASK) >> _FOFF); if (xchar == _FMAX) { - return (ps->_Sh[_F0] & _FFRAC) != 0 || ps->_Sh[_F1] != 0 ? _NANCODE : _INFCODE; + return (ps->_Sh[_F0] & _FFRAC) != 0 || ps->_Sh[_F1] != 0 ? _NANCODE : FP_INFINITE; } else if (xchar == 0 && 0 < (xchar = _FDnorm(ps))) { return 0; } @@ -136,7 +136,7 @@ namespace { constexpr float inf = _STD numeric_limits::infinity(); *px = ps->_Sh[_F0] & _FSIGN ? -inf : inf; - return _INFCODE; + return FP_INFINITE; } else if (-xchar < lexp) { // finite result, repack ps->_Sh[_F0] = static_cast(ps->_Sh[_F0] & ~_FMASK | (lexp + xchar) << _FOFF); return FP_NORMAL; @@ -201,7 +201,7 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Exp(double* px, double y, short eof return 0; } else if (hugexp < *px) { // certain overflow *px = _Xfe_overflow(y); - return _INFCODE; + return FP_INFINITE; } else { // xexp won't overflow double g = *px * invln2; short xexp = static_cast(g + (g < 0.0 ? -0.5 : +0.5)); @@ -227,7 +227,7 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Exp(double* px, double y, short eof case 0: *px = _Xfe_underflow(y); break; - case _INFCODE: + case FP_INFINITE: *px = _Xfe_overflow(y); break; default: @@ -260,7 +260,7 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FExp(float* px, float y, short eoff return 0; } else if (hugexp < *px) { // certain overflow *px = _Xfe_overflow(y); - return _INFCODE; + return FP_INFINITE; } else { // xexp won't overflow float g = *px * invln2; short xexp = static_cast(g + (g < 0.0F ? -0.5F : +0.5F)); @@ -286,7 +286,7 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FExp(float* px, float y, short eoff case 0: *px = _Xfe_underflow(y); break; - case _INFCODE: + case FP_INFINITE: *px = _Xfe_overflow(y); break; default: diff --git a/stl/src/xsinh.cpp b/stl/src/xsinh.cpp index e4227d229f1..97c643f145e 100644 --- a/stl/src/xsinh.cpp +++ b/stl/src/xsinh.cpp @@ -32,7 +32,7 @@ _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Sinh(double x, double y) noexcept switch (_STD fpclassify(x)) { // test for special codes case _NANCODE: return x; - case _INFCODE: + case FP_INFINITE: return y != 0.0 ? x : DSIGN(x) ? -y : y; case 0: return x * y; @@ -62,7 +62,7 @@ _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Sinh(double x, double y) noexcept } else { switch (_Exp(&x, y, -1)) { case 0: // report underflow - case _INFCODE: // report overflow + case FP_INFINITE: // report overflow errno = ERANGE; break; } @@ -87,7 +87,7 @@ _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float x, float y) noexcept { switch (_STD fpclassify(x)) { // test for special codes case _NANCODE: return x; - case _INFCODE: + case FP_INFINITE: return y != 0.0F ? x : FSIGN(x) ? -y : y; case 0: return x * y; @@ -117,7 +117,7 @@ _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float x, float y) noexcept { } else { switch (_FExp(&x, y, -1)) { case 0: // report underflow - case _INFCODE: // report overflow + case FP_INFINITE: // report overflow errno = ERANGE; break; } From a12cfcea919b5c4f736cac6af50dc8ac86538220 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 03:41:23 -0800 Subject: [PATCH 12/21] `_NANCODE` => `FP_NAN` --- stl/inc/complex | 2 +- stl/src/xcosh.cpp | 4 ++-- stl/src/xexp.cpp | 4 ++-- stl/src/xsinh.cpp | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index 8017946e92c..50ca9ae0aa9 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -556,7 +556,7 @@ public: static _CONSTEXPR20 bool _Isnan(_Ty _Left) noexcept { #if defined(__LDBL_DIG__) && __LDBL_DIG__ == 18 - return _CSTD _LDtest(&_Left) == _NANCODE; + return _CSTD _LDtest(&_Left) == FP_NAN; #else // ^^^ 80-bit long double (not supported by MSVC in general, see GH-1316) / 64-bit long double vvv const auto _Uint = _Bit_cast(_Left); return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; diff --git a/stl/src/xcosh.cpp b/stl/src/xcosh.cpp index 153651a3ec7..cc27aeda6ff 100644 --- a/stl/src/xcosh.cpp +++ b/stl/src/xcosh.cpp @@ -7,7 +7,7 @@ _EXTERN_C_UNLESS_PURE _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Cosh(double x, double y) noexcept { // compute y * cosh(x), |y| <= 1 switch (_STD fpclassify(x)) { // test for special codes - case _NANCODE: + case FP_NAN: case FP_INFINITE: return x; case 0: @@ -41,7 +41,7 @@ _CRTIMP2_PURE long double __CLRCALL_PURE_OR_CDECL _LCosh(long double x, long dou _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FCosh(float x, float y) noexcept { // compute y * cosh(x), |y| <= 1 switch (_STD fpclassify(x)) { // test for special codes - case _NANCODE: + case FP_NAN: case FP_INFINITE: return x; case 0: diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index b556f84979e..f64f8ada13f 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -39,7 +39,7 @@ namespace { if (xchar == _DMAX) { return (ps->_Sh[_D0] & _DFRAC) != 0 || ps->_Sh[_D1] != 0 || ps->_Sh[_D2] != 0 || ps->_Sh[_D3] != 0 - ? _NANCODE + ? FP_NAN : FP_INFINITE; } else if (xchar == 0 && 0 < (xchar = _Dnorm(ps))) { return 0; @@ -127,7 +127,7 @@ namespace { short xchar = static_cast((ps->_Sh[_F0] & _FMASK) >> _FOFF); if (xchar == _FMAX) { - return (ps->_Sh[_F0] & _FFRAC) != 0 || ps->_Sh[_F1] != 0 ? _NANCODE : FP_INFINITE; + return (ps->_Sh[_F0] & _FFRAC) != 0 || ps->_Sh[_F1] != 0 ? FP_NAN : FP_INFINITE; } else if (xchar == 0 && 0 < (xchar = _FDnorm(ps))) { return 0; } diff --git a/stl/src/xsinh.cpp b/stl/src/xsinh.cpp index 97c643f145e..6955b464856 100644 --- a/stl/src/xsinh.cpp +++ b/stl/src/xsinh.cpp @@ -30,7 +30,7 @@ _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Sinh(double x, double y) noexcept short neg; switch (_STD fpclassify(x)) { // test for special codes - case _NANCODE: + case FP_NAN: return x; case FP_INFINITE: return y != 0.0 ? x : DSIGN(x) ? -y : y; @@ -85,7 +85,7 @@ _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float x, float y) noexcept { short neg; switch (_STD fpclassify(x)) { // test for special codes - case _NANCODE: + case FP_NAN: return x; case FP_INFINITE: return y != 0.0F ? x : FSIGN(x) ? -y : y; From c548b9a3d674f99cebf5aa311195068d2bff5401 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 03:47:40 -0800 Subject: [PATCH 13/21] `0` => `FP_ZERO`, carefully. --- stl/src/xcosh.cpp | 8 ++++---- stl/src/xexp.cpp | 24 ++++++++++++------------ stl/src/xsinh.cpp | 8 ++++---- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/stl/src/xcosh.cpp b/stl/src/xcosh.cpp index cc27aeda6ff..616134166db 100644 --- a/stl/src/xcosh.cpp +++ b/stl/src/xcosh.cpp @@ -10,7 +10,7 @@ _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Cosh(double x, double y) noexcept case FP_NAN: case FP_INFINITE: return x; - case 0: + case FP_ZERO: return y; default: // finite if (y == 0.0) { @@ -26,7 +26,7 @@ _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Cosh(double x, double y) noexcept return y * (x + 0.25 / x); } switch (_Exp(&x, y, -1)) { - case 0: // report underflow + case FP_ZERO: // report underflow case FP_INFINITE: // report overflow errno = ERANGE; break; @@ -44,7 +44,7 @@ _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FCosh(float x, float y) noexcept { case FP_NAN: case FP_INFINITE: return x; - case 0: + case FP_ZERO: return y; default: // finite if (y == 0.0) { @@ -60,7 +60,7 @@ _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FCosh(float x, float y) noexcept { return y * (x + 0.25F / x); } switch (_FExp(&x, y, -1)) { - case 0: // report underflow + case FP_ZERO: // report underflow case FP_INFINITE: // report overflow errno = ERANGE; break; diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index f64f8ada13f..308c6e4b0d1 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -42,7 +42,7 @@ namespace { ? FP_NAN : FP_INFINITE; } else if (xchar == 0 && 0 < (xchar = _Dnorm(ps))) { - return 0; + return FP_ZERO; } if (0 < lexp && _DMAX - xchar <= lexp) { // overflow, return +/-INF @@ -63,7 +63,7 @@ namespace { ps->_Sh[_D1] = 0; ps->_Sh[_D2] = 0; ps->_Sh[_D3] = 0; - return 0; + return FP_ZERO; } else { // nonzero, align fraction short xexp = static_cast(lexp); unsigned short psx = 0; @@ -89,7 +89,7 @@ namespace { && (++ps->_Sh[_D2] & 0xffff) == 0 && (++ps->_Sh[_D1] & 0xffff) == 0) { ++ps->_Sh[_D0]; // round up } else if (ps->_Sh[_D0] == sign && ps->_Sh[_D1] == 0 && ps->_Sh[_D2] == 0 && ps->_Sh[_D3] == 0) { - return 0; + return FP_ZERO; } return FP_NORMAL; @@ -129,7 +129,7 @@ namespace { if (xchar == _FMAX) { return (ps->_Sh[_F0] & _FFRAC) != 0 || ps->_Sh[_F1] != 0 ? FP_NAN : FP_INFINITE; } else if (xchar == 0 && 0 < (xchar = _FDnorm(ps))) { - return 0; + return FP_ZERO; } if (0 < lexp && _FMAX - xchar <= lexp) { // overflow, return +/-INF @@ -148,7 +148,7 @@ namespace { if (lexp < -(16 + 1 + _FOFF) || 0 <= lexp) { // underflow, return +/-0 ps->_Sh[_F0] = sign; ps->_Sh[_F1] = 0; - return 0; + return FP_ZERO; } else { // nonzero, align fraction short xexp = static_cast(lexp); unsigned short psx = 0; @@ -171,7 +171,7 @@ namespace { if ((0x8000 < psx || 0x8000 == psx && (ps->_Sh[_F1] & 0x0001) != 0) && (++ps->_Sh[_F1] & 0xffff) == 0) { ++ps->_Sh[_F0]; // round up } else if (ps->_Sh[_F0] == sign && ps->_Sh[_F1] == 0) { - return 0; + return FP_ZERO; } return FP_NORMAL; @@ -195,10 +195,10 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Exp(double* px, double y, short eof if (y == 0.0) { // zero *px = y; - return 0; + return FP_ZERO; } else if (*px < -hugexp) { // certain underflow *px = _Xfe_underflow(y); - return 0; + return FP_ZERO; } else if (hugexp < *px) { // certain overflow *px = _Xfe_overflow(y); return FP_INFINITE; @@ -224,7 +224,7 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Exp(double* px, double y, short eof const short result_code = _Dscale(px, static_cast(xexp) + eoff); switch (result_code) { - case 0: + case FP_ZERO: *px = _Xfe_underflow(y); break; case FP_INFINITE: @@ -254,10 +254,10 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FExp(float* px, float y, short eoff if (y == 0.0F) { // zero *px = y; - return 0; + return FP_ZERO; } else if (*px < -hugexp) { // certain underflow *px = _Xfe_underflow(y); - return 0; + return FP_ZERO; } else if (hugexp < *px) { // certain overflow *px = _Xfe_overflow(y); return FP_INFINITE; @@ -283,7 +283,7 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FExp(float* px, float y, short eoff const short result_code = _FDscale(px, static_cast(xexp) + eoff); switch (result_code) { - case 0: + case FP_ZERO: *px = _Xfe_underflow(y); break; case FP_INFINITE: diff --git a/stl/src/xsinh.cpp b/stl/src/xsinh.cpp index 6955b464856..567b09eb62c 100644 --- a/stl/src/xsinh.cpp +++ b/stl/src/xsinh.cpp @@ -34,7 +34,7 @@ _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Sinh(double x, double y) noexcept return x; case FP_INFINITE: return y != 0.0 ? x : DSIGN(x) ? -y : y; - case 0: + case FP_ZERO: return x * y; default: // finite if (y == 0.0) { @@ -61,7 +61,7 @@ _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Sinh(double x, double y) noexcept x = y * (x - 0.25 / x); } else { switch (_Exp(&x, y, -1)) { - case 0: // report underflow + case FP_ZERO: // report underflow case FP_INFINITE: // report overflow errno = ERANGE; break; @@ -89,7 +89,7 @@ _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float x, float y) noexcept { return x; case FP_INFINITE: return y != 0.0F ? x : FSIGN(x) ? -y : y; - case 0: + case FP_ZERO: return x * y; default: // finite if (y == 0.0F) { @@ -116,7 +116,7 @@ _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float x, float y) noexcept { x = y * (x - 0.25F / x); } else { switch (_FExp(&x, y, -1)) { - case 0: // report underflow + case FP_ZERO: // report underflow case FP_INFINITE: // report overflow errno = ERANGE; break; From 4330caae185d1890bc362c2c93b2e56c6f572b16 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 03:57:41 -0800 Subject: [PATCH 14/21] Remove now-unused `_Dtest()` macros. --- stl/inc/ymath.h | 4 ---- stl/src/xmath.hpp | 4 ---- 2 files changed, 8 deletions(-) diff --git a/stl/inc/ymath.h b/stl/inc/ymath.h index 6c1adbe4421..222cf9248a8 100644 --- a/stl/inc/ymath.h +++ b/stl/inc/ymath.h @@ -16,10 +16,6 @@ _STL_DISABLE_CLANG_WARNINGS _EXTERN_C_UNLESS_PURE -// macros for _Dtest return (0 => ZERO) -#define _INFCODE 1 -#define _NANCODE 2 - _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Cosh(double, double) noexcept; _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Sinh(double, double) noexcept; _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Exp(double*, double, short) noexcept; diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index bce4e5d89b0..b8eb12e4fe5 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -20,10 +20,6 @@ #define DSIGN(x) (reinterpret_cast<_Dval*>(&(x))->_Sh[_D0] & _DSIGN) #define FSIGN(x) (reinterpret_cast<_Fval*>(&(x))->_Sh[_F0] & _FSIGN) -// macros for _Dtest return (0 => ZERO) -#define _DENORM (-2) // C9X only -#define _FINITE (-1) - _EXTERN_C_UNLESS_PURE // double declarations From d8dfbd5592a27e45e50b3b0c774ab90b7bc28b27 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 04:21:18 -0800 Subject: [PATCH 15/21] Replace `DSIGN` and `FSIGN` with `signbit()`. Equivalence proof: C:\Temp>type meow.cpp #include #include #include using namespace std; union _Dval { unsigned short _Sh[8]; double _Val; }; union _Fval { unsigned short _Sh[8]; float _Val; }; #define _D0 3 #define _F0 1 #define DSIGN(x) (reinterpret_cast<_Dval*>(&(x))->_Sh[_D0] & _DSIGN) #define FSIGN(x) (reinterpret_cast<_Fval*>(&(x))->_Sh[_F0] & _FSIGN) void test_dbl(double dbl) { const bool macro = static_cast(DSIGN(dbl)); println("dbl: {:4}; macro: {:5}; signbit: {:5}; Equal: {}", dbl, macro, signbit(dbl), macro == signbit(dbl)); } void test_flt(float flt) { const bool macro = static_cast(FSIGN(flt)); println("flt: {:4}; macro: {:5}; signbit: {:5}; Equal: {}", flt, macro, signbit(flt), macro == signbit(flt)); } int main() { test_dbl(numeric_limits::infinity()); test_dbl(-numeric_limits::infinity()); test_flt(numeric_limits::infinity()); test_flt(-numeric_limits::infinity()); } C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /MTd /Od meow.cpp meow.cpp C:\Temp>meow dbl: inf; macro: false; signbit: false; Equal: true dbl: -inf; macro: true ; signbit: true ; Equal: true flt: inf; macro: false; signbit: false; Equal: true flt: -inf; macro: true ; signbit: true ; Equal: true --- stl/src/xmath.hpp | 3 --- stl/src/xsinh.cpp | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index b8eb12e4fe5..4b92bbd4a6d 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -17,9 +17,6 @@ #define _F0 1 // little-endian #define _F1 0 -#define DSIGN(x) (reinterpret_cast<_Dval*>(&(x))->_Sh[_D0] & _DSIGN) -#define FSIGN(x) (reinterpret_cast<_Fval*>(&(x))->_Sh[_F0] & _FSIGN) - _EXTERN_C_UNLESS_PURE // double declarations diff --git a/stl/src/xsinh.cpp b/stl/src/xsinh.cpp index 567b09eb62c..ccdadea8a5f 100644 --- a/stl/src/xsinh.cpp +++ b/stl/src/xsinh.cpp @@ -33,7 +33,7 @@ _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Sinh(double x, double y) noexcept case FP_NAN: return x; case FP_INFINITE: - return y != 0.0 ? x : DSIGN(x) ? -y : y; + return y != 0.0 ? x : _STD signbit(x) ? -y : y; case FP_ZERO: return x * y; default: // finite @@ -88,7 +88,7 @@ _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float x, float y) noexcept { case FP_NAN: return x; case FP_INFINITE: - return y != 0.0F ? x : FSIGN(x) ? -y : y; + return y != 0.0F ? x : _STD signbit(x) ? -y : y; case FP_ZERO: return x * y; default: // finite From 340232de4590a4da9fb81b881e0d4eaedc90e4b2 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 04:30:13 -0800 Subject: [PATCH 16/21] Move `_Dval`, `_Fval`, and their index macros into xexp.cpp's unnamed namespace. It's okay to move these unions out of _EXTERN_C_UNLESS_PURE, because nothing else uses them. --- stl/src/xexp.cpp | 19 +++++++++++++++++++ stl/src/xmath.hpp | 19 ------------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index 308c6e4b0d1..8300ae1ea1c 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -4,6 +4,17 @@ #include "xmath.hpp" namespace { +// float properties +#define _D0 3 // little-endian, small long doubles +#define _D1 2 +#define _D2 1 +#define _D3 0 + + union _Dval { // pun floating type as integer array + unsigned short _Sh[8]; + double _Val; + }; + short _Dnorm(_Dval* ps) noexcept { // normalize double fraction short xchar = 1; unsigned short sign = static_cast(ps->_Sh[_D0] & _DSIGN); @@ -97,6 +108,14 @@ namespace { } } +#define _F0 1 // little-endian +#define _F1 0 + + union _Fval { // pun floating type as integer array + unsigned short _Sh[8]; + float _Val; + }; + short _FDnorm(_Fval* ps) noexcept { // normalize float fraction short xchar = 1; unsigned short sign = static_cast(ps->_Sh[_F0] & _FSIGN); diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index 4b92bbd4a6d..38a26cdab7c 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -8,31 +8,12 @@ #include #include -// float properties -#define _D0 3 // little-endian, small long doubles -#define _D1 2 -#define _D2 1 -#define _D3 0 - -#define _F0 1 // little-endian -#define _F1 0 - _EXTERN_C_UNLESS_PURE // double declarations -union _Dval { // pun floating type as integer array - unsigned short _Sh[8]; - double _Val; -}; - extern const double _Xbig; // float declarations -union _Fval { // pun floating type as integer array - unsigned short _Sh[8]; - float _Val; -}; - extern const float _FXbig; _END_EXTERN_C_UNLESS_PURE From bb230a5bd5edee91d2203a48e78d0c3e022f17ea Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 04:33:30 -0800 Subject: [PATCH 17/21] Change index macros to `constexpr int`, cleanup comments. --- stl/src/xexp.cpp | 13 ++++++------- stl/src/xmath.hpp | 5 ----- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index 8300ae1ea1c..ca24d4964eb 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -4,11 +4,10 @@ #include "xmath.hpp" namespace { -// float properties -#define _D0 3 // little-endian, small long doubles -#define _D1 2 -#define _D2 1 -#define _D3 0 + constexpr int _D0 = 3; // little-endian + constexpr int _D1 = 2; + constexpr int _D2 = 1; + constexpr int _D3 = 0; union _Dval { // pun floating type as integer array unsigned short _Sh[8]; @@ -108,8 +107,8 @@ namespace { } } -#define _F0 1 // little-endian -#define _F1 0 + constexpr int _F0 = 1; // little-endian + constexpr int _F1 = 0; union _Fval { // pun floating type as integer array unsigned short _Sh[8]; diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index 38a26cdab7c..2224381091e 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -9,13 +9,8 @@ #include _EXTERN_C_UNLESS_PURE - -// double declarations extern const double _Xbig; - -// float declarations extern const float _FXbig; - _END_EXTERN_C_UNLESS_PURE // raise IEEE 754 exceptions From a6d8c16d8f3f8d8b13d661b467dc8f14a6bff273 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 04:36:11 -0800 Subject: [PATCH 18/21] Move `_Xfe_overflow()`, `_Xfe_underflow()` into xexp.cpp's unnamed namespace. They obviously aren't dllexported. --- stl/src/xexp.cpp | 24 ++++++++++++++++++++++++ stl/src/xmath.hpp | 23 ----------------------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index ca24d4964eb..88f9bd72e08 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -196,6 +196,30 @@ namespace { } } } + +// raise IEEE 754 exceptions +#ifndef _M_CEE_PURE +#pragma float_control(except, on, push) +#endif + + template + [[nodiscard]] T _Xfe_overflow(const T sign) noexcept { + static_assert(_STD is_floating_point_v, "Expected is_floating_point_v."); + constexpr T huge = _STD numeric_limits::max(); + return _STD copysign(huge, sign) * huge; + } + + template + [[nodiscard]] T _Xfe_underflow(const T sign) noexcept { + static_assert(_STD is_floating_point_v, "Expected is_floating_point_v."); + constexpr T tiny = _STD numeric_limits::min(); + return _STD copysign(tiny, sign) * tiny; + } + +#ifndef _M_CEE_PURE +#pragma float_control(pop) +#endif + } // unnamed namespace _EXTERN_C_UNLESS_PURE diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index 2224381091e..ce2cdcd82a4 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -12,26 +12,3 @@ _EXTERN_C_UNLESS_PURE extern const double _Xbig; extern const float _FXbig; _END_EXTERN_C_UNLESS_PURE - -// raise IEEE 754 exceptions -#ifndef _M_CEE_PURE -#pragma float_control(except, on, push) -#endif - -template -[[nodiscard]] T _Xfe_overflow(const T sign) noexcept { - static_assert(_STD is_floating_point_v, "Expected is_floating_point_v."); - constexpr T huge = _STD numeric_limits::max(); - return _STD copysign(huge, sign) * huge; -} - -template -[[nodiscard]] T _Xfe_underflow(const T sign) noexcept { - static_assert(_STD is_floating_point_v, "Expected is_floating_point_v."); - constexpr T tiny = _STD numeric_limits::min(); - return _STD copysign(tiny, sign) * tiny; -} - -#ifndef _M_CEE_PURE -#pragma float_control(pop) -#endif From e56b8f87e8acd117033994918f4a82c59bfc4bf3 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 04:41:14 -0800 Subject: [PATCH 19/21] Replace `extern const` `_Xbig` and `_FXbig` with replicated `constexpr`. They weren't dllexported. Although this results in a bit of code duplication, the result is more optimizer-friendly, and will allow us to eliminate xmath.hpp. --- stl/src/xcosh.cpp | 2 ++ stl/src/xmath.hpp | 5 ----- stl/src/xsinh.cpp | 4 +++- stl/src/xvalues.cpp | 3 --- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/stl/src/xcosh.cpp b/stl/src/xcosh.cpp index 616134166db..6822a5a8cab 100644 --- a/stl/src/xcosh.cpp +++ b/stl/src/xcosh.cpp @@ -21,6 +21,7 @@ _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Cosh(double x, double y) noexcept x = -x; } + constexpr double _Xbig = ((48 + _DOFF) + 2) * 0.347; if (x < _Xbig) { // worth adding in exp(-x) _Exp(&x, 1.0, -1); return y * (x + 0.25 / x); @@ -55,6 +56,7 @@ _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FCosh(float x, float y) noexcept { x = -x; } + constexpr float _FXbig = ((16 + _FOFF) + 2) * 0.347f; if (x < _FXbig) { // worth adding in exp(-x) _FExp(&x, 1.0F, -1); return y * (x + 0.25F / x); diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index ce2cdcd82a4..57c553c6843 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -7,8 +7,3 @@ #include #include #include - -_EXTERN_C_UNLESS_PURE -extern const double _Xbig; -extern const float _FXbig; -_END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xsinh.cpp b/stl/src/xsinh.cpp index ccdadea8a5f..34e2c6ff6e5 100644 --- a/stl/src/xsinh.cpp +++ b/stl/src/xsinh.cpp @@ -49,6 +49,7 @@ _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Sinh(double x, double y) noexcept } constexpr double rteps = 0x1p-27; + constexpr double _Xbig = ((48 + _DOFF) + 2) * 0.347; if (x < rteps) { x *= y; // x tiny } else if (x < 1.0) { @@ -103,7 +104,8 @@ _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _FSinh(float x, float y) noexcept { neg = 0; } - constexpr float rteps = 0x1p-12f; + constexpr float rteps = 0x1p-12f; + constexpr float _FXbig = ((16 + _FOFF) + 2) * 0.347f; if (x < rteps) { x *= y; // x tiny } else if (x < 1.0F) { diff --git a/stl/src/xvalues.cpp b/stl/src/xvalues.cpp index 0fb45636130..dcc48528ff4 100644 --- a/stl/src/xvalues.cpp +++ b/stl/src/xvalues.cpp @@ -13,9 +13,6 @@ _EXTERN_C_UNLESS_PURE -extern const double _Xbig = ((48 + _DOFF) + 2) * 0.347; -extern const float _FXbig = ((16 + _FOFF) + 2) * 0.347f; - // TRANSITION, ABI: preserved for binary compatibility union _Dconst { // pun float types as integer array unsigned short _Word[8]; From 055190cc564b1fba97b933ba89da811e0fb7ebcb Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 04:53:36 -0800 Subject: [PATCH 20/21] Delete xmath.hpp, include only relevant headers. --- stl/src/xcosh.cpp | 4 +++- stl/src/xdtest.cpp | 2 +- stl/src/xexp.cpp | 3 ++- stl/src/xmath.hpp | 9 --------- stl/src/xsinh.cpp | 5 +++-- stl/src/xvalues.cpp | 2 +- 6 files changed, 10 insertions(+), 15 deletions(-) delete mode 100644 stl/src/xmath.hpp diff --git a/stl/src/xcosh.cpp b/stl/src/xcosh.cpp index 6822a5a8cab..2eb46bf197f 100644 --- a/stl/src/xcosh.cpp +++ b/stl/src/xcosh.cpp @@ -1,7 +1,9 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include "xmath.hpp" +#include +#include +#include _EXTERN_C_UNLESS_PURE diff --git a/stl/src/xdtest.cpp b/stl/src/xdtest.cpp index a9253d53d2f..7f4c1906293 100644 --- a/stl/src/xdtest.cpp +++ b/stl/src/xdtest.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include "xmath.hpp" +#include _EXTERN_C_UNLESS_PURE diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index 88f9bd72e08..f83cbe44260 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include "xmath.hpp" +#include +#include namespace { constexpr int _D0 = 3; // little-endian diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp deleted file mode 100644 index 57c553c6843..00000000000 --- a/stl/src/xmath.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#pragma once - -#include -#include -#include -#include diff --git a/stl/src/xsinh.cpp b/stl/src/xsinh.cpp index 34e2c6ff6e5..44914ad9af8 100644 --- a/stl/src/xsinh.cpp +++ b/stl/src/xsinh.cpp @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include +#include #include - -#include "xmath.hpp" +#include namespace { double _Poly(double x, const double* tab, int n) noexcept { // compute polynomial diff --git a/stl/src/xvalues.cpp b/stl/src/xvalues.cpp index dcc48528ff4..020c3c823a0 100644 --- a/stl/src/xvalues.cpp +++ b/stl/src/xvalues.cpp @@ -9,7 +9,7 @@ #endif #endif -#include "xmath.hpp" +#include _EXTERN_C_UNLESS_PURE From a85563e0d6c344e8a237f5b2e92ddba05fe97676 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 12 Dec 2025 05:12:41 -0800 Subject: [PATCH 21/21] Fix dangerous `_Dval`, `_Fval` union sizes. These are within an unnamed namespace, so we can alter their sizes. There was no actual harm here, since we never indexed into the nonexistent memory, but it was still risky, and likely to annoy static analysis someday. --- stl/src/xexp.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/stl/src/xexp.cpp b/stl/src/xexp.cpp index f83cbe44260..6a4bca0cf63 100644 --- a/stl/src/xexp.cpp +++ b/stl/src/xexp.cpp @@ -11,9 +11,10 @@ namespace { constexpr int _D3 = 0; union _Dval { // pun floating type as integer array - unsigned short _Sh[8]; + unsigned short _Sh[4]; double _Val; }; + static_assert(sizeof(_Dval::_Sh) == sizeof(_Dval::_Val), "_Dval members should be the same size"); short _Dnorm(_Dval* ps) noexcept { // normalize double fraction short xchar = 1; @@ -112,9 +113,10 @@ namespace { constexpr int _F1 = 0; union _Fval { // pun floating type as integer array - unsigned short _Sh[8]; + unsigned short _Sh[2]; float _Val; }; + static_assert(sizeof(_Fval::_Sh) == sizeof(_Fval::_Val), "_Fval members should be the same size"); short _FDnorm(_Fval* ps) noexcept { // normalize float fraction short xchar = 1;