Skip to content

Conversation

krishna2803
Copy link
Contributor

This PR adds expbf16 higher math function for BFloat16 type along with the tests.

@llvmbot
Copy link
Member

llvmbot commented Oct 3, 2025

@llvm/pr-subscribers-backend-amdgpu

@llvm/pr-subscribers-libc

Author: Krishna Pandey (krishna2803)

Changes

This PR adds expbf16 higher math function for BFloat16 type along with the tests.


Patch is 22.15 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/161919.diff

21 Files Affected:

  • (modified) libc/config/baremetal/aarch64/entrypoints.txt (+1)
  • (modified) libc/config/baremetal/arm/entrypoints.txt (+1)
  • (modified) libc/config/baremetal/riscv/entrypoints.txt (+1)
  • (modified) libc/config/darwin/aarch64/entrypoints.txt (+1)
  • (modified) libc/config/darwin/x86_64/entrypoints.txt (+1)
  • (modified) libc/config/gpu/amdgpu/entrypoints.txt (+1)
  • (modified) libc/config/gpu/nvptx/entrypoints.txt (+1)
  • (modified) libc/config/linux/aarch64/entrypoints.txt (+1)
  • (modified) libc/config/linux/arm/entrypoints.txt (+1)
  • (modified) libc/config/linux/riscv/entrypoints.txt (+1)
  • (modified) libc/config/linux/x86_64/entrypoints.txt (+1)
  • (modified) libc/config/windows/entrypoints.txt (+1)
  • (modified) libc/docs/headers/math/index.rst (+1-1)
  • (modified) libc/src/math/CMakeLists.txt (+1)
  • (added) libc/src/math/expbf16.h (+21)
  • (modified) libc/src/math/generic/CMakeLists.txt (+22)
  • (added) libc/src/math/generic/expbf16.cpp (+184)
  • (modified) libc/test/src/math/CMakeLists.txt (+12)
  • (added) libc/test/src/math/expbf16_test.cpp (+59)
  • (modified) libc/test/src/math/smoke/CMakeLists.txt (+14)
  • (added) libc/test/src/math/smoke/expbf16_test.cpp (+63)
diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt
index 935c95af0d4af..f8d0ed5167d43 100644
--- a/libc/config/baremetal/aarch64/entrypoints.txt
+++ b/libc/config/baremetal/aarch64/entrypoints.txt
@@ -778,6 +778,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.expbf16
   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 82e257c1d2b0d..3291d54c6e308 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -778,6 +778,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.expbf16
   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 c10cc1162cc5a..bf0e7d7108bdb 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -778,6 +778,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.expbf16
   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 e3c6c2b30c415..d5eba9cdf4f9d 100644
--- a/libc/config/darwin/aarch64/entrypoints.txt
+++ b/libc/config/darwin/aarch64/entrypoints.txt
@@ -608,6 +608,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.expbf16
   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 e899bf97ea3f6..78dab1d24d20c 100644
--- a/libc/config/darwin/x86_64/entrypoints.txt
+++ b/libc/config/darwin/x86_64/entrypoints.txt
@@ -251,6 +251,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.expbf16
   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 0dda7d5c683ec..524e42c0f6c94 100644
--- a/libc/config/gpu/amdgpu/entrypoints.txt
+++ b/libc/config/gpu/amdgpu/entrypoints.txt
@@ -634,6 +634,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.expbf16
   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 6070fb5b17b3c..d6450cdba6dce 100644
--- a/libc/config/gpu/nvptx/entrypoints.txt
+++ b/libc/config/gpu/nvptx/entrypoints.txt
@@ -636,6 +636,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.expbf16
   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 ae8deabc97407..184e7878dbc24 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -861,6 +861,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.expbf16
   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 f04ac40145d3a..999f863bbba36 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -478,6 +478,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.expbf16
   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 5f407e842121e..c54ce62703131 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -883,6 +883,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.expbf16
   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 bf2ad4a40ca11..e55e2664f0818 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -918,6 +918,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.expbf16
   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 3a76595b258e2..750715c83cbca 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -324,6 +324,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.canonicalizebf16
   libc.src.math.ceilbf16
   libc.src.math.copysignbf16
+  libc.src.math.expbf16
   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 51bf238b950b0..529fb2f798be2 100644
--- a/libc/docs/headers/math/index.rst
+++ b/libc/docs/headers/math/index.rst
@@ -289,7 +289,7 @@ Higher Math Functions
 +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+
 | cosh      | |check|          |                 |                        | |check|              |                        |                        | 7.12.5.4               | F.10.2.4                   |
 +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+
-| cospi     | |check|          |                 |                        | |check|              |                        |                        | 7.12.4.12              | F.10.1.12                  |
+| cospi     | |check|          |                 |                        | |check|              |                        | |check|                | 7.12.4.12              | F.10.1.12                  |
 +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+
 | dsqrt     | N/A              | N/A             |   |check|              | N/A                  |       |check|\*        |                        | 7.12.14.6              | F.10.11                    |
 +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index 3c7e99f4a9c46..d74b43e0f923b 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -139,6 +139,7 @@ add_math_entrypoint_object(erff)
 add_math_entrypoint_object(exp)
 add_math_entrypoint_object(expf)
 add_math_entrypoint_object(expf16)
+add_math_entrypoint_object(expbf16)
 
 add_math_entrypoint_object(exp2)
 add_math_entrypoint_object(exp2f)
diff --git a/libc/src/math/expbf16.h b/libc/src/math/expbf16.h
new file mode 100644
index 0000000000000..7c7aed30b4a51
--- /dev/null
+++ b/libc/src/math/expbf16.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for expbf16 -----------------------*- 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_EXPBF16_H
+#define LLVM_LIBC_SRC_MATH_EXPBF16_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+bfloat16 expbf16(bfloat16 x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_EXPBF16_H
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 8074a3925626c..0adcc7fd31015 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -1441,6 +1441,28 @@ add_entrypoint_object(
     libc.src.errno.errno
 )
 
+add_entrypoint_object(
+  expbf16
+  SRCS
+    expbf16.cpp
+  HDRS
+    ../expbf16.h
+  DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
+    libc.src.__support.CPP.array
+    libc.src.__support.FPUtil.cast
+    libc.src.__support.FPUtil.except_value_utils
+    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.FPUtil.bfloat16
+    libc.src.__support.macros.optimization
+)
+
 add_entrypoint_object(
   exp2
   SRCS
diff --git a/libc/src/math/generic/expbf16.cpp b/libc/src/math/generic/expbf16.cpp
new file mode 100644
index 0000000000000..bd03660a4a11d
--- /dev/null
+++ b/libc/src/math/generic/expbf16.cpp
@@ -0,0 +1,184 @@
+//===-- BFloat16 e^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/expbf16.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/except_value_utils.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/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// Generated by Sollya with the following commands:
+//   > display = hexadecimal;
+//   > for i from -96 to 88 by 8 do print(i, round(exp(i), SG, RN) @ "f,");
+static constexpr float EXP_HI[24] = {
+    0x1.6a4p-139f,   0x1.07b71p-127f, 0x1.7fd974p-116f, 0x1.175afp-104f,
+    0x1.969d48p-93f, 0x1.27ec46p-81f, 0x1.aebabap-70f,  0x1.397924p-58f,
+    0x1.c8465p-47f,  0x1.4c1078p-35f, 0x1.e355bcp-24f,  0x1.5fc21p-12f,
+    0x1p0f,          0x1.749ea8p11f,  0x1.0f2ebep23f,   0x1.8ab7fcp34f,
+    0x1.1f43fcp46f,  0x1.a220d4p57f,  0x1.304d6ap69f,   0x1.baed16p80f,
+    0x1.425982p92f,  0x1.d531d8p103f, 0x1.55779cp115f,  0x1.f1056ep126f,
+};
+
+// Generated by Sollya with the following commands:
+//   > display = hexadecimal;
+//   > for i from 0 to 7.75 by 0.25 do print(round(exp(i), SG, RN) @ "f,");
+static constexpr float EXP_MID[32] = {
+    0x1p0f,         0x1.48b5e4p0f,  0x1.a61298p0f,  0x1.0ef9dcp1f,
+    0x1.5bf0a8p1f,  0x1.bec38ep1f,  0x1.1ed3fep2f,  0x1.704b6ap2f,
+    0x1.d8e64cp2f,  0x1.2f9b88p3f,  0x1.85d6fep3f,  0x1.f4907p3f,
+    0x1.415e5cp4f,  0x1.9ca53cp4f,  0x1.08ec72p5f,  0x1.542b2ep5f,
+    0x1.b4c902p5f,  0x1.186bf2p6f,  0x1.68118ap6f,  0x1.ce564ep6f,
+    0x1.28d38ap7f,  0x1.7d21eep7f,  0x1.e96244p7f,  0x1.3a30dp8f,
+    0x1.936dc6p8f,  0x1.0301a4p9f,  0x1.4c9222p9f,  0x1.ab0786p9f,
+    0x1.122886p10f, 0x1.6006b6p10f, 0x1.c402b6p10f, 0x1.223252p11f,
+};
+
+constexpr fputil::ExceptValues<bfloat16, 4> EXPBF16_EXCEPTS = {{
+    // (input, RZ output, RU offset, RD offset, RN offset)
+    // x = 0x40DB (6.84375)
+    // MPFR: RU=0x446B, RD=0x446A, RZ=0x446A, RN=0x446B
+    {0x40DBU, 0x446AU, 1U, 0U, 1U},
+    // x = 0x419D, keep original
+    {0x419DU, 0x4D9FU, 1U, 0U, 0U},
+    // x = 0x41F9 (31.125)
+    // MPFR: RU=0x55F0, RD=0x55EF, RZ=0x55EF, RN=0x55F0
+    {0x41F9U, 0x55EFU, 1U, 0U, 1U},
+    // x = 0xC19F (-19.875)
+    // MPFR: RU=0x3121, RD=0x3120, RZ=0x3120, RN=0x3121
+    {0xC19FU, 0x3120U, 1U, 0U, 1U},
+}};
+
+LLVM_LIBC_FUNCTION(bfloat16, expbf16, (bfloat16 x)) {
+  using FPBits = fputil::FPBits<bfloat16>;
+  FPBits x_bits(x);
+
+  uint16_t x_u = x_bits.uintval();
+  uint16_t x_abs = x_u & 0x7fffU;
+
+  // 0 <= |x| <= 2^(-3), or |x| >= 89, or x is NaN
+  if (LIBC_UNLIKELY(x_abs <= 0x3e00U || x_abs >= 0x42b2U)) {
+
+    // exp(NaN) = NaN
+    if (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;
+    }
+
+    // if x >= 89
+    if (x_bits.is_pos() && x_abs >= 0x42b2U) {
+      // exp(inf) = inf
+      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();
+      }
+    }
+
+    // x <= -93
+    if (x_u >= 0xc2baU) {
+      // exp(-inf) = +0
+      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);
+
+      switch (fputil::quick_get_round()) {
+      case FE_UPWARD:
+        return FPBits::min_subnormal().get_val();
+      default:
+        return FPBits::zero().get_val();
+      }
+    }
+
+    // 0 < |x| <= 2^(-3)
+    if (x_abs <= 0x3e00U && !x_bits.is_zero()) {
+      float xf = static_cast<float>(x);
+      // Degree-3 minimax polynomial generated by Sollya with the following
+      // commands:
+      //   > display = hexadecimal;
+      //   > P = fpminimax(expm1(x)/x, 2, [|SG...|], [-2^-7, 2^-7]);
+      //   > 1 + x * P;
+      //   0x1p0 + x * (0x1p0 + x * (0x1.00004p-1 + x * 0x1.555578p-3))
+      return fputil::cast<bfloat16>(
+          fputil::polyeval(xf, 0x1p+0f, 0x1p+0f, 0x1.0004p-1f, 0x1.555778p-3f));
+    }
+
+    // exp(0) = 1
+    if (x_bits.is_zero())
+      return bfloat16(1.0f);
+  }
+
+  if (auto r = EXPBF16_EXCEPTS.lookup(x_u); LIBC_UNLIKELY(r.has_value()))
+    return r.value();
+
+  // For -93 < x < 89, we do the following range reduction:
+  // x = hi + mid + lo
+  // where,
+  //    hi / 2^3 is an integer
+  //    mid * 2^2 is an integer
+  //    -2^3 <= lo <= 2^3
+  // also, hi + mid = round(4 * x) / x
+  // then,
+  //   exp(x) = exp(hi + mid + lo)
+  //          = exp(hi) * exp(mid) * exp(lo)
+  // we store 184/8 + 1 = 24 values for looking up exp(hi)
+  //    from -96 to 88
+  // we store 8*4 = 32 values for looking up exp(mid) since
+  //    mid will always have the bit pattern |bbb.bb| where
+  //    b can be either 0 or 1
+
+  float xf = static_cast<float>(x);
+  float kf = fputil::nearest_integer(xf * 4.0f);
+  int x_hi_mid = static_cast<int>(kf);
+  int x_hi = x_hi_mid >> 5;
+  int x_mid = x_hi_mid & 0b11111;
+  // lo = x - (hi + mid) = round(x * 4) / (-4) + x
+  float lo = fputil::multiply_add(kf, -0.25f, xf);
+
+  float exp_hi = EXP_HI[x_hi + 12];
+  float exp_mid = EXP_MID[x_mid];
+
+  // Degree-3 minimax polynomial generated by Sollya with the following
+  // commands:
+  //   > display = hexadecimal;
+  //   > P = fpminimax(expm1(x)/x, 2, [|SG...|], [-2^-7, 2^-7]);
+  //   > 1 + x * P;
+  //   0x1p0 + x * (0x1p0 + x * (0x1.00004p-1 + x * 0x1.555578p-3))
+  float exp_lo =
+      fputil::polyeval(lo, 0x1p+0f, 0x1p+0f, 0x1.0004p-1f, 0x1.555778p-3f);
+
+  return fputil::cast<bfloat16>(exp_hi * exp_mid * exp_lo);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 2d2d5287bb384..299762cbbc808 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -1138,6 +1138,18 @@ add_fp_unittest(
     libc.src.math.expf16
 )
 
+add_fp_unittest(
+  expbf16_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    expbf16_test.cpp
+  DEPENDS
+    libc.src.math.expbf16
+    libc.src.__support.FPUtil.bfloat16
+)
+
 add_fp_unittest(
   exp2_test
   NEED_MPFR
diff --git a/libc/test/src/math/expbf16_test.cpp b/libc/test/src/math/expbf16_test.cpp
new file mode 100644
index 0000000000000..35f247348f9dc
--- /dev/null
+++ b/libc/test/src/math/expbf16_test.cpp
@@ -0,0 +1,59 @@
+//===-- Exhaustive test for expbf16 ---------------------------------------===//
+//
+// 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/expbf16.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+using LlvmLibcExpBf16Test = 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;
+// static constexpr uint16_t POS_STOP = 0x3e00U;
+
+// range: [-0, -inf]
+static constexpr uint16_t NEG_START = 0x8000U;
+static constexpr uint16_t NEG_STOP = 0xff80U;
+
+TEST_F(LlvmLibcExpBf16Test, PositiveRange) {
+  for (uint16_t v = POS_START; v <= POS_STOP; ++v) {
+    bfloat16 x = FPBits(v).get_val();
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x,
+                                   LIBC_NAMESPACE::expbf16(x), 0.5);
+  }
+
+  auto test_value = [&](uint16_t v) {
+    bfloat16 x = FPBits(v).get_val();
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x,
+                                   LIBC_NAMESPACE::expbf16(x), 0.5);
+  };
+
+  auto test_value_f = [&](float v) {
+    bfloat16 x(v);
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x,
+                                   LIBC_NAMESPACE::expbf16(x), 0.5);
+  };
+
+  test_value(0xc2c8);
+  test_value(0xc2ba);
+
+  test_value_f(17.45f);
+}
+
+TEST_F(LlvmLibcExpBf16Test, NegativeRange) {
+  for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) {
+    bfloat16 x = FPBits(v).get_val();
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp, x,
+                                   LIBC_NAMESPACE::expbf16(x), 0.5);
+  }
+}
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 42a97ba10b601..8373423b7bc13 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -1395,6 +1395,20 @@ add_fp_unittest(
     libc.src.__support.FPUtil.cast
 )
 
+add_fp_unittest(
+  expbf16_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    expbf16_test.cpp
+  DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
+    libc.src.math.expbf16
+    libc.src.__support.FPUtil.bfloat16
+    libc.src.__support.FPUtil.cast
+)
+
 add_fp_unittest(
   exp2_test
   SUITE
diff --git a/libc/test/src/math/smoke/expbf16_test.cpp b/libc/test/src/math/smoke/expbf16_test.cpp
new file mode 100644
index 0000000000000..8576b78e4391e
--- /dev/null
+++ b/libc/test/src/math/smoke/expbf16_test.cpp
@@ -0,0 +1,63 @@
+//===-- Unittests for ex...
[truncated]

Signed-off-by: Krishna Pandey <[email protected]>
Signed-off-by: Krishna Pandey <[email protected]>
Signed-off-by: Krishna Pandey <[email protected]>
// range: [0, inf]
static constexpr uint16_t POS_START = 0x0000U;
static constexpr uint16_t POS_STOP = 0x7f80U;
// static constexpr uint16_t POS_STOP = 0x3e00U;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed in 0816194

Signed-off-by: Krishna Pandey <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants