[libc-commits] [libc] [llvm] [libc][math][c23] Add exp10bf16 math function (PR #193299)

via libc-commits libc-commits at lists.llvm.org
Tue Jun 9 07:12:00 PDT 2026


https://github.com/ProfessionalMenace updated https://github.com/llvm/llvm-project/pull/193299

>From 635a9bd7dd774310f8c2964185f443cd664e5e96 Mon Sep 17 00:00:00 2001
From: ProfessionalMenace <vondracekadam00 at gmail.com>
Date: Fri, 17 Apr 2026 02:40:29 +0200
Subject: [PATCH 1/5] exp10bf16

---
 libc/config/baremetal/aarch64/entrypoints.txt |   1 +
 libc/config/baremetal/arm/entrypoints.txt     |   1 +
 libc/config/baremetal/riscv/entrypoints.txt   |   1 +
 libc/config/darwin/aarch64/entrypoints.txt    |   1 +
 libc/config/darwin/x86_64/entrypoints.txt     |   1 +
 libc/config/gpu/amdgpu/entrypoints.txt        |   1 +
 libc/config/gpu/nvptx/entrypoints.txt         |   1 +
 libc/config/linux/aarch64/entrypoints.txt     |   1 +
 libc/config/linux/arm/entrypoints.txt         |   1 +
 libc/config/linux/riscv/entrypoints.txt       |   1 +
 libc/config/linux/x86_64/entrypoints.txt      |   1 +
 libc/config/windows/entrypoints.txt           |   1 +
 libc/docs/headers/math/index.rst              |   2 +-
 libc/shared/math.h                            |   1 +
 libc/shared/math/exp10bf16.h                  |  23 +++
 libc/src/__support/math/CMakeLists.txt        |  15 ++
 libc/src/__support/math/exp10bf16.h           | 147 ++++++++++++++++++
 libc/src/math/CMakeLists.txt                  |   1 +
 libc/src/math/exp10bf16.h                     |  21 +++
 libc/src/math/generic/CMakeLists.txt          |  10 ++
 libc/src/math/generic/exp10bf16.cpp           |  18 +++
 libc/test/shared/CMakeLists.txt               |   1 +
 libc/test/shared/shared_math_test.cpp         |   1 +
 libc/test/src/math/CMakeLists.txt             |  12 ++
 libc/test/src/math/exp10bf16_test.cpp         |  39 +++++
 libc/test/src/math/smoke/CMakeLists.txt       |  13 ++
 libc/test/src/math/smoke/exp10bf16_test.cpp   |  39 +++++
 27 files changed, 354 insertions(+), 1 deletion(-)
 create mode 100644 libc/shared/math/exp10bf16.h
 create mode 100644 libc/src/__support/math/exp10bf16.h
 create mode 100644 libc/src/math/exp10bf16.h
 create mode 100644 libc/src/math/generic/exp10bf16.cpp
 create mode 100644 libc/test/src/math/exp10bf16_test.cpp
 create mode 100644 libc/test/src/math/smoke/exp10bf16_test.cpp

diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt
index 737e02142e134..45d9506d1908a 100644
--- a/libc/config/baremetal/aarch64/entrypoints.txt
+++ b/libc/config/baremetal/aarch64/entrypoints.txt
@@ -814,6 +814,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.exp10bf16
   libc.src.math.fabsbf16
   libc.src.math.fdimbf16
   libc.src.math.floorbf16
diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index 56f2a370ce7fe..dfb15d5ae9e1d 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -825,6 +825,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.exp10bf16
   libc.src.math.fabsbf16
   libc.src.math.fdimbf16
   libc.src.math.floorbf16
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index 812bbd1a2dc14..42d0c4e7f90d2 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -822,6 +822,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.exp10bf16
   libc.src.math.fabsbf16
   libc.src.math.fdimbf16
   libc.src.math.floorbf16
diff --git a/libc/config/darwin/aarch64/entrypoints.txt b/libc/config/darwin/aarch64/entrypoints.txt
index 8a593569736a3..8dc6ce29e9c92 100644
--- a/libc/config/darwin/aarch64/entrypoints.txt
+++ b/libc/config/darwin/aarch64/entrypoints.txt
@@ -635,6 +635,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.exp10bf16
   libc.src.math.fabsbf16
   libc.src.math.fdimbf16
   libc.src.math.floorbf16
diff --git a/libc/config/darwin/x86_64/entrypoints.txt b/libc/config/darwin/x86_64/entrypoints.txt
index d35700d341d1a..4129d58f53418 100644
--- a/libc/config/darwin/x86_64/entrypoints.txt
+++ b/libc/config/darwin/x86_64/entrypoints.txt
@@ -256,6 +256,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.exp10bf16
   libc.src.math.fabsbf16
   libc.src.math.fdimbf16
   libc.src.math.floorbf16
diff --git a/libc/config/gpu/amdgpu/entrypoints.txt b/libc/config/gpu/amdgpu/entrypoints.txt
index 0e57c46051751..d63ef3283d097 100644
--- a/libc/config/gpu/amdgpu/entrypoints.txt
+++ b/libc/config/gpu/amdgpu/entrypoints.txt
@@ -663,6 +663,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.exp10bf16
   libc.src.math.fabsbf16
   libc.src.math.fdimbf16
   libc.src.math.floorbf16
diff --git a/libc/config/gpu/nvptx/entrypoints.txt b/libc/config/gpu/nvptx/entrypoints.txt
index 5b2a402e7c806..9fd7ea6a98c68 100644
--- a/libc/config/gpu/nvptx/entrypoints.txt
+++ b/libc/config/gpu/nvptx/entrypoints.txt
@@ -665,6 +665,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.exp10bf16
   libc.src.math.fabsbf16
   libc.src.math.fdimbf16
   libc.src.math.floorbf16
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index bc2055db769ab..6ce51cce91674 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -929,6 +929,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.exp10bf16
   libc.src.math.fabsbf16
   libc.src.math.fdimbf16
   libc.src.math.floorbf16
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index c4ac53c4925a3..3e19b44b60038 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -504,6 +504,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.exp10bf16
   libc.src.math.fabsbf16
   libc.src.math.fdimbf16
   libc.src.math.floorbf16
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 641125a61e22e..9c448b5c7676b 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -950,6 +950,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.exp10bf16
   libc.src.math.fabsbf16
   libc.src.math.fdimbf16
   libc.src.math.floorbf16
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index b6c79cd2b6c8b..755afe6ba63f1 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1017,6 +1017,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.exp10bf16
   libc.src.math.fabsbf16
   libc.src.math.fdimbf16
   libc.src.math.floorbf16
diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index d7f66dc58e4db..90fde854c4ac0 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -346,6 +346,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.exp10bf16
   libc.src.math.fabsbf16
   libc.src.math.fdimbf16
   libc.src.math.floorbf16
diff --git a/libc/docs/headers/math/index.rst b/libc/docs/headers/math/index.rst
index a2b7f51da99a1..879400d713b81 100644
--- a/libc/docs/headers/math/index.rst
+++ b/libc/docs/headers/math/index.rst
@@ -297,7 +297,7 @@ Higher Math Functions
 +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+
 | exp       | |check|          | |check|         |                        | |check|              |                        |                        | 7.12.6.1               | F.10.3.1                   |
 +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+
-| exp10     | |check|          | |check|         |                        | |check|              |                        |                        | 7.12.6.2               | F.10.3.2                   |
+| exp10     | |check|          | |check|         |                        | |check|              | |check|                |                        | 7.12.6.2               | F.10.3.2                   |
 +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+
 | exp10m1   | |check|          |                 |                        | |check|              |                        |                        | 7.12.6.3               | F.10.3.3                   |
 +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+
diff --git a/libc/shared/math.h b/libc/shared/math.h
index 49d167afe4ba9..1cf5b942bc180 100644
--- a/libc/shared/math.h
+++ b/libc/shared/math.h
@@ -104,6 +104,7 @@
 #include "math/erff16.h"
 #include "math/exp.h"
 #include "math/exp10.h"
+#include "math/exp10bf16.h"
 #include "math/exp10f.h"
 #include "math/exp10f16.h"
 #include "math/exp10m1f.h"
diff --git a/libc/shared/math/exp10bf16.h b/libc/shared/math/exp10bf16.h
new file mode 100644
index 0000000000000..ba6fd984a0312
--- /dev/null
+++ b/libc/shared/math/exp10bf16.h
@@ -0,0 +1,23 @@
+//===-- Shared exp10bf16 function --------------------------------*- 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_SHARED_MATH_EXP10BF16_H
+#define LLVM_LIBC_SHARED_MATH_EXP10BF16_H
+
+#include "shared/libc_common.h"
+#include "src/__support/math/exp10bf16.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace shared {
+
+using math::exp10bf16;
+
+} // namespace shared
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SHARED_MATH_EXP10BF16_H
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index cce07c31d2d29..ca4223a99dd14 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -2956,6 +2956,21 @@ add_header_library(
     libc.src.__support.macros.config
 )
 
+add_header_library(
+  exp10bf16
+  HDRS
+    exp10bf16.h
+  DEPENDS
+    libc.src.__support.FPUtil.cast
+    libc.src.__support.FPUtil.bfloat16
+    libc.src.__support.FPUtil.fenv_impl
+    libc.src.__support.FPUtil.fp_bits
+    libc.src.__support.FPUtil.manipulation_functions
+    libc.src.__support.FPUtil.polyeval
+    libc.src.__support.FPUtil.multiply_add
+    libc.src.__support.macros.optimization
+)
+
 add_header_library(
   exp10m1f
   HDRS
diff --git a/libc/src/__support/math/exp10bf16.h b/libc/src/__support/math/exp10bf16.h
new file mode 100644
index 0000000000000..2820bb5be74e7
--- /dev/null
+++ b/libc/src/__support/math/exp10bf16.h
@@ -0,0 +1,147 @@
+//===-- Implementation header for exp10bf16 ---------------------*- 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___SUPPORT_MATH_EXP10BF16_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP10BF16_H
+
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/ManipulationFunctions.h"
+#include "src/__support/FPUtil/PolyEval.h"
+#include "src/__support/FPUtil/bfloat16.h"
+#include "src/__support/FPUtil/cast.h"
+#include "src/__support/FPUtil/except_value_utils.h"
+#include "src/__support/FPUtil/nearest_integer.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/optimization.h"
+
+// This is an algorithm for exp10(x) in bfloat16 which is correctly rounded for
+// all rounding modes, based on the implementation of exp10bf16(x)
+// from the RLIBM project at: https://people.cs.rutgers.edu/~sn349/rlibm
+
+// Step 1 - Range reduction of edge cases:
+// Find the largest value x for which exp10bf16(x) = +0.0
+// x < log10(min subnormal bfloat16)
+// Find the smallest value x for which exp10bf16(x) = +INF
+// x > log10(max normal bfloat16)
+
+// Step 2 - Range reduction to subnormal range:
+// exp10(x) = exp2(x * log2(10)) and further decompose x * log2(10) into
+// sum of two parts - closest integer i and a fraction f
+// exp10(x) = exp2(x * log2(10)) = exp2(i + f) = exp2(i) * exp2(f)
+
+// Step 4 - Polynomial approximation:
+// Approximate the range reduced function exp2(f) on a domain (-0.5, 0.5)
+// using a fourth degree polynomial P
+// Generated by Sollya with the following command:
+// > display = hexadecimal;
+// > exp2 = 2^x;
+// > I = [-0.5, 0.5];
+// > P = fpminimax(exp2, 4, [|1, SG...|], I);
+// > E = infnorm(exp2 - P, I);
+
+// Step 4 - Output compensation:
+// exp10(x) = exp2(i) * P(f)
+
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
+
+// Generated by Sollya with the following command:
+// round(log2(10), SG, RN);
+LIBC_INLINE_VAR constexpr float LOG2F_10 = 0x1.a934fp1;
+
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+constexpr fputil::ExceptValues<bfloat16, 4> EXP10BF16_EXCEPTS{
+    {// {inputs, RZ output, RU offset, RD offset, RN offset}
+     // x = -0x1.6ep-7, exp10bf16(x) = 0x1.f2p-1 (RN)
+     {0xBC37U, 0x3F79U, 1U, 0U, 0U},
+     // x = -0x1.2ap-6, exp10bf16(x) = 0x1.eap-1 (RN)
+     {0xBC95U, 0x3F75U, 1U, 0U, 0U},
+     // x = -0x1.74p-3, exp10bf16(x) = 0x1.5p-1 (RN)
+     {0xBE3AU, 0x3F28U, 1U, 0U, 0U},
+     // x = -0x1.44p-1, exp10bf16(x) = 0x1.dcp-3 (RN)
+     {0xBF22U, 0x3E6EU, 1U, 0U, 0U}}};
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+LIBC_INLINE constexpr bfloat16 exp10bf16(bfloat16 x) {
+  using FPBits = typename fputil::FPBits<bfloat16>;
+  FPBits x_bits(x);
+
+  uint16_t x_u = x_bits.uintval();
+
+  // special case where exp10bf16(NaN) = NaN
+  if (LIBC_UNLIKELY(x_bits.is_nan())) {
+    if (x_bits.is_signaling_nan()) {
+      fputil::raise_except_if_required(FE_INVALID);
+      return FPBits::quiet_nan().get_val();
+    }
+    return x;
+  }
+
+  // exp10bf16(x) = +0.0
+  if (x_bits.is_neg() && x_u >= 0xc222U) { // x <= -0x1.44p+5
+    return FPBits::zero().get_val();
+  }
+
+  // exp10bf16(x) = +INF
+  if (x_bits.is_pos() && x_u >= 0x421bU) { // x >= 0x1.36p+5
+    if (x_bits.is_inf()) {
+      return FPBits::inf().get_val();
+    }
+
+    switch (fputil::quick_get_round()) {
+    case FE_TONEAREST:
+    case FE_UPWARD:
+      fputil::set_errno_if_required(ERANGE);
+      fputil::raise_except_if_required(FE_OVERFLOW);
+      return FPBits::inf().get_val();
+    default:
+      return FPBits::max_normal().get_val();
+    }
+  }
+
+  // Hard-to-round cases with exact results
+  if (LIBC_UNLIKELY((x_u & ~(0x3F80U | 0x4000U | 0x4040U)) == 0)) {
+    switch (x_u) {
+    case 0x3F80U: // x = 1.0
+      return fputil::cast<bfloat16>(10.0);
+    case 0x4000U: // x = 2.0
+      return fputil::cast<bfloat16>(100.0);
+    case 0x4040U: // x = 3.0
+      return fputil::cast<bfloat16>(1'000.0);
+    }
+  }
+
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+  if (auto r = EXP10BF16_EXCEPTS.lookup(x_u); LIBC_UNLIKELY(r.has_value())) {
+    return r.value();
+  }
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+  // x * log2(10)
+  float xscaled = fputil::cast<bfloat16>(x) * LOG2F_10;
+
+  // range reduction to (-0.5, 0.5)
+  float intPart = fputil::nearest_integer(xscaled);
+  float fracPart = xscaled - intPart;
+
+  // polynomial approximation of exp2(x) on (-0.5, 0.5)
+  float poly = fputil::polyeval(fracPart,
+                                0x1p0f, // Exp2(0) = Exp10(0) = 1
+                                0x1.62e0dep-1f, 0x1.ec00d6p-3f, 0x1.ca13dcp-5f,
+                                0x1.3ac75ep-7f);
+
+  // output compensation
+  float result = fputil::ldexp(poly, static_cast<int>(intPart));
+  return fputil::cast<bfloat16>(result);
+}
+
+} // namespace math
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP10BF16_H
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index 3ed9501d60a5b..a989fce387538 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -161,6 +161,7 @@ add_math_entrypoint_object(exp2m1f16)
 add_math_entrypoint_object(exp10)
 add_math_entrypoint_object(exp10f)
 add_math_entrypoint_object(exp10f16)
+add_math_entrypoint_object(exp10bf16)
 
 add_math_entrypoint_object(exp10m1f)
 add_math_entrypoint_object(exp10m1f16)
diff --git a/libc/src/math/exp10bf16.h b/libc/src/math/exp10bf16.h
new file mode 100644
index 0000000000000..3ca1c830aec3f
--- /dev/null
+++ b/libc/src/math/exp10bf16.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for exp10bf16 ---------------------*- 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_EXP10BF16_H
+#define LLVM_LIBC_SRC_MATH_EXP10BF16_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+bfloat16 exp10bf16(bfloat16 x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_EXP10BF16_H
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 677ad87dbc72f..6353bffdea94f 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -1292,6 +1292,16 @@ add_entrypoint_object(
     libc.src.errno.errno
 )
 
+add_entrypoint_object(
+  exp10bf16
+  SRCS
+    exp10bf16.cpp
+  HDRS
+    ../exp10bf16.h
+  DEPENDS
+    libc.src.__support.math.exp10bf16
+)
+
 add_entrypoint_object(
   exp10f
   SRCS
diff --git a/libc/src/math/generic/exp10bf16.cpp b/libc/src/math/generic/exp10bf16.cpp
new file mode 100644
index 0000000000000..9f02e16ecc0e3
--- /dev/null
+++ b/libc/src/math/generic/exp10bf16.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation for exp10bf16(x) 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/exp10bf16.h"
+#include "src/__support/math/exp10bf16.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(bfloat16, exp10bf16, (bfloat16 x)) {
+  return math::exp10bf16(x);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt
index 4b34361f0ba43..9ad0c0a9e5249 100644
--- a/libc/test/shared/CMakeLists.txt
+++ b/libc/test/shared/CMakeLists.txt
@@ -123,6 +123,7 @@ add_fp_unittest(
     libc.src.__support.math.exp10
     libc.src.__support.math.exp10f
     libc.src.__support.math.exp10f16
+    libc.src.__support.math.exp10bf16
     libc.src.__support.math.expf
     libc.src.__support.math.expf16
     libc.src.__support.math.f16add
diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp
index 776cad754cce6..63fb8803c6db5 100644
--- a/libc/test/shared/shared_math_test.cpp
+++ b/libc/test/shared/shared_math_test.cpp
@@ -769,6 +769,7 @@ TEST(LlvmLibcSharedMathTest, AllBFloat16) {
   EXPECT_FP_EQ(bfloat16(0.0), LIBC_NAMESPACE::shared::ceilbf16(bfloat16(0.0)));
   EXPECT_FP_EQ(bfloat16(0.0), LIBC_NAMESPACE::shared::copysignbf16(
                                   bfloat16(0.0), bfloat16(0.0)));
+  EXPECT_FP_EQ(bfloat16(1.0), LIBC_NAMESPACE::shared::exp10bf16(bfloat16(0.0)));
   EXPECT_FP_EQ(bfloat16(0.0), LIBC_NAMESPACE::shared::fabsbf16(bfloat16(0.0)));
   EXPECT_FP_EQ(bfloat16(0.0), LIBC_NAMESPACE::shared::floorbf16(bfloat16(0.0)));
   EXPECT_FP_EQ(bfloat16(0.0),
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index b2dd913cdf864..c667650465307 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -1156,6 +1156,18 @@ add_fp_unittest(
     libc.src.__support.FPUtil.fp_bits
 )
 
+add_fp_unittest(
+  exp10bf16_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    exp10bf16_test.cpp
+  DEPENDS
+    libc.src.math.exp10bf16
+    libc.src.__support.FPUtil.bfloat16
+)
+
 add_fp_unittest(
   expf_test
   NEED_MPFR
diff --git a/libc/test/src/math/exp10bf16_test.cpp b/libc/test/src/math/exp10bf16_test.cpp
new file mode 100644
index 0000000000000..0eddf98bb1cfb
--- /dev/null
+++ b/libc/test/src/math/exp10bf16_test.cpp
@@ -0,0 +1,39 @@
+//===-- Exhaustive tests for exp10bf16(x) 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/__support/FPUtil/bfloat16.h"
+#include "src/math/exp10bf16.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+using LlvmLibcExp10Bf16Test = LIBC_NAMESPACE::testing::FPTest<bfloat16>;
+
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
+
+// range: [0, inf]
+static constexpr uint16_t POS_START = 0x0000U;
+static constexpr uint16_t POS_STOP = 0x7f80U;
+
+TEST_F(LlvmLibcExp10Bf16Test, PositiveRange) {
+  for (uint16_t v = POS_START; v <= POS_STOP; ++v) {
+    bfloat16 x = FPBits(v).get_val();
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x, LIBC_NAMESPACE::exp10bf16(x), 0.5);
+  }
+}
+
+// range: [-0, -inf]
+static constexpr uint16_t NEG_START = 0x8000U;
+static constexpr uint16_t NEG_STOP = 0xff80U;
+
+TEST_F(LlvmLibcExp10Bf16Test, NegativeRange) {
+  for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) {
+    bfloat16 x = FPBits(v).get_val();
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x, LIBC_NAMESPACE::exp10bf16(x), 0.5);
+  }
+}
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 3f785809b7b7f..d8e0fe8765e33 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -1358,6 +1358,19 @@ add_fp_unittest(
     libc.src.__support.FPUtil.fp_bits
 )
 
+add_fp_unittest(
+  exp10bf16_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    exp10bf16_test.cpp
+  DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
+    libc.src.math.exp10bf16
+    libc.src.__support.FPUtil.bfloat16
+)
+
 add_fp_unittest(
   exp_test
   SUITE
diff --git a/libc/test/src/math/smoke/exp10bf16_test.cpp b/libc/test/src/math/smoke/exp10bf16_test.cpp
new file mode 100644
index 0000000000000..c5ab7ee6fc1a6
--- /dev/null
+++ b/libc/test/src/math/smoke/exp10bf16_test.cpp
@@ -0,0 +1,39 @@
+//===-- Unittests for exp10bf16 -------------------------------------------===//
+//
+// 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/__support/FPUtil/bfloat16.h"
+#include "src/math/exp10bf16.h"
+#include "test/UnitTest/FEnvSafeTest.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+using LlvmLibcExp10Bf16Test = LIBC_NAMESPACE::testing::FPTest<bfloat16>;
+
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
+
+TEST_F(LlvmLibcExp10Bf16Test, SpecialNumbers) {
+  EXPECT_FP_IS_NAN(LIBC_NAMESPACE::exp10bf16(aNaN));
+  EXPECT_MATH_ERRNO(0);
+
+  EXPECT_FP_IS_NAN_WITH_EXCEPTION(LIBC_NAMESPACE::exp10bf16(sNaN), FE_INVALID);
+  EXPECT_MATH_ERRNO(0);
+
+  EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::exp10bf16(inf));
+  EXPECT_MATH_ERRNO(0);
+
+  EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::exp10bf16(neg_inf));
+  EXPECT_MATH_ERRNO(0);
+
+  EXPECT_FP_EQ_ALL_ROUNDING(bfloat16(1.0), LIBC_NAMESPACE::exp10bf16(zero));
+  EXPECT_MATH_ERRNO(0);
+
+  EXPECT_FP_EQ_ALL_ROUNDING(bfloat16(1.0), LIBC_NAMESPACE::exp10bf16(neg_zero));
+  EXPECT_MATH_ERRNO(0);
+}
+

>From 7bdacf51a1b67dff72d0d46dfa789917d82fd34f Mon Sep 17 00:00:00 2001
From: ProfessionalMenace <vondracekadam00 at gmail.com>
Date: Tue, 21 Apr 2026 21:22:25 +0200
Subject: [PATCH 2/5] formatting & bazel

Bazel formatting issue
---
 libc/shared/math/exp10bf16.h                  |  2 +-
 libc/test/src/math/exp10bf16_test.cpp         |  6 ++--
 libc/test/src/math/smoke/exp10bf16_test.cpp   |  1 -
 .../llvm-project-overlay/libc/BUILD.bazel     | 30 +++++++++++++++++++
 4 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/libc/shared/math/exp10bf16.h b/libc/shared/math/exp10bf16.h
index ba6fd984a0312..2024fb5699b54 100644
--- a/libc/shared/math/exp10bf16.h
+++ b/libc/shared/math/exp10bf16.h
@@ -1,4 +1,4 @@
-//===-- Shared exp10bf16 function --------------------------------*- C++ -*-===//
+//===-- Shared exp10bf16 function -------------------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/libc/test/src/math/exp10bf16_test.cpp b/libc/test/src/math/exp10bf16_test.cpp
index 0eddf98bb1cfb..db0f06fe28804 100644
--- a/libc/test/src/math/exp10bf16_test.cpp
+++ b/libc/test/src/math/exp10bf16_test.cpp
@@ -23,7 +23,8 @@ static constexpr uint16_t POS_STOP = 0x7f80U;
 TEST_F(LlvmLibcExp10Bf16Test, PositiveRange) {
   for (uint16_t v = POS_START; v <= POS_STOP; ++v) {
     bfloat16 x = FPBits(v).get_val();
-    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x, LIBC_NAMESPACE::exp10bf16(x), 0.5);
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x,
+                                   LIBC_NAMESPACE::exp10bf16(x), 0.5);
   }
 }
 
@@ -34,6 +35,7 @@ static constexpr uint16_t NEG_STOP = 0xff80U;
 TEST_F(LlvmLibcExp10Bf16Test, NegativeRange) {
   for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) {
     bfloat16 x = FPBits(v).get_val();
-    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x, LIBC_NAMESPACE::exp10bf16(x), 0.5);
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x,
+                                   LIBC_NAMESPACE::exp10bf16(x), 0.5);
   }
 }
diff --git a/libc/test/src/math/smoke/exp10bf16_test.cpp b/libc/test/src/math/smoke/exp10bf16_test.cpp
index c5ab7ee6fc1a6..a9eb5d9be58d6 100644
--- a/libc/test/src/math/smoke/exp10bf16_test.cpp
+++ b/libc/test/src/math/smoke/exp10bf16_test.cpp
@@ -36,4 +36,3 @@ TEST_F(LlvmLibcExp10Bf16Test, SpecialNumbers) {
   EXPECT_FP_EQ_ALL_ROUNDING(bfloat16(1.0), LIBC_NAMESPACE::exp10bf16(neg_zero));
   EXPECT_MATH_ERRNO(0);
 }
-
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 7c0a9faff678d..0a672919d7051 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -6647,6 +6647,28 @@ libc_support_library(
     ],
 )
 
+libc_support_library(
+    name = "__support_math_exp10bf16",
+    hdrs = ["src/__support/math/exp10bf16.h"],
+    deps = [
+        ":__support_common",
+        ":__support_fputil_bfloat16",
+        ":__support_fputil_cast",
+        ":__support_fputil_except_value_utils",
+        ":__support_fputil_fenv_impl",
+        ":__support_fputil_fp_bits",
+        ":__support_fputil_manipulation_functions",
+        ":__support_fputil_multiply_add",
+        ":__support_fputil_nearest_integer",
+        ":__support_fputil_polyeval",
+        ":__support_fputil_rounding_mode",
+        ":__support_libc_errno",
+        ":__support_macros_config",
+        ":__support_macros_optimization",
+        ":errno",
+    ],
+)
+
 libc_support_library(
     name = "__support_math_exp10m1f",
     hdrs = ["src/__support/math/exp10m1f.h"],
@@ -10427,6 +10449,14 @@ libc_math_function(
     ],
 )
 
+libc_math_function(
+    name = "exp10bf16",
+    additional_deps = [
+        ":__support_math_exp10bf16",
+        ":errno",
+    ],
+)
+
 libc_math_function(
     name = "exp10f",
     additional_deps = [

>From 9072e3e4d3bdb70d5abc2cde40e156feece8baa2 Mon Sep 17 00:00:00 2001
From: ProfessionalMenace <vondracekadam00 at gmail.com>
Date: Tue, 28 Apr 2026 10:07:36 +0200
Subject: [PATCH 3/5] minor fixes

---
 libc/src/__support/math/exp10bf16.h | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/libc/src/__support/math/exp10bf16.h b/libc/src/__support/math/exp10bf16.h
index 2820bb5be74e7..f12957770e681 100644
--- a/libc/src/__support/math/exp10bf16.h
+++ b/libc/src/__support/math/exp10bf16.h
@@ -56,7 +56,7 @@ namespace math {
 LIBC_INLINE_VAR constexpr float LOG2F_10 = 0x1.a934fp1;
 
 #ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-constexpr fputil::ExceptValues<bfloat16, 4> EXP10BF16_EXCEPTS{
+LIBC_INLINE_VAR constexpr fputil::ExceptValues<bfloat16, 4> EXP10BF16_EXCEPTS{
     {// {inputs, RZ output, RU offset, RD offset, RN offset}
      // x = -0x1.6ep-7, exp10bf16(x) = 0x1.f2p-1 (RN)
      {0xBC37U, 0x3F79U, 1U, 0U, 0U},
@@ -90,9 +90,8 @@ LIBC_INLINE constexpr bfloat16 exp10bf16(bfloat16 x) {
 
   // exp10bf16(x) = +INF
   if (x_bits.is_pos() && x_u >= 0x421bU) { // x >= 0x1.36p+5
-    if (x_bits.is_inf()) {
+    if (x_bits.is_inf())
       return FPBits::inf().get_val();
-    }
 
     switch (fputil::quick_get_round()) {
     case FE_TONEAREST:

>From d6334f351ad64d5babf26dacd6ba52b8f826234e Mon Sep 17 00:00:00 2001
From: ProfessionalMenace <vondracekadam00 at gmail.com>
Date: Tue, 5 May 2026 02:15:33 +0200
Subject: [PATCH 4/5] applied suggestions

---
 libc/src/__support/math/CMakeLists.txt            | 1 -
 libc/test/src/math/smoke/exp10bf16_test.cpp       | 3 ---
 utils/bazel/llvm-project-overlay/libc/BUILD.bazel | 1 -
 3 files changed, 5 deletions(-)

diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index ca4223a99dd14..d9f952e460a96 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -2967,7 +2967,6 @@ add_header_library(
     libc.src.__support.FPUtil.fp_bits
     libc.src.__support.FPUtil.manipulation_functions
     libc.src.__support.FPUtil.polyeval
-    libc.src.__support.FPUtil.multiply_add
     libc.src.__support.macros.optimization
 )
 
diff --git a/libc/test/src/math/smoke/exp10bf16_test.cpp b/libc/test/src/math/smoke/exp10bf16_test.cpp
index a9eb5d9be58d6..24784666265cd 100644
--- a/libc/test/src/math/smoke/exp10bf16_test.cpp
+++ b/libc/test/src/math/smoke/exp10bf16_test.cpp
@@ -11,12 +11,9 @@
 #include "test/UnitTest/FEnvSafeTest.h"
 #include "test/UnitTest/FPMatcher.h"
 #include "test/UnitTest/Test.h"
-#include "utils/MPFRWrapper/MPFRUtils.h"
 
 using LlvmLibcExp10Bf16Test = LIBC_NAMESPACE::testing::FPTest<bfloat16>;
 
-namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
-
 TEST_F(LlvmLibcExp10Bf16Test, SpecialNumbers) {
   EXPECT_FP_IS_NAN(LIBC_NAMESPACE::exp10bf16(aNaN));
   EXPECT_MATH_ERRNO(0);
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 0a672919d7051..cada7daa33ea0 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -6658,7 +6658,6 @@ libc_support_library(
         ":__support_fputil_fenv_impl",
         ":__support_fputil_fp_bits",
         ":__support_fputil_manipulation_functions",
-        ":__support_fputil_multiply_add",
         ":__support_fputil_nearest_integer",
         ":__support_fputil_polyeval",
         ":__support_fputil_rounding_mode",

>From fa25581c61508503b520aeecc3a36c9be7d6a7c7 Mon Sep 17 00:00:00 2001
From: ProfessionalMenace <vondracekadam00 at gmail.com>
Date: Tue, 9 Jun 2026 16:11:27 +0200
Subject: [PATCH 5/5] nitpicks & update

---
 libc/src/__support/math/exp10bf16.h         | 37 ++++++++++++---------
 libc/test/src/math/smoke/exp10bf16_test.cpp |  1 -
 2 files changed, 22 insertions(+), 16 deletions(-)

diff --git a/libc/src/__support/math/exp10bf16.h b/libc/src/__support/math/exp10bf16.h
index f12957770e681..dea3e761c7a9e 100644
--- a/libc/src/__support/math/exp10bf16.h
+++ b/libc/src/__support/math/exp10bf16.h
@@ -17,7 +17,6 @@
 #include "src/__support/FPUtil/cast.h"
 #include "src/__support/FPUtil/except_value_utils.h"
 #include "src/__support/FPUtil/nearest_integer.h"
-#include "src/__support/common.h"
 #include "src/__support/macros/optimization.h"
 
 // This is an algorithm for exp10(x) in bfloat16 which is correctly rounded for
@@ -35,10 +34,10 @@
 // sum of two parts - closest integer i and a fraction f
 // exp10(x) = exp2(x * log2(10)) = exp2(i + f) = exp2(i) * exp2(f)
 
-// Step 4 - Polynomial approximation:
-// Approximate the range reduced function exp2(f) on a domain (-0.5, 0.5)
+// Step 3 - Polynomial approximation:
+// Approximate the range reduced function exp2(f) on a domain [-0.5, 0.5]
 // using a fourth degree polynomial P
-// Generated by Sollya with the following command:
+// Generated by Sollya with the following commands:
 // > display = hexadecimal;
 // > exp2 = 2^x;
 // > I = [-0.5, 0.5];
@@ -52,7 +51,7 @@ namespace LIBC_NAMESPACE_DECL {
 namespace math {
 
 // Generated by Sollya with the following command:
-// round(log2(10), SG, RN);
+// > round(log2(10), SG, RN);
 LIBC_INLINE_VAR constexpr float LOG2F_10 = 0x1.a934fp1;
 
 #ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
@@ -85,6 +84,14 @@ LIBC_INLINE constexpr bfloat16 exp10bf16(bfloat16 x) {
 
   // exp10bf16(x) = +0.0
   if (x_bits.is_neg() && x_u >= 0xc222U) { // x <= -0x1.44p+5
+    if (x_bits.is_inf())
+      return FPBits::zero().get_val();
+
+    fputil::set_errno_if_required(ERANGE);
+    fputil::raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
+
+    if (fputil::fenv_is_round_up())
+      return FPBits::min_subnormal().get_val();
     return FPBits::zero().get_val();
   }
 
@@ -123,20 +130,20 @@ LIBC_INLINE constexpr bfloat16 exp10bf16(bfloat16 x) {
 #endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
 
   // x * log2(10)
-  float xscaled = fputil::cast<bfloat16>(x) * LOG2F_10;
+  float xs = fputil::cast<float>(x) * LOG2F_10;
 
-  // range reduction to (-0.5, 0.5)
-  float intPart = fputil::nearest_integer(xscaled);
-  float fracPart = xscaled - intPart;
+  // range reduction to [-0.5, 0.5]
+  float xs_i = fputil::nearest_integer(xs);
+  float xs_f = xs - xs_i;
 
-  // polynomial approximation of exp2(x) on (-0.5, 0.5)
-  float poly = fputil::polyeval(fracPart,
-                                0x1p0f, // Exp2(0) = Exp10(0) = 1
-                                0x1.62e0dep-1f, 0x1.ec00d6p-3f, 0x1.ca13dcp-5f,
-                                0x1.3ac75ep-7f);
+  // polynomial approximation of exp2(x) on [-0.5, 0.5]
+  float exp2_f = fputil::polyeval(xs_f,
+                                  0x1p0f, // Exp2(0) = Exp10(0) = 1
+                                  0x1.62e0dep-1f, 0x1.ec00d6p-3f,
+                                  0x1.ca13dcp-5f, 0x1.3ac75ep-7f);
 
   // output compensation
-  float result = fputil::ldexp(poly, static_cast<int>(intPart));
+  float result = fputil::ldexp(exp2_f, static_cast<int>(xs_i));
   return fputil::cast<bfloat16>(result);
 }
 
diff --git a/libc/test/src/math/smoke/exp10bf16_test.cpp b/libc/test/src/math/smoke/exp10bf16_test.cpp
index 24784666265cd..fc802b4eda3c1 100644
--- a/libc/test/src/math/smoke/exp10bf16_test.cpp
+++ b/libc/test/src/math/smoke/exp10bf16_test.cpp
@@ -8,7 +8,6 @@
 
 #include "src/__support/FPUtil/bfloat16.h"
 #include "src/math/exp10bf16.h"
-#include "test/UnitTest/FEnvSafeTest.h"
 #include "test/UnitTest/FPMatcher.h"
 #include "test/UnitTest/Test.h"
 



More information about the libc-commits mailing list