[libc-commits] [libc] [libc][math][c23] Add {ldexp, scalbn, scalbln}f16 C23 math functions (PR #94797)

via libc-commits libc-commits at lists.llvm.org
Fri Jun 21 05:40:33 PDT 2024


https://github.com/overmighty updated https://github.com/llvm/llvm-project/pull/94797

>From bea104a1de18332deacdbc667603d9186af5caeb Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Fri, 7 Jun 2024 15:27:58 +0200
Subject: [PATCH 1/5] [libc][math][c23] Add ldexpf16 C23 math function

---
 libc/config/linux/aarch64/entrypoints.txt     |  1 +
 libc/config/linux/x86_64/entrypoints.txt      |  1 +
 libc/docs/math/index.rst                      |  2 +-
 libc/spec/stdc.td                             |  1 +
 .../__support/FPUtil/ManipulationFunctions.h  |  2 +-
 libc/src/__support/FPUtil/dyadic_float.h      |  5 +++++
 libc/src/math/CMakeLists.txt                  |  1 +
 libc/src/math/generic/CMakeLists.txt          | 13 ++++++++++++
 libc/src/math/generic/ldexpf16.cpp            | 19 ++++++++++++++++++
 libc/src/math/ldexpf16.h                      | 20 +++++++++++++++++++
 libc/test/src/math/smoke/CMakeLists.txt       | 15 ++++++++++++++
 libc/test/src/math/smoke/LdExpTest.h          | 16 +++++++--------
 libc/test/src/math/smoke/ldexpf16_test.cpp    | 13 ++++++++++++
 13 files changed, 99 insertions(+), 10 deletions(-)
 create mode 100644 libc/src/math/generic/ldexpf16.cpp
 create mode 100644 libc/src/math/ldexpf16.h
 create mode 100644 libc/test/src/math/smoke/ldexpf16_test.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index aa223a6a72a6f..77c8b95e5066e 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -524,6 +524,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.fromfpxf16
     libc.src.math.getpayloadf16
     libc.src.math.ilogbf16
+    libc.src.math.ldexpf16
     libc.src.math.llogbf16
     libc.src.math.llrintf16
     libc.src.math.llroundf16
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index ab7f572b61858..c26908ed6a12c 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -557,6 +557,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.fromfpxf16
     libc.src.math.getpayloadf16
     libc.src.math.ilogbf16
+    libc.src.math.ldexpf16
     libc.src.math.llogbf16
     libc.src.math.llrintf16
     libc.src.math.llroundf16
diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst
index c9b12387143ad..c245253638947 100644
--- a/libc/docs/math/index.rst
+++ b/libc/docs/math/index.rst
@@ -174,7 +174,7 @@ Basic Operations
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | ilogb            | |check|          | |check|         | |check|                | |check|              | |check|                | 7.12.6.8               | F.10.3.8                   |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
-| ldexp            | |check|          | |check|         | |check|                |                      | |check|                | 7.12.6.9               | F.10.3.9                   |
+| ldexp            | |check|          | |check|         | |check|                | |check|              | |check|                | 7.12.6.9               | F.10.3.9                   |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | llogb            | |check|          | |check|         | |check|                | |check|              | |check|                | 7.12.6.10              | F.10.3.10                  |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index f0b36f826c56d..a2bf102e2871e 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -533,6 +533,7 @@ def StdC : StandardSpec<"stdc"> {
           FunctionSpec<"ldexp", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntType>]>,
           FunctionSpec<"ldexpf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntType>]>,
           FunctionSpec<"ldexpl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>]>,
+          GuardedFunctionSpec<"ldexpf16", RetValSpec<Float16Type>, [ArgSpec<Float16Type>, ArgSpec<IntType>], "LIBC_TYPES_HAS_FLOAT16">,
           GuardedFunctionSpec<"ldexpf128", RetValSpec<Float128Type>, [ArgSpec<Float128Type>, ArgSpec<IntType>], "LIBC_TYPES_HAS_FLOAT128">,
 
           FunctionSpec<"log10", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
diff --git a/libc/src/__support/FPUtil/ManipulationFunctions.h b/libc/src/__support/FPUtil/ManipulationFunctions.h
index a289c2ef70467..11ea6e3738d28 100644
--- a/libc/src/__support/FPUtil/ManipulationFunctions.h
+++ b/libc/src/__support/FPUtil/ManipulationFunctions.h
@@ -185,7 +185,7 @@ LIBC_INLINE constexpr T ldexp(T x, int exp) {
   }
 
   // For all other values, NormalFloat to T conversion handles it the right way.
-  DyadicFloat<FPBits<T>::STORAGE_LEN> normal(bits.get_val());
+  DyadicFloat<cpp::max(FPBits<T>::STORAGE_LEN, 32)> normal(bits.get_val());
   normal.exponent += exp;
   return static_cast<T>(normal);
 }
diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h
index 12a69228d36c7..f1791f9da56ad 100644
--- a/libc/src/__support/FPUtil/dyadic_float.h
+++ b/libc/src/__support/FPUtil/dyadic_float.h
@@ -14,6 +14,7 @@
 #include "src/__support/CPP/type_traits.h"
 #include "src/__support/big_int.h"
 #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
+#include "src/__support/macros/properties/types.h" // float16
 
 #include <stddef.h>
 
@@ -183,6 +184,10 @@ template <size_t Bits> struct DyadicFloat {
     return r;
   }
 
+  LIBC_INLINE explicit constexpr operator float16() const {
+    return static_cast<float16>(static_cast<float>(*this));
+  }
+
   LIBC_INLINE explicit constexpr operator MantissaType() const {
     if (mantissa.is_zero())
       return 0;
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index 92e0cd248b2e1..5454b409f6c99 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -230,6 +230,7 @@ add_math_entrypoint_object(llogbf128)
 add_math_entrypoint_object(ldexp)
 add_math_entrypoint_object(ldexpf)
 add_math_entrypoint_object(ldexpl)
+add_math_entrypoint_object(ldexpf16)
 add_math_entrypoint_object(ldexpf128)
 
 add_math_entrypoint_object(log10)
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index f509b9710a806..c0fc1d5115b25 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -1487,6 +1487,19 @@ add_entrypoint_object(
     libc.src.__support.FPUtil.manipulation_functions
 )
 
+add_entrypoint_object(
+  ldexpf16
+  SRCS
+    ldexpf16.cpp
+  HDRS
+    ../ldexpf16.h
+  COMPILE_OPTIONS
+    -O0 -ggdb3
+  DEPENDS
+    libc.src.__support.macros.properties.types
+    libc.src.__support.FPUtil.manipulation_functions
+)
+
 add_entrypoint_object(
   ldexpf128
   SRCS
diff --git a/libc/src/math/generic/ldexpf16.cpp b/libc/src/math/generic/ldexpf16.cpp
new file mode 100644
index 0000000000000..ed15c4572edf5
--- /dev/null
+++ b/libc/src/math/generic/ldexpf16.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of ldexpf16 function -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/ldexpf16.h"
+#include "src/__support/FPUtil/ManipulationFunctions.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(float16, ldexpf16, (float16 x, int exp)) {
+  return fputil::ldexp(x, exp);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/math/ldexpf16.h b/libc/src/math/ldexpf16.h
new file mode 100644
index 0000000000000..7303610b18dff
--- /dev/null
+++ b/libc/src/math/ldexpf16.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for ldexpf16 ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_LDEXPF16_H
+#define LLVM_LIBC_SRC_MATH_LDEXPF16_H
+
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE {
+
+float16 ldexpf16(float16 x, int exp);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_LDEXPF16_H
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index bd8de18287de2..9fc3f2717225e 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -1550,6 +1550,21 @@ add_fp_unittest(
     libc.src.__support.FPUtil.normal_float
 )
 
+add_fp_unittest(
+  ldexpf16_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    ldexpf16_test.cpp
+  HDRS
+    LdExpTest.h
+  DEPENDS
+    libc.src.math.ldexpf16
+    libc.src.__support.CPP.limits
+    libc.src.__support.FPUtil.fp_bits
+    libc.src.__support.FPUtil.normal_float
+)
+
 add_fp_unittest(
   ldexpf128_test
   SUITE
diff --git a/libc/test/src/math/smoke/LdExpTest.h b/libc/test/src/math/smoke/LdExpTest.h
index 713d305c47494..19c02d2dc7d0f 100644
--- a/libc/test/src/math/smoke/LdExpTest.h
+++ b/libc/test/src/math/smoke/LdExpTest.h
@@ -31,7 +31,7 @@ class LdExpTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   const T nan = FPBits::quiet_nan().get_val();
 
   // A normalized mantissa to be used with tests.
-  static constexpr StorageType MANTISSA = NormalFloat::ONE + 0x1234;
+  static constexpr StorageType MANTISSA = NormalFloat::ONE + 0x123;
 
 public:
   typedef T (*LdExpFunc)(T, int);
@@ -60,7 +60,7 @@ class LdExpTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
 
   void testOverflow(LdExpFunc func) {
     NormalFloat x(Sign::POS, FPBits::MAX_BIASED_EXPONENT - 10,
-                  NormalFloat::ONE + 0xF00BA);
+                  NormalFloat::ONE + 0xF00);
     for (int32_t exp = 10; exp < 100; ++exp) {
       ASSERT_FP_EQ(inf, func(T(x), exp));
       ASSERT_FP_EQ(neg_inf, func(-T(x), exp));
@@ -95,10 +95,10 @@ class LdExpTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
 
   void testNormalOperation(LdExpFunc func) {
     T val_array[] = {// Normal numbers
-                     NormalFloat(Sign::POS, 100, MANTISSA),
-                     NormalFloat(Sign::POS, -100, MANTISSA),
-                     NormalFloat(Sign::NEG, 100, MANTISSA),
-                     NormalFloat(Sign::NEG, -100, MANTISSA),
+                     NormalFloat(Sign::POS, 10, MANTISSA),
+                     NormalFloat(Sign::POS, -10, MANTISSA),
+                     NormalFloat(Sign::NEG, 10, MANTISSA),
+                     NormalFloat(Sign::NEG, -10, MANTISSA),
                      // Subnormal numbers
                      NormalFloat(Sign::POS, -FPBits::EXP_BIAS, MANTISSA),
                      NormalFloat(Sign::NEG, -FPBits::EXP_BIAS, MANTISSA)};
@@ -114,8 +114,8 @@ class LdExpTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
         NormalFloat two_to_exp = NormalFloat(static_cast<T>(1.L));
         two_to_exp = two_to_exp.mul2(exp);
 
-        ASSERT_FP_EQ(func(x, exp), x * two_to_exp);
-        ASSERT_FP_EQ(func(x, -exp), x / two_to_exp);
+        ASSERT_FP_EQ(func(x, exp), x * static_cast<T>(two_to_exp));
+        ASSERT_FP_EQ(func(x, -exp), x / static_cast<T>(two_to_exp));
       }
     }
 
diff --git a/libc/test/src/math/smoke/ldexpf16_test.cpp b/libc/test/src/math/smoke/ldexpf16_test.cpp
new file mode 100644
index 0000000000000..ecf8f76a3aac8
--- /dev/null
+++ b/libc/test/src/math/smoke/ldexpf16_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for ldexpf16 --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LdExpTest.h"
+
+#include "src/math/ldexpf16.h"
+
+LIST_LDEXP_TESTS(float16, LIBC_NAMESPACE::ldexpf16);

>From 537c6ff08f895e5041884515a643c56d21a85ef7 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Fri, 7 Jun 2024 21:21:34 +0200
Subject: [PATCH 2/5] [libc][math][c23] Add scalbnf16 C23 math function

---
 libc/config/linux/aarch64/entrypoints.txt   |  1 +
 libc/config/linux/x86_64/entrypoints.txt    |  1 +
 libc/docs/math/index.rst                    |  2 +-
 libc/spec/stdc.td                           |  1 +
 libc/src/math/CMakeLists.txt                |  1 +
 libc/src/math/generic/CMakeLists.txt        | 14 ++++++++++++
 libc/src/math/generic/scalbnf16.cpp         | 25 +++++++++++++++++++++
 libc/src/math/scalbnf16.h                   | 20 +++++++++++++++++
 libc/test/src/math/smoke/CMakeLists.txt     | 13 +++++++++++
 libc/test/src/math/smoke/scalbnf16_test.cpp | 13 +++++++++++
 10 files changed, 90 insertions(+), 1 deletion(-)
 create mode 100644 libc/src/math/generic/scalbnf16.cpp
 create mode 100644 libc/src/math/scalbnf16.h
 create mode 100644 libc/test/src/math/smoke/scalbnf16_test.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 77c8b95e5066e..ba2c8c76b5c13 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -546,6 +546,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.rintf16
     libc.src.math.roundf16
     libc.src.math.roundevenf16
+    libc.src.math.scalbnf16
     libc.src.math.setpayloadf16
     libc.src.math.setpayloadsigf16
     libc.src.math.totalorderf16
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index c26908ed6a12c..6a75ec9d2719a 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -576,6 +576,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.rintf16
     libc.src.math.roundf16
     libc.src.math.roundevenf16
+    libc.src.math.scalbnf16
     libc.src.math.setpayloadf16
     libc.src.math.setpayloadsigf16
     libc.src.math.totalorderf16
diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst
index c245253638947..d44037bfeedea 100644
--- a/libc/docs/math/index.rst
+++ b/libc/docs/math/index.rst
@@ -212,7 +212,7 @@ Basic Operations
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | roundeven        | |check|          | |check|         | |check|                | |check|              | |check|                | 7.12.9.8               | F.10.6.8                   |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
-| scalbn           | |check|          | |check|         | |check|                |                      | |check|                | 7.12.6.19              | F.10.3.19                  |
+| scalbn           | |check|          | |check|         | |check|                | |check|              | |check|                | 7.12.6.19              | F.10.3.19                  |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | setpayload       |                  |                 |                        | |check|              |                        | F.10.13.2              | N/A                        |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index a2bf102e2871e..803cda1b09b69 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -699,6 +699,7 @@ def StdC : StandardSpec<"stdc"> {
           FunctionSpec<"scalbn", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntType>]>,
           FunctionSpec<"scalbnf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntType>]>,
           FunctionSpec<"scalbnl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>]>,
+          GuardedFunctionSpec<"scalbnf16", RetValSpec<Float16Type>, [ArgSpec<Float16Type>, ArgSpec<IntType>], "LIBC_TYPES_HAS_FLOAT16">,
           GuardedFunctionSpec<"scalbnf128", RetValSpec<Float128Type>, [ArgSpec<Float128Type>, ArgSpec<IntType>], "LIBC_TYPES_HAS_FLOAT128">,
 
           FunctionSpec<"nanf", RetValSpec<FloatType>, [ArgSpec<ConstCharPtr>]>,
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index 5454b409f6c99..34cb3dbfb6655 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -351,6 +351,7 @@ add_math_entrypoint_object(roundevenf128)
 add_math_entrypoint_object(scalbn)
 add_math_entrypoint_object(scalbnf)
 add_math_entrypoint_object(scalbnl)
+add_math_entrypoint_object(scalbnf16)
 add_math_entrypoint_object(scalbnf128)
 
 add_math_entrypoint_object(setpayloadf16)
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index c0fc1d5115b25..c7de6d2921e38 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -3553,6 +3553,20 @@ add_entrypoint_object(
     -O3
 )
 
+add_entrypoint_object(
+  scalbnf16
+  SRCS
+    scalbnf16.cpp
+  HDRS
+    ../scalbnf16.h
+  DEPENDS
+    libc.hdr.float_macros
+    libc.src.__support.macros.properties.types
+    libc.src.__support.FPUtil.manipulation_functions
+  COMPILE_OPTIONS
+    -O3
+)
+
 add_entrypoint_object(
   scalbnf128
   SRCS
diff --git a/libc/src/math/generic/scalbnf16.cpp b/libc/src/math/generic/scalbnf16.cpp
new file mode 100644
index 0000000000000..a42fdfffd569f
--- /dev/null
+++ b/libc/src/math/generic/scalbnf16.cpp
@@ -0,0 +1,25 @@
+//===-- Implementation of scalbnf16 function ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/scalbnf16.h"
+#include "src/__support/FPUtil/ManipulationFunctions.h"
+#include "src/__support/common.h"
+
+#include "hdr/float_macros.h"
+
+#if FLT_RADIX != 2
+#error "FLT_RADIX != 2 is not supported."
+#endif
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(float16, scalbnf16, (float16 x, int n)) {
+  return fputil::ldexp(x, n);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/math/scalbnf16.h b/libc/src/math/scalbnf16.h
new file mode 100644
index 0000000000000..95e4862f38070
--- /dev/null
+++ b/libc/src/math/scalbnf16.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for scalbnf16 ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_SCALBNF16_H
+#define LLVM_LIBC_SRC_MATH_SCALBNF16_H
+
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE {
+
+float16 scalbnf16(float16 x, int n);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_SCALBNF16_H
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 9fc3f2717225e..ef5ed27369068 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -3509,6 +3509,19 @@ add_fp_unittest(
     libc.src.__support.FPUtil.fp_bits
 )
 
+add_fp_unittest(
+  scalbnf16_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    scalbnf16_test.cpp
+  HDRS
+    ScalbnTest.h
+  DEPENDS
+    libc.src.math.scalbnf16
+    libc.src.__support.FPUtil.fp_bits
+)
+
 add_fp_unittest(
   scalbnf128_test
   SUITE
diff --git a/libc/test/src/math/smoke/scalbnf16_test.cpp b/libc/test/src/math/smoke/scalbnf16_test.cpp
new file mode 100644
index 0000000000000..407cad5e7fabd
--- /dev/null
+++ b/libc/test/src/math/smoke/scalbnf16_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for scalbnf16 -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ScalbnTest.h"
+
+#include "src/math/scalbnf16.h"
+
+LIST_SCALBN_TESTS(float16, LIBC_NAMESPACE::scalbnf16)

>From 4541c4c7b21bb8964d789da97d5933eb18b7e753 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Fri, 7 Jun 2024 21:51:02 +0200
Subject: [PATCH 3/5] [libc][math][c23] Add scalblnf16 C23 math function

---
 libc/config/linux/aarch64/entrypoints.txt     |  1 +
 libc/config/linux/x86_64/entrypoints.txt      |  1 +
 libc/docs/math/index.rst                      |  2 ++
 libc/spec/stdc.td                             |  2 ++
 .../__support/FPUtil/ManipulationFunctions.h  |  6 +++--
 libc/src/math/CMakeLists.txt                  |  2 ++
 libc/src/math/generic/CMakeLists.txt          | 14 +++++++++++
 libc/src/math/generic/scalblnf16.cpp          | 25 +++++++++++++++++++
 libc/src/math/scalblnf16.h                    | 20 +++++++++++++++
 libc/test/src/math/smoke/CMakeLists.txt       | 13 ++++++++++
 libc/test/src/math/smoke/LdExpTest.h          | 17 ++++++++++---
 libc/test/src/math/smoke/ScalbnTest.h         |  4 +--
 libc/test/src/math/smoke/scalblnf16_test.cpp  | 13 ++++++++++
 libc/test/src/math/smoke/scalbn_test.cpp      |  2 +-
 libc/test/src/math/smoke/scalbnf128_test.cpp  |  2 +-
 libc/test/src/math/smoke/scalbnf16_test.cpp   |  2 +-
 libc/test/src/math/smoke/scalbnf_test.cpp     |  2 +-
 libc/test/src/math/smoke/scalbnl_test.cpp     |  2 +-
 18 files changed, 118 insertions(+), 12 deletions(-)
 create mode 100644 libc/src/math/generic/scalblnf16.cpp
 create mode 100644 libc/src/math/scalblnf16.h
 create mode 100644 libc/test/src/math/smoke/scalblnf16_test.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index ba2c8c76b5c13..63238ec0094fb 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -546,6 +546,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.rintf16
     libc.src.math.roundf16
     libc.src.math.roundevenf16
+    libc.src.math.scalblnf16
     libc.src.math.scalbnf16
     libc.src.math.setpayloadf16
     libc.src.math.setpayloadsigf16
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 6a75ec9d2719a..ac170bf7b3da3 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -576,6 +576,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.rintf16
     libc.src.math.roundf16
     libc.src.math.roundevenf16
+    libc.src.math.scalblnf16
     libc.src.math.scalbnf16
     libc.src.math.setpayloadf16
     libc.src.math.setpayloadsigf16
diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst
index d44037bfeedea..d6e642c4907f0 100644
--- a/libc/docs/math/index.rst
+++ b/libc/docs/math/index.rst
@@ -212,6 +212,8 @@ Basic Operations
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | roundeven        | |check|          | |check|         | |check|                | |check|              | |check|                | 7.12.9.8               | F.10.6.8                   |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
+| scalbln          |                  |                 |                        | |check|              |                        | 7.12.6.19              | F.10.3.19                  |
++------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | scalbn           | |check|          | |check|         | |check|                | |check|              | |check|                | 7.12.6.19              | F.10.3.19                  |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | setpayload       |                  |                 |                        | |check|              |                        | F.10.13.2              | N/A                        |
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 803cda1b09b69..73d00c3e33aa9 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -696,6 +696,8 @@ def StdC : StandardSpec<"stdc"> {
           FunctionSpec<"asinhf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
           FunctionSpec<"atanhf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
 
+          GuardedFunctionSpec<"scalblnf16", RetValSpec<Float16Type>, [ArgSpec<Float16Type>, ArgSpec<LongType>], "LIBC_TYPES_HAS_FLOAT16">,
+
           FunctionSpec<"scalbn", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntType>]>,
           FunctionSpec<"scalbnf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntType>]>,
           FunctionSpec<"scalbnl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>]>,
diff --git a/libc/src/__support/FPUtil/ManipulationFunctions.h b/libc/src/__support/FPUtil/ManipulationFunctions.h
index 11ea6e3738d28..a9c64122d9311 100644
--- a/libc/src/__support/FPUtil/ManipulationFunctions.h
+++ b/libc/src/__support/FPUtil/ManipulationFunctions.h
@@ -143,7 +143,7 @@ LIBC_INLINE constexpr T logb(T x) {
 }
 
 template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
-LIBC_INLINE constexpr T ldexp(T x, int exp) {
+LIBC_INLINE constexpr T ldexp(T x, long exp) {
   FPBits<T> bits(x);
   if (LIBC_UNLIKELY((exp == 0) || bits.is_zero() || bits.is_inf_or_nan()))
     return x;
@@ -186,7 +186,9 @@ LIBC_INLINE constexpr T ldexp(T x, int exp) {
 
   // For all other values, NormalFloat to T conversion handles it the right way.
   DyadicFloat<cpp::max(FPBits<T>::STORAGE_LEN, 32)> normal(bits.get_val());
-  normal.exponent += exp;
+  // Make sure that exp fits into an int when not taking the fast paths above.
+  static_assert(EXP_LIMIT <= INT_MAX && -EXP_LIMIT >= INT_MIN);
+  normal.exponent += static_cast<int>(exp);
   return static_cast<T>(normal);
 }
 
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index 34cb3dbfb6655..a921939ea806c 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -348,6 +348,8 @@ add_math_entrypoint_object(roundevenl)
 add_math_entrypoint_object(roundevenf16)
 add_math_entrypoint_object(roundevenf128)
 
+add_math_entrypoint_object(scalblnf16)
+
 add_math_entrypoint_object(scalbn)
 add_math_entrypoint_object(scalbnf)
 add_math_entrypoint_object(scalbnl)
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index c7de6d2921e38..846ad2fae8d11 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -3514,6 +3514,20 @@ add_entrypoint_object(
     libc.src.__support.macros.optimization
 )
 
+add_entrypoint_object(
+  scalblnf16
+  SRCS
+    scalblnf16.cpp
+  HDRS
+    ../scalblnf16.h
+  DEPENDS
+    libc.hdr.float_macros
+    libc.src.__support.macros.properties.types
+    libc.src.__support.FPUtil.manipulation_functions
+  COMPILE_OPTIONS
+    -O3
+)
+
 add_entrypoint_object(
   scalbn
   SRCS
diff --git a/libc/src/math/generic/scalblnf16.cpp b/libc/src/math/generic/scalblnf16.cpp
new file mode 100644
index 0000000000000..844a071d754a6
--- /dev/null
+++ b/libc/src/math/generic/scalblnf16.cpp
@@ -0,0 +1,25 @@
+//===-- Implementation of scalblnf16 function -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/scalblnf16.h"
+#include "src/__support/FPUtil/ManipulationFunctions.h"
+#include "src/__support/common.h"
+
+#include "hdr/float_macros.h"
+
+#if FLT_RADIX != 2
+#error "FLT_RADIX != 2 is not supported."
+#endif
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(float16, scalblnf16, (float16 x, long n)) {
+  return fputil::ldexp(x, n);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/math/scalblnf16.h b/libc/src/math/scalblnf16.h
new file mode 100644
index 0000000000000..be93fab1bf68a
--- /dev/null
+++ b/libc/src/math/scalblnf16.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for scalblnf16 --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_SCALBLNF16_H
+#define LLVM_LIBC_SRC_MATH_SCALBLNF16_H
+
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE {
+
+float16 scalblnf16(float16 x, long n);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_SCALBLNF16_H
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index ef5ed27369068..8cae52fb0cebe 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -3470,6 +3470,19 @@ add_fp_unittest(
     libc.src.__support.FPUtil.fp_bits
 )
 
+add_fp_unittest(
+  scalblnf16_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    scalblnf16_test.cpp
+  HDRS
+    ScalbnTest.h
+  DEPENDS
+    libc.src.math.scalblnf16
+    libc.src.__support.FPUtil.fp_bits
+)
+
 add_fp_unittest(
   scalbn_test
   SUITE
diff --git a/libc/test/src/math/smoke/LdExpTest.h b/libc/test/src/math/smoke/LdExpTest.h
index 19c02d2dc7d0f..231535a9a505e 100644
--- a/libc/test/src/math/smoke/LdExpTest.h
+++ b/libc/test/src/math/smoke/LdExpTest.h
@@ -18,7 +18,7 @@
 
 #include <stdint.h>
 
-template <typename T>
+template <typename T, typename U = int>
 class LdExpTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
   using NormalFloat = LIBC_NAMESPACE::fputil::NormalFloat<T>;
@@ -34,10 +34,10 @@ class LdExpTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   static constexpr StorageType MANTISSA = NormalFloat::ONE + 0x123;
 
 public:
-  typedef T (*LdExpFunc)(T, int);
+  typedef T (*LdExpFunc)(T, U);
 
   void testSpecialNumbers(LdExpFunc func) {
-    int exp_array[5] = {-INT_MAX - 1, -10, 0, 10, INT_MAX};
+    int exp_array[5] = {INT_MIN, -10, 0, 10, INT_MAX};
     for (int exp : exp_array) {
       ASSERT_FP_EQ(zero, func(zero, exp));
       ASSERT_FP_EQ(neg_zero, func(neg_zero, exp));
@@ -45,6 +45,17 @@ class LdExpTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
       ASSERT_FP_EQ(neg_inf, func(neg_inf, exp));
       ASSERT_FP_EQ(nan, func(nan, exp));
     }
+
+    if constexpr (sizeof(U) < sizeof(long) || sizeof(long) == sizeof(int))
+      return;
+    long long_exp_array[4] = {LONG_MIN, INT_MIN - 1L, INT_MAX + 1L, LONG_MAX};
+    for (long exp : long_exp_array) {
+      ASSERT_FP_EQ(zero, func(zero, exp));
+      ASSERT_FP_EQ(neg_zero, func(neg_zero, exp));
+      ASSERT_FP_EQ(inf, func(inf, exp));
+      ASSERT_FP_EQ(neg_inf, func(neg_inf, exp));
+      ASSERT_FP_EQ(nan, func(nan, exp));
+    }
   }
 
   void testPowersOfTwo(LdExpFunc func) {
diff --git a/libc/test/src/math/smoke/ScalbnTest.h b/libc/test/src/math/smoke/ScalbnTest.h
index e1d035c4ea3aa..67ea30f9f0df6 100644
--- a/libc/test/src/math/smoke/ScalbnTest.h
+++ b/libc/test/src/math/smoke/ScalbnTest.h
@@ -12,8 +12,8 @@
 #include "LdExpTest.h"
 #include "test/UnitTest/Test.h"
 
-#define LIST_SCALBN_TESTS(T, func)                                             \
-  using LlvmLibcScalbnTest = LdExpTestTemplate<T>;                             \
+#define LIST_SCALBN_TESTS(T, U, func)                                          \
+  using LlvmLibcScalbnTest = LdExpTestTemplate<T, U>;                          \
   TEST_F(LlvmLibcScalbnTest, SpecialNumbers) { testSpecialNumbers(&func); }    \
   TEST_F(LlvmLibcScalbnTest, PowersOfTwo) { testPowersOfTwo(&func); }          \
   TEST_F(LlvmLibcScalbnTest, OverFlow) { testOverflow(&func); }                \
diff --git a/libc/test/src/math/smoke/scalblnf16_test.cpp b/libc/test/src/math/smoke/scalblnf16_test.cpp
new file mode 100644
index 0000000000000..a678254292901
--- /dev/null
+++ b/libc/test/src/math/smoke/scalblnf16_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for scalblnf16 ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ScalbnTest.h"
+
+#include "src/math/scalblnf16.h"
+
+LIST_SCALBN_TESTS(float16, long, LIBC_NAMESPACE::scalblnf16)
diff --git a/libc/test/src/math/smoke/scalbn_test.cpp b/libc/test/src/math/smoke/scalbn_test.cpp
index 413a2395ca3c5..86ad71b01c2bb 100644
--- a/libc/test/src/math/smoke/scalbn_test.cpp
+++ b/libc/test/src/math/smoke/scalbn_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/scalbn.h"
 
-LIST_SCALBN_TESTS(double, LIBC_NAMESPACE::scalbn)
+LIST_SCALBN_TESTS(double, int, LIBC_NAMESPACE::scalbn)
diff --git a/libc/test/src/math/smoke/scalbnf128_test.cpp b/libc/test/src/math/smoke/scalbnf128_test.cpp
index dc259de211489..b42902a76a228 100644
--- a/libc/test/src/math/smoke/scalbnf128_test.cpp
+++ b/libc/test/src/math/smoke/scalbnf128_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/scalbnf128.h"
 
-LIST_SCALBN_TESTS(float128, LIBC_NAMESPACE::scalbnf128)
+LIST_SCALBN_TESTS(float128, int, LIBC_NAMESPACE::scalbnf128)
diff --git a/libc/test/src/math/smoke/scalbnf16_test.cpp b/libc/test/src/math/smoke/scalbnf16_test.cpp
index 407cad5e7fabd..9cee0d04780e5 100644
--- a/libc/test/src/math/smoke/scalbnf16_test.cpp
+++ b/libc/test/src/math/smoke/scalbnf16_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/scalbnf16.h"
 
-LIST_SCALBN_TESTS(float16, LIBC_NAMESPACE::scalbnf16)
+LIST_SCALBN_TESTS(float16, int, LIBC_NAMESPACE::scalbnf16)
diff --git a/libc/test/src/math/smoke/scalbnf_test.cpp b/libc/test/src/math/smoke/scalbnf_test.cpp
index e97781c2b2354..b25db4e8175e9 100644
--- a/libc/test/src/math/smoke/scalbnf_test.cpp
+++ b/libc/test/src/math/smoke/scalbnf_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/scalbnf.h"
 
-LIST_SCALBN_TESTS(float, LIBC_NAMESPACE::scalbnf)
+LIST_SCALBN_TESTS(float, int, LIBC_NAMESPACE::scalbnf)
diff --git a/libc/test/src/math/smoke/scalbnl_test.cpp b/libc/test/src/math/smoke/scalbnl_test.cpp
index b0e0053790902..838b0650c5ad9 100644
--- a/libc/test/src/math/smoke/scalbnl_test.cpp
+++ b/libc/test/src/math/smoke/scalbnl_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/scalbnl.h"
 
-LIST_SCALBN_TESTS(long double, LIBC_NAMESPACE::scalbnl)
+LIST_SCALBN_TESTS(long double, int, LIBC_NAMESPACE::scalbnl)

>From 4e4a9e15de56433f96ffd7d21cd2ffb3af27a610 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Thu, 20 Jun 2024 16:36:26 +0200
Subject: [PATCH 4/5] fixup! [libc][math][c23] Add ldexpf16 C23 math function

---
 .../__support/FPUtil/ManipulationFunctions.h  | 12 ++++----
 libc/src/__support/FPUtil/dyadic_float.h      | 29 ++++++++++---------
 libc/src/__support/big_int.h                  |  3 +-
 libc/src/math/generic/CMakeLists.txt          |  2 +-
 libc/test/src/math/smoke/LdExpTest.h          |  2 +-
 5 files changed, 27 insertions(+), 21 deletions(-)

diff --git a/libc/src/__support/FPUtil/ManipulationFunctions.h b/libc/src/__support/FPUtil/ManipulationFunctions.h
index a9c64122d9311..97c43126a71a3 100644
--- a/libc/src/__support/FPUtil/ManipulationFunctions.h
+++ b/libc/src/__support/FPUtil/ManipulationFunctions.h
@@ -142,8 +142,10 @@ LIBC_INLINE constexpr T logb(T x) {
   return static_cast<T>(normal.get_unbiased_exponent());
 }
 
-template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
-LIBC_INLINE constexpr T ldexp(T x, long exp) {
+template <typename T, typename U>
+LIBC_INLINE constexpr cpp::enable_if_t<
+    cpp::is_floating_point_v<T> && cpp::is_integral_v<U>, T>
+ldexp(T x, U exp) {
   FPBits<T> bits(x);
   if (LIBC_UNLIKELY((exp == 0) || bits.is_zero() || bits.is_inf_or_nan()))
     return x;
@@ -156,6 +158,8 @@ LIBC_INLINE constexpr T ldexp(T x, long exp) {
   // calculating the limit.
   constexpr int EXP_LIMIT =
       FPBits<T>::MAX_BIASED_EXPONENT + FPBits<T>::FRACTION_LEN + 1;
+  // Make sure that we can safely cast exp to int when not returning early.
+  static_assert(EXP_LIMIT <= INT_MAX && -EXP_LIMIT >= INT_MIN);
   if (LIBC_UNLIKELY(exp > EXP_LIMIT)) {
     int rounding_mode = quick_get_round();
     Sign sign = bits.sign();
@@ -185,9 +189,7 @@ LIBC_INLINE constexpr T ldexp(T x, long exp) {
   }
 
   // For all other values, NormalFloat to T conversion handles it the right way.
-  DyadicFloat<cpp::max(FPBits<T>::STORAGE_LEN, 32)> normal(bits.get_val());
-  // Make sure that exp fits into an int when not taking the fast paths above.
-  static_assert(EXP_LIMIT <= INT_MAX && -EXP_LIMIT >= INT_MIN);
+  DyadicFloat<FPBits<T>::STORAGE_LEN> normal(bits.get_val());
   normal.exponent += static_cast<int>(exp);
   return static_cast<T>(normal);
 }
diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h
index f1791f9da56ad..63cb98351201f 100644
--- a/libc/src/__support/FPUtil/dyadic_float.h
+++ b/libc/src/__support/FPUtil/dyadic_float.h
@@ -14,7 +14,6 @@
 #include "src/__support/CPP/type_traits.h"
 #include "src/__support/big_int.h"
 #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
-#include "src/__support/macros/properties/types.h" // float16
 
 #include <stddef.h>
 
@@ -127,7 +126,7 @@ template <size_t Bits> struct DyadicFloat {
         shift >= MantissaType::BITS ? MantissaType(0) : mantissa >> shift;
 
     T d_hi = FPBits<T>::create_value(
-                 sign, exp_hi,
+                 sign, static_cast<output_bits_t>(exp_hi),
                  (static_cast<output_bits_t>(m_hi) & FPBits<T>::SIG_MASK) |
                      IMPLICIT_MASK)
                  .get_val();
@@ -144,25 +143,32 @@ template <size_t Bits> struct DyadicFloat {
 
     if (LIBC_UNLIKELY(exp_lo <= 0)) {
       // d_lo is denormal, but the output is normal.
-      int scale_up_exponent = 2 * PRECISION;
+      int scale_up_exponent = 1 - exp_lo;
       T scale_up_factor =
-          FPBits<T>::create_value(sign, FPBits<T>::EXP_BIAS + scale_up_exponent,
+          FPBits<T>::create_value(sign,
+                                  static_cast<output_bits_t>(
+                                      FPBits<T>::EXP_BIAS + scale_up_exponent),
                                   IMPLICIT_MASK)
               .get_val();
       T scale_down_factor =
-          FPBits<T>::create_value(sign, FPBits<T>::EXP_BIAS - scale_up_exponent,
+          FPBits<T>::create_value(sign,
+                                  static_cast<output_bits_t>(
+                                      FPBits<T>::EXP_BIAS - scale_up_exponent),
                                   IMPLICIT_MASK)
               .get_val();
 
-      d_lo = FPBits<T>::create_value(sign, exp_lo + scale_up_exponent,
-                                     IMPLICIT_MASK)
+      d_lo = FPBits<T>::create_value(
+                 sign, static_cast<output_bits_t>(exp_lo + scale_up_exponent),
+                 IMPLICIT_MASK)
                  .get_val();
 
       return multiply_add(d_lo, T(round_and_sticky), d_hi * scale_up_factor) *
              scale_down_factor;
     }
 
-    d_lo = FPBits<T>::create_value(sign, exp_lo, IMPLICIT_MASK).get_val();
+    d_lo = FPBits<T>::create_value(sign, static_cast<output_bits_t>(exp_lo),
+                                   IMPLICIT_MASK)
+               .get_val();
 
     // Still correct without FMA instructions if `d_lo` is not underflow.
     T r = multiply_add(d_lo, T(round_and_sticky), d_hi);
@@ -170,7 +176,8 @@ template <size_t Bits> struct DyadicFloat {
     if (LIBC_UNLIKELY(denorm)) {
       // Exponent before rounding is in denormal range, simply clear the
       // exponent field.
-      output_bits_t clear_exp = (output_bits_t(exp_hi) << FPBits<T>::SIG_LEN);
+      output_bits_t clear_exp = static_cast<output_bits_t>(
+          output_bits_t(exp_hi) << FPBits<T>::SIG_LEN);
       output_bits_t r_bits = FPBits<T>(r).uintval() - clear_exp;
       if (!(r_bits & FPBits<T>::EXP_MASK)) {
         // Output is denormal after rounding, clear the implicit bit for 80-bit
@@ -184,10 +191,6 @@ template <size_t Bits> struct DyadicFloat {
     return r;
   }
 
-  LIBC_INLINE explicit constexpr operator float16() const {
-    return static_cast<float16>(static_cast<float>(*this));
-  }
-
   LIBC_INLINE explicit constexpr operator MantissaType() const {
     if (mantissa.is_zero())
       return 0;
diff --git a/libc/src/__support/big_int.h b/libc/src/__support/big_int.h
index c30c3ece54a30..5ce9541d73f68 100644
--- a/libc/src/__support/big_int.h
+++ b/libc/src/__support/big_int.h
@@ -302,7 +302,8 @@ LIBC_INLINE constexpr cpp::array<word, N> shift(cpp::array<word, N> array,
       dst = static_cast<word>((part1 << bit_offset) |
                               (part2 >> (WORD_BITS - bit_offset)));
     else
-      dst = (part1 >> bit_offset) | (part2 << (WORD_BITS - bit_offset));
+      dst = static_cast<word>((part1 >> bit_offset) |
+                              (part2 << (WORD_BITS - bit_offset)));
   }
   return out;
 }
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 846ad2fae8d11..a0114aafcad39 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -1494,7 +1494,7 @@ add_entrypoint_object(
   HDRS
     ../ldexpf16.h
   COMPILE_OPTIONS
-    -O0 -ggdb3
+    -O3
   DEPENDS
     libc.src.__support.macros.properties.types
     libc.src.__support.FPUtil.manipulation_functions
diff --git a/libc/test/src/math/smoke/LdExpTest.h b/libc/test/src/math/smoke/LdExpTest.h
index 231535a9a505e..7739bd71e5e7a 100644
--- a/libc/test/src/math/smoke/LdExpTest.h
+++ b/libc/test/src/math/smoke/LdExpTest.h
@@ -71,7 +71,7 @@ class LdExpTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
 
   void testOverflow(LdExpFunc func) {
     NormalFloat x(Sign::POS, FPBits::MAX_BIASED_EXPONENT - 10,
-                  NormalFloat::ONE + 0xF00);
+                  NormalFloat::ONE + 0xFB);
     for (int32_t exp = 10; exp < 100; ++exp) {
       ASSERT_FP_EQ(inf, func(T(x), exp));
       ASSERT_FP_EQ(neg_inf, func(-T(x), exp));

>From 33952e56b209287003146172c77e5ebfcad4b130 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Thu, 20 Jun 2024 16:39:18 +0200
Subject: [PATCH 5/5] fixup! [libc][math][c23] Add ldexpf16 C23 math function

Update dyadic_float dependencies.
---
 libc/src/__support/FPUtil/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt
index 01ca4254c7996..4ede74206e973 100644
--- a/libc/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/CMakeLists.txt
@@ -201,8 +201,8 @@ add_header_library(
   DEPENDS
     .fp_bits
     .multiply_add
+    libc.src.__support.CPP.type_traits
     libc.src.__support.big_int
-    libc.src.__support.common
     libc.src.__support.macros.optimization
 )
 



More information about the libc-commits mailing list