[libc-commits] [libc] b0dbd2c - [libc][math] Add option to set a specific exponent for frexp with Inf/NaN inputs. (#112387)

via libc-commits libc-commits at lists.llvm.org
Fri Oct 18 06:58:18 PDT 2024


Author: lntue
Date: 2024-10-18T09:58:15-04:00
New Revision: b0dbd2ca5b52a277560a70a2864ea9949f1e3794

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

LOG: [libc][math] Add option to set a specific exponent for frexp with Inf/NaN inputs. (#112387)

In IEEE 754 and C standards, when calling `frexp` with Inf/Nan inputs,
the exponent result is unspecified. In this case, FreeBSD libc and musl
just passthrough `exp`, while glibc, FreeBSD libm set exp = 0, and MSVC
set exp = -1.

By default, LLVM libc will passthrough `exp` just as FreeBSD libc and
musl, but we also allow users to explicitly choose the return exp value
in this case for compatibility with other libc.

Notice that, gcc did generate passthrough `exp` for `frexp(NaN/Inf,
exp)`: https://godbolt.org/z/sM8fEej4E

Added: 
    

Modified: 
    libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
    libc/config/config.json
    libc/docs/configure.rst
    libc/src/__support/FPUtil/ManipulationFunctions.h
    libc/test/src/math/smoke/FrexpTest.h

Removed: 
    


################################################################################
diff  --git a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
index 737ac87f4c7a21..0c658c6866c437 100644
--- a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
+++ b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
@@ -79,6 +79,14 @@ function(_get_compile_options_from_config output_var)
     list(APPEND config_options "-DLIBC_ADD_NULL_CHECKS")
   endif()
 
+  if(NOT "${LIBC_CONF_FREXP_INF_NAN_EXPONENT}" STREQUAL "")
+    list(APPEND config_options "-DLIBC_FREXP_INF_NAN_EXPONENT=${LIBC_CONF_FREXP_INF_NAN_EXPONENT}")
+  endif()
+
+  if(LIBC_CONF_MATH_OPTIMIZATIONS)
+    list(APPEND compile_options "-DLIBC_MATH=${LIBC_CONF_MATH_OPTIMIZATIONS}")
+  endif()
+
   set(${output_var} ${config_options} PARENT_SCOPE)
 endfunction(_get_compile_options_from_config)
 
@@ -170,9 +178,6 @@ function(_get_common_compile_options output_var flags)
       list(APPEND compile_options "-Wthread-safety")
       list(APPEND compile_options "-Wglobal-constructors")
     endif()
-    if(LIBC_CONF_MATH_OPTIMIZATIONS)
-      list(APPEND compile_options "-DLIBC_MATH=${LIBC_CONF_MATH_OPTIMIZATIONS}")
-    endif()
   elseif(MSVC)
     list(APPEND compile_options "/EHs-c-")
     list(APPEND compile_options "/GR-")

diff  --git a/libc/config/config.json b/libc/config/config.json
index 2e4f878778e6e0..9a5d5c3c68da60 100644
--- a/libc/config/config.json
+++ b/libc/config/config.json
@@ -87,6 +87,10 @@
     "LIBC_CONF_MATH_OPTIMIZATIONS": {
       "value": 0,
       "doc": "Configures optimizations for math functions. Values accepted are LIBC_MATH_SKIP_ACCURATE_PASS, LIBC_MATH_SMALL_TABLES, LIBC_MATH_NO_ERRNO, LIBC_MATH_NO_EXCEPT, and LIBC_MATH_FAST."
+    },
+    "LIBC_CONF_FREXP_INF_NAN_EXPONENT": {
+      "value": "",
+      "doc": "The value written back to the second parameter when calling frexp/frexpf/frexpl` with `+/-Inf`/`NaN` is unspecified.  Configue an explicit exp value for Inf/NaN inputs."
     }
   },
   "qsort": {

diff  --git a/libc/docs/configure.rst b/libc/docs/configure.rst
index 867bb807d10ac9..e225e6b566dfb2 100644
--- a/libc/docs/configure.rst
+++ b/libc/docs/configure.rst
@@ -33,6 +33,7 @@ to learn about the defaults for your platform and target.
 * **"general" options**
     - ``LIBC_ADD_NULL_CHECKS``: Add nullptr checks in the library's implementations to some functions for which passing nullptr is undefined behavior.
 * **"math" options**
+    - ``LIBC_CONF_FREXP_INF_NAN_EXPONENT``: Set the specific exp value for Inf/NaN inputs.
     - ``LIBC_CONF_MATH_OPTIMIZATIONS``: Configures optimizations for math functions. Values accepted are LIBC_MATH_SKIP_ACCURATE_PASS, LIBC_MATH_SMALL_TABLES, LIBC_MATH_NO_ERRNO, LIBC_MATH_NO_EXCEPT, and LIBC_MATH_FAST.
 * **"printf" options**
     - ``LIBC_CONF_PRINTF_DISABLE_FIXED_POINT``: Disable printing fixed point values in printf and friends.

diff  --git a/libc/src/__support/FPUtil/ManipulationFunctions.h b/libc/src/__support/FPUtil/ManipulationFunctions.h
index 66bfe2aa377f99..9c10011ccd2039 100644
--- a/libc/src/__support/FPUtil/ManipulationFunctions.h
+++ b/libc/src/__support/FPUtil/ManipulationFunctions.h
@@ -31,8 +31,16 @@ namespace fputil {
 template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
 LIBC_INLINE T frexp(T x, int &exp) {
   FPBits<T> bits(x);
-  if (bits.is_inf_or_nan())
+  if (bits.is_inf_or_nan()) {
+#ifdef LIBC_FREXP_INF_NAN_EXPONENT
+    // The value written back to the second parameter when calling
+    // frexp/frexpf/frexpl` with `+/-Inf`/`NaN` is unspecified in the standard.
+    // Set the exp value for Inf/NaN inputs explicitly to
+    // LIBC_FREXP_INF_NAN_EXPONENT if it is defined.
+    exp = LIBC_FREXP_INF_NAN_EXPONENT;
+#endif // LIBC_FREXP_INF_NAN_EXPONENT
     return x;
+  }
   if (bits.is_zero()) {
     exp = 0;
     return x;

diff  --git a/libc/test/src/math/smoke/FrexpTest.h b/libc/test/src/math/smoke/FrexpTest.h
index 11641fc6743c44..3fb3a2e1688c81 100644
--- a/libc/test/src/math/smoke/FrexpTest.h
+++ b/libc/test/src/math/smoke/FrexpTest.h
@@ -21,8 +21,19 @@ class FrexpTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   void testSpecialNumbers(FrexpFunc func) {
     int exponent;
     EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(aNaN, &exponent));
+#ifdef LIBC_FREXP_INF_NAN_EXPONENT
+    EXPECT_EQ(LIBC_FREXP_INF_NAN_EXPONENT, exponent);
+#endif // LIBC_FREXP_INF_NAN_EXPONENT
+
     EXPECT_FP_EQ_ALL_ROUNDING(inf, func(inf, &exponent));
+#ifdef LIBC_FREXP_INF_NAN_EXPONENT
+    EXPECT_EQ(LIBC_FREXP_INF_NAN_EXPONENT, exponent);
+#endif // LIBC_FREXP_INF_NAN_EXPONENT
+
     EXPECT_FP_EQ_ALL_ROUNDING(neg_inf, func(neg_inf, &exponent));
+#ifdef LIBC_FREXP_INF_NAN_EXPONENT
+    EXPECT_EQ(LIBC_FREXP_INF_NAN_EXPONENT, exponent);
+#endif // LIBC_FREXP_INF_NAN_EXPONENT
 
     EXPECT_FP_EQ_ALL_ROUNDING(zero, func(zero, &exponent));
     EXPECT_EQ(exponent, 0);


        


More information about the libc-commits mailing list