[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