[libc-commits] [libc] [libc][math][c++23] Add exp2bf16 math function (PR #230213)
via libc-commits
libc-commits at lists.llvm.org
Thu Oct 15 09:49:19 PDT 2026
https://github.com/un-pixelated updated https://github.com/llvm/llvm-project/pull/230213
>From 504e73988525c60ae47464e97eac9df7bf2ad1e1 Mon Sep 17 00:00:00 2001
From: pixl <planner.chisels.7j at icloud.com>
Date: Thu, 15 Oct 2026 20:33:11 +0530
Subject: [PATCH] [libc][math][c++23] Add exp2bf16 math function
---
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/exp2bf16.h | 28 +++
libc/src/__support/math/CMakeLists.txt | 21 ++
libc/src/__support/math/exp2bf16.h | 211 ++++++++++++++++++
libc/src/math/CMakeLists.txt | 1 +
libc/src/math/exp2bf16.h | 26 +++
libc/src/math/generic/CMakeLists.txt | 10 +
libc/src/math/generic/exp2bf16.cpp | 23 ++
libc/test/shared/shared_math_test.cpp | 1 +
libc/test/src/math/CMakeLists.txt | 12 +
libc/test/src/math/exp2bf16_test.cpp | 46 ++++
libc/test/src/math/smoke/CMakeLists.txt | 13 ++
libc/test/src/math/smoke/exp2bf16_test.cpp | 66 ++++++
26 files changed, 472 insertions(+), 1 deletion(-)
create mode 100644 libc/shared/math/exp2bf16.h
create mode 100644 libc/src/__support/math/exp2bf16.h
create mode 100644 libc/src/math/exp2bf16.h
create mode 100644 libc/src/math/generic/exp2bf16.cpp
create mode 100644 libc/test/src/math/exp2bf16_test.cpp
create mode 100644 libc/test/src/math/smoke/exp2bf16_test.cpp
diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt
index 114534ce61ae6e..cb341c2d8b0e30 100644
--- a/libc/config/baremetal/aarch64/entrypoints.txt
+++ b/libc/config/baremetal/aarch64/entrypoints.txt
@@ -828,6 +828,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
libc.src.math.canonicalizebf16
libc.src.math.ceilbf16
libc.src.math.copysignbf16
+ libc.src.math.exp2bf16
libc.src.math.expbf16
libc.src.math.fabsbf16
libc.src.math.fdimbf16
diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index c8148815c34e34..65e36c110d696f 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -839,6 +839,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
libc.src.math.canonicalizebf16
libc.src.math.ceilbf16
libc.src.math.copysignbf16
+ libc.src.math.exp2bf16
libc.src.math.expbf16
libc.src.math.fabsbf16
libc.src.math.fdimbf16
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index 622d6156cff11d..caa5f3c559cc6c 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -831,6 +831,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
libc.src.math.canonicalizebf16
libc.src.math.ceilbf16
libc.src.math.copysignbf16
+ libc.src.math.exp2bf16
libc.src.math.expbf16
libc.src.math.fabsbf16
libc.src.math.fdimbf16
diff --git a/libc/config/darwin/aarch64/entrypoints.txt b/libc/config/darwin/aarch64/entrypoints.txt
index d702b2c5a65497..5600b82ad3410b 100644
--- a/libc/config/darwin/aarch64/entrypoints.txt
+++ b/libc/config/darwin/aarch64/entrypoints.txt
@@ -650,6 +650,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
libc.src.math.canonicalizebf16
libc.src.math.ceilbf16
libc.src.math.copysignbf16
+ libc.src.math.exp2bf16
libc.src.math.expbf16
libc.src.math.fabsbf16
libc.src.math.fdimbf16
diff --git a/libc/config/darwin/x86_64/entrypoints.txt b/libc/config/darwin/x86_64/entrypoints.txt
index 716ab572f8d3cd..e3fc845d2ed3af 100644
--- a/libc/config/darwin/x86_64/entrypoints.txt
+++ b/libc/config/darwin/x86_64/entrypoints.txt
@@ -285,6 +285,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
libc.src.math.canonicalizebf16
libc.src.math.ceilbf16
libc.src.math.copysignbf16
+ libc.src.math.exp2bf16
libc.src.math.expbf16
libc.src.math.fabsbf16
libc.src.math.fdimbf16
diff --git a/libc/config/gpu/amdgpu/entrypoints.txt b/libc/config/gpu/amdgpu/entrypoints.txt
index 5c5e5891da8227..2eaef608e9a7ac 100644
--- a/libc/config/gpu/amdgpu/entrypoints.txt
+++ b/libc/config/gpu/amdgpu/entrypoints.txt
@@ -699,6 +699,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
libc.src.math.canonicalizebf16
libc.src.math.ceilbf16
libc.src.math.copysignbf16
+ libc.src.math.exp2bf16
libc.src.math.expbf16
libc.src.math.fabsbf16
libc.src.math.fdimbf16
diff --git a/libc/config/gpu/nvptx/entrypoints.txt b/libc/config/gpu/nvptx/entrypoints.txt
index afae725484a891..79d0c733ec3c01 100644
--- a/libc/config/gpu/nvptx/entrypoints.txt
+++ b/libc/config/gpu/nvptx/entrypoints.txt
@@ -715,6 +715,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
libc.src.math.canonicalizebf16
libc.src.math.ceilbf16
libc.src.math.copysignbf16
+ libc.src.math.exp2bf16
libc.src.math.expbf16
libc.src.math.fabsbf16
libc.src.math.fdimbf16
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index cee039a405c8d3..42ce377d7dca9a 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1063,6 +1063,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
libc.src.math.canonicalizebf16
libc.src.math.ceilbf16
libc.src.math.copysignbf16
+ libc.src.math.exp2bf16
libc.src.math.expbf16
libc.src.math.fabsbf16
libc.src.math.fdimbf16
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index a6ed087f34ee2a..85af57dc2c8d23 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -664,6 +664,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
libc.src.math.canonicalizebf16
libc.src.math.ceilbf16
libc.src.math.copysignbf16
+ libc.src.math.exp2bf16
libc.src.math.expbf16
libc.src.math.fabsbf16
libc.src.math.fdimbf16
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index f91a8939ac61d6..7e0511487c2cf5 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1137,6 +1137,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
libc.src.math.canonicalizebf16
libc.src.math.ceilbf16
libc.src.math.copysignbf16
+ libc.src.math.exp2bf16
libc.src.math.expbf16
libc.src.math.fabsbf16
libc.src.math.fdimbf16
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 1aaafc9c084679..155ae28d753bec 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1159,6 +1159,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
libc.src.math.canonicalizebf16
libc.src.math.ceilbf16
libc.src.math.copysignbf16
+ libc.src.math.exp2bf16
libc.src.math.expbf16
libc.src.math.fabsbf16
libc.src.math.fdimbf16
diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index 3a48b49e169b3a..1712b2ad26fda4 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -376,6 +376,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
libc.src.math.canonicalizebf16
libc.src.math.ceilbf16
libc.src.math.copysignbf16
+ libc.src.math.exp2bf16
libc.src.math.expbf16
libc.src.math.fabsbf16
libc.src.math.fdimbf16
diff --git a/libc/docs/headers/math/index.rst b/libc/docs/headers/math/index.rst
index 67fc2e259eff9b..575c7bd1d1a10a 100644
--- a/libc/docs/headers/math/index.rst
+++ b/libc/docs/headers/math/index.rst
@@ -301,7 +301,7 @@ Higher Math Functions
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+
| exp10m1 | |check| | | | |check| | | | 7.12.6.3 | F.10.3.3 |
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+
-| exp2 | |check| | |check| | | |check| | | | 7.12.6.4 | F.10.3.4 |
+| exp2 | |check| | |check| | | |check| | | |check| | 7.12.6.4 | F.10.3.4 |
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+
| exp2m1 | |check| | | | |check| | | | 7.12.6.5 | F.10.3.5 |
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+
diff --git a/libc/shared/math.h b/libc/shared/math.h
index 7b52cedf99c245..eb72bebcb53bfa 100644
--- a/libc/shared/math.h
+++ b/libc/shared/math.h
@@ -110,6 +110,7 @@
#include "math/exp10m1f.h"
#include "math/exp10m1f16.h"
#include "math/exp2.h"
+#include "math/exp2bf16.h"
#include "math/exp2f.h"
#include "math/exp2f16.h"
#include "math/exp2m1f.h"
diff --git a/libc/shared/math/exp2bf16.h b/libc/shared/math/exp2bf16.h
new file mode 100644
index 00000000000000..fa7a760c14e529
--- /dev/null
+++ b/libc/shared/math/exp2bf16.h
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Shared header for the exp2bf16 function.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SHARED_MATH_EXP2BF16_H
+#define LLVM_LIBC_SHARED_MATH_EXP2BF16_H
+
+#include "shared/libc_common.h"
+#include "src/__support/math/exp2bf16.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace shared {
+
+using math::exp2bf16;
+
+} // namespace shared
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SHARED_MATH_EXP2BF16_H
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index ef33e3f8ada7b0..cd17eb93c93425 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -4295,6 +4295,27 @@ add_header_library(
libc.src.__support.macros.optimization
)
+add_header_library(
+ exp2bf16
+ HDRS
+ exp2bf16.h
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.fenv_macros
+ libc.src.__support.FPUtil.bfloat16
+ libc.src.__support.FPUtil.cast
+ libc.src.__support.FPUtil.fenv_impl
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.FPUtil.multiply_add
+ libc.src.__support.FPUtil.nearest_integer
+ libc.src.__support.FPUtil.polyeval
+ libc.src.__support.FPUtil.rounding_mode
+ libc.src.__support.macros.attributes
+ libc.src.__support.macros.config
+ libc.src.__support.macros.optimization
+ libc.src.__support.macros.properties.types
+)
+
add_header_library(
exp2f16
HDRS
diff --git a/libc/src/__support/math/exp2bf16.h b/libc/src/__support/math/exp2bf16.h
new file mode 100644
index 00000000000000..44fa5da0ebe477
--- /dev/null
+++ b/libc/src/__support/math/exp2bf16.h
@@ -0,0 +1,211 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of the exp2bf16 function, which computes 2^x for bfloat16.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP2BF16_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP2BF16_H
+
+#include "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/PolyEval.h"
+#include "src/__support/FPUtil/bfloat16.h"
+#include "src/__support/FPUtil/cast.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/FPUtil/nearest_integer.h"
+#include "src/__support/FPUtil/rounding_mode.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
+
+namespace exp2bf16_internal {
+// Generated by Sollya with the following commands:
+// > display = hexadecimal;
+// > for i in [|-126.5, -127, -127.5, -128, -129, -130, -131, -132, -133|]
+// do print(round(2^i, SG, RN) @ "f,");
+LIBC_INLINE_VAR constexpr float EXP2_DENORMAL[9] = {
+ 0x1.6a09e8p-127f, 0x1p-127f, 0x1.6a09e8p-128f, 0x1p-128f, 0x1p-129f,
+ 0x1p-130f, 0x1p-131f, 0x1p-132f, 0x1p-133f,
+};
+
+// Generated by Sollya with the following commands:
+// > display = hexadecimal;
+// > for i from 0 to 15 do print(round(2^(i/16), SG, RN) @ "f,");
+LIBC_INLINE_VAR constexpr float EXP2_MID[16] = {
+ 0x1p0f, 0x1.0b5586p0f, 0x1.172b84p0f, 0x1.2387a6p0f,
+ 0x1.306fep0f, 0x1.3dea64p0f, 0x1.4bfdaep0f, 0x1.5ab07ep0f,
+ 0x1.6a09e6p0f, 0x1.7a1148p0f, 0x1.8ace54p0f, 0x1.9c4918p0f,
+ 0x1.ae89fap0f, 0x1.c199bep0f, 0x1.d5818ep0f, 0x1.ea4afap0f,
+};
+} // namespace exp2bf16_internal
+
+LIBC_INLINE bfloat16 exp2bf16(bfloat16 x) {
+ using FPBits = fputil::FPBits<bfloat16>;
+ FPBits x_bits(x);
+ uint16_t x_uint = x_bits.uintval();
+
+ // We first check for NaN
+ if (LIBC_UNLIKELY(x_bits.is_nan())) {
+ // If it is a signaling NaN, then we raise an FE_INVALID exception
+ // and return a quiet NaN
+ if (x_bits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ // If not, just return the NaN
+ return x;
+ }
+
+ // exp2bf16 may only give numeric output for input x in (-134.0, 128.0).
+ // All the remaining exceptional cases (overflow, underflow and denormal
+ // outputs) have |x| >= 126.5, so we filter them with a single check.
+ constexpr uint16_t EXCEPTIONAL_ABS_BASE = 0x42FD; // 0x1.fap6 = 126.5
+ if (LIBC_UNLIKELY(x_bits.abs().uintval() >= EXCEPTIONAL_ABS_BASE)) {
+ if (x_bits.is_pos()) {
+ // Overflow: x >= 128.0 (0x4300 = 0x1p7)
+ if (x_uint >= 0x4300) {
+ // exp2(Inf) = Inf
+ if (x_bits.is_inf())
+ return x;
+
+#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+ // If we can only RN, then it'll go towards INF
+ fputil::set_errno_if_required(ERANGE);
+ fputil::raise_overflow_except_if_required<float>();
+ return FPBits::inf().get_val();
+#else
+ // If not, get what other rounding modes are available
+ switch (fputil::quick_get_round()) {
+ case FE_TONEAREST:
+ case FE_UPWARD:
+ // Both of these go to Inf
+ fputil::set_errno_if_required(ERANGE);
+ fputil::raise_overflow_except_if_required<float>();
+ return FPBits::inf().get_val();
+ default:
+ // RD and RZ go to the maximum possible value in the
+ // range of the function, being the maximum normal.
+ return FPBits::max_normal().get_val();
+ }
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+ }
+ } else {
+ // Underflow: x <= -134.0 (0xC306 = -0x1.0cp7)
+ if (x_uint >= 0xC306) {
+ // exp2(-Inf) = 0
+ if (x_bits.is_inf())
+ return FPBits::zero().get_val();
+
+ // Need these for every output now.
+ fputil::set_errno_if_required(ERANGE);
+ fputil::raise_underflow_except_if_required<float>();
+#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+ return FPBits::zero().get_val();
+#else
+ switch (fputil::quick_get_round()) {
+ case FE_UPWARD:
+ // RU rounds up to the minimum subnormal
+ return FPBits::min_subnormal().get_val();
+ default:
+ // All other rounding modes go down to zero
+ return FPBits::zero().get_val();
+ }
+#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+ }
+
+ // Handle denormal output separately, by using a LUT
+ // We are handling these separately because the trick of adding hi
+ // directly to the exponent of the result will not work if the
+ // output is denormal. There are only 9 such inputs and they are
+ // all back-to-back when expressed as an uint16_t, with
+ // x_uint >= 0xC2FD (-0x1.fap6 = -126.5) and
+ // x_uint <= 0xC305 (-0x1.0ap7 = -133.0).
+ constexpr uint16_t DENORMAL_LUT_BASE = 0xC2FD;
+ return fputil::cast<bfloat16>(
+ exp2bf16_internal::EXP2_DENORMAL[x_uint - DENORMAL_LUT_BASE]);
+ }
+ }
+
+ // For inputs not handled above in -134.0 < x < 128.0,
+ // we perform the following range reduction:
+ // x = hi + mid + lo
+ // where,
+ // hi is an integer
+ // mid is a grid point of the form j / 2^n in [0, 1)
+ // lo is what's leftover ie x - k / 2^n
+ // and |lo| <= 2^(-n-1)
+ // with,
+ // n = 4
+ // k = round(2^n * x)
+ // hi = k >> n
+ // j = k & (2^n - 1)
+ // then,
+ // exp2(x) = exp2(hi + mid + lo)
+ // = exp2(hi) * exp2(mid) * exp2(lo)
+ //
+ // To get exp2(hi), we'll just add hi to the exponent bits of the
+ // result of exp2(mid) * exp2(lo), which is exact.
+ // exp2(mid) we shall obtain by consulting our LUT,
+ // exp2(lo) by the polynomial.
+
+ float x_float = fputil::cast<float>(x);
+ float k_float = fputil::nearest_integer(x_float * 16.0f);
+
+ int k_int = static_cast<int>(k_float);
+ int hi = k_int >> 4;
+ int j = k_int & (16 - 1);
+
+ // lo = x - (hi + mid) = x - k / 2^n
+ // = k * (-2^(-n)) + x
+ float lo = fputil::multiply_add(k_float, -0.0625f, x_float);
+
+ float exp2_mid = exp2bf16_internal::EXP2_MID[j];
+
+ // Degree-3 minimax polynomial generated by Sollya with the following
+ // commands:
+ // > display = hexadecimal;
+ // > P = fpminimax(2^x, [|1, 2, 3|], [|SG...|], [-2^-5, 2^-5], relative,
+ // floating, 1);
+ // 0x1p0 + x * (0x1.62e43p-1 + x * (0x1.ebfff4p-3 + x * 0x1.c6aceep-5))
+ float exp2_lo = fputil::polyeval(lo, 0x1p0f, 0x1.62e43p-1f, 0x1.ebfff4p-3f,
+ 0x1.c6aceep-5f);
+
+ // We tried using Estrin's scheme as follows,
+ // float lo2 = lo * lo;
+ // float p0 = fputil::multiply_add(lo, 0x1.62e43p-1f, 0x1p0f);
+ // float p1 = fputil::multiply_add(lo, 0x1.c6aceep-5f, 0x1.ebfff4p-3f);
+ // float exp2_lo = fputil::multiply_add(lo2, p1, p0);
+ // however that led to a 1-ULP error in all RU, negative, small input cases.
+ // The latency increase wasn't significant (~1%) so we reverted back
+ // to Horner's scheme.
+
+ float res = exp2_mid * exp2_lo;
+
+ fputil::FPBits<float> res_bits(res);
+ uint32_t res_int = res_bits.uintval();
+
+ uint32_t exp_hi = hi << fputil::FPBits<float>::FRACTION_LEN;
+ res_int += exp_hi;
+
+ res = fputil::FPBits<float>(res_int).get_val();
+ return fputil::cast<bfloat16>(res);
+}
+
+} // namespace math
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP2BF16_H
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index 2c7568f0b63618..4f1dd95a6993da 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -154,6 +154,7 @@ add_math_entrypoint_object(expf16)
add_math_entrypoint_object(expbf16)
add_math_entrypoint_object(exp2)
+add_math_entrypoint_object(exp2bf16)
add_math_entrypoint_object(exp2f)
add_math_entrypoint_object(exp2f16)
diff --git a/libc/src/math/exp2bf16.h b/libc/src/math/exp2bf16.h
new file mode 100644
index 00000000000000..b19fb2d2f92bc0
--- /dev/null
+++ b/libc/src/math/exp2bf16.h
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Public declaration of the exp2bf16 entrypoint.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_EXP2BF16_H
+#define LLVM_LIBC_SRC_MATH_EXP2BF16_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+bfloat16 exp2bf16(bfloat16 x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_EXP2BF16_H
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 28b8e954530ddf..17f586036396f1 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -1284,6 +1284,16 @@ add_entrypoint_object(
libc.src.__support.math.exp2f
)
+add_entrypoint_object(
+ exp2bf16
+ SRCS
+ exp2bf16.cpp
+ HDRS
+ ../exp2bf16.h
+ DEPENDS
+ libc.src.__support.math.exp2bf16
+)
+
add_entrypoint_object(
exp2f16
SRCS
diff --git a/libc/src/math/generic/exp2bf16.cpp b/libc/src/math/generic/exp2bf16.cpp
new file mode 100644
index 00000000000000..d560c318955df1
--- /dev/null
+++ b/libc/src/math/generic/exp2bf16.cpp
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Entrypoint definition for the exp2bf16 function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/math/exp2bf16.h"
+#include "src/math/exp2bf16.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(bfloat16, exp2bf16, (bfloat16 x)) {
+ return math::exp2bf16(x);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp
index 7b785331f36c6a..5b6663fa6494f6 100644
--- a/libc/test/shared/shared_math_test.cpp
+++ b/libc/test/shared/shared_math_test.cpp
@@ -809,6 +809,7 @@ TEST(LlvmLibcSharedMathTest, AllBFloat16) {
bfloat16(0.0)));
EXPECT_FP_EQ(bfloat16(0.0), setpayloadsigbf16_res);
+ EXPECT_FP_EQ(bfloat16(1.0), LIBC_NAMESPACE::shared::exp2bf16(bfloat16(0.0)));
EXPECT_FP_EQ(bfloat16(1.0), LIBC_NAMESPACE::shared::expbf16(bfloat16(0.0)));
EXPECT_FP_EQ(bfloat16(0.0), LIBC_NAMESPACE::shared::log_bf16(bfloat16(1.0)));
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 92d599fba947e5..97facaf909097f 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -1398,6 +1398,18 @@ add_fp_unittest(
libc.src.__support.FPUtil.fp_bits
)
+add_fp_unittest(
+ exp2bf16_test
+ NEED_MPFR
+ SUITE
+ libc-math-unittests
+ SRCS
+ exp2bf16_test.cpp
+ DEPENDS
+ libc.src.math.exp2bf16
+ libc.src.__support.FPUtil.bfloat16
+)
+
add_fp_unittest(
exp2f16_test
NEED_MPFR
diff --git a/libc/test/src/math/exp2bf16_test.cpp b/libc/test/src/math/exp2bf16_test.cpp
new file mode 100644
index 00000000000000..6b99b8eb62be35
--- /dev/null
+++ b/libc/test/src/math/exp2bf16_test.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Exhaustive test for the exp2bf16 function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/FPUtil/bfloat16.h"
+#include "src/math/exp2bf16.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+using LlvmLibcExp2bf16Test = 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;
+
+// range: [-0, -inf]
+static constexpr uint16_t NEG_START = 0x8000U;
+static constexpr uint16_t NEG_STOP = 0xff80U;
+
+TEST_F(LlvmLibcExp2bf16Test, PositiveRange) {
+ for (uint16_t v = POS_START; v <= POS_STOP; v++) {
+ bfloat16 x = FPBits(v).get_val();
+ EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2, x,
+ LIBC_NAMESPACE::exp2bf16(x), 0.5);
+ }
+}
+
+TEST_F(LlvmLibcExp2bf16Test, NegativeRange) {
+ for (uint16_t v = NEG_START; v <= NEG_STOP; v++) {
+ bfloat16 x = FPBits(v).get_val();
+ EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2, x,
+ LIBC_NAMESPACE::exp2bf16(x), 0.5);
+ }
+}
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index fe9fafdfab9a3f..6f1650fcffa7fd 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -1499,6 +1499,19 @@ add_fp_unittest(
libc.src.__support.FPUtil.fp_bits
)
+add_fp_unittest(
+ exp2bf16_test
+ SUITE
+ libc-math-smoke-tests
+ SRCS
+ exp2bf16_test.cpp
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.fenv_macros
+ libc.src.math.exp2bf16
+ libc.src.__support.FPUtil.bfloat16
+)
+
add_fp_unittest(
exp2f16_test
SUITE
diff --git a/libc/test/src/math/smoke/exp2bf16_test.cpp b/libc/test/src/math/smoke/exp2bf16_test.cpp
new file mode 100644
index 00000000000000..c9930fa218b4ce
--- /dev/null
+++ b/libc/test/src/math/smoke/exp2bf16_test.cpp
@@ -0,0 +1,66 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Smoke test for the exp2bf16 function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
+#include "src/__support/FPUtil/bfloat16.h"
+#include "src/math/exp2bf16.h"
+#include "test/UnitTest/FEnvSafeTest.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+
+class LlvmLibcExp2bf16Test : public LIBC_NAMESPACE::testing::FEnvSafeTest {
+ DECLARE_SPECIAL_CONSTANTS(bfloat16)
+
+public:
+ void test_special_numbers() {
+ EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::exp2bf16(aNaN));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::exp2bf16(sNaN),
+ FE_INVALID);
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::exp2bf16(inf));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::exp2bf16(neg_inf));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_ALL_ROUNDING(bfloat16(1.0f), LIBC_NAMESPACE::exp2bf16(zero));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_ALL_ROUNDING(bfloat16(1.0f),
+ LIBC_NAMESPACE::exp2bf16(neg_zero));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::exp2bf16(max_normal),
+ FE_OVERFLOW);
+ EXPECT_MATH_ERRNO(ERANGE);
+
+ EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::exp2bf16(bfloat16(128.0f)),
+ FE_OVERFLOW);
+ EXPECT_MATH_ERRNO(ERANGE);
+
+ EXPECT_FP_EQ_WITH_EXCEPTION(zero, LIBC_NAMESPACE::exp2bf16(neg_max_normal),
+ FE_UNDERFLOW | FE_INEXACT);
+ EXPECT_MATH_ERRNO(ERANGE);
+
+ EXPECT_FP_EQ_WITH_EXCEPTION(zero,
+ LIBC_NAMESPACE::exp2bf16(bfloat16(-134.0f)),
+ FE_UNDERFLOW | FE_INEXACT);
+ EXPECT_MATH_ERRNO(ERANGE);
+ }
+};
+
+TEST_F(LlvmLibcExp2bf16Test, SpecialNumbers) { test_special_numbers(); }
More information about the libc-commits
mailing list