[libc-commits] [libc] [llvm] [libc][math] Impl bfloat16 lgamma function. (PR #199312)

Kiriti Ponduri via libc-commits libc-commits at lists.llvm.org
Mon May 25 01:27:35 PDT 2026


https://github.com/udaykiriti updated https://github.com/llvm/llvm-project/pull/199312

>From 8df441e478ca4336f383e1fb22786f94d2cbfc86 Mon Sep 17 00:00:00 2001
From: udaykiriti <udaykiriti9 at gmail.com>
Date: Sat, 23 May 2026 07:56:37 +0530
Subject: [PATCH 1/2] [libc][math] Impl bfloat16 lgamma function.

Signed-off-by: udaykiriti <udaykiriti9 at gmail.com>
---
 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/shared/math.h                            |   1 +
 libc/shared/math/lgammabf16.h                 |  23 +++
 libc/src/__support/math/CMakeLists.txt        |  16 ++
 libc/src/__support/math/lgammabf16.h          | 193 ++++++++++++++++++
 libc/src/math/CMakeLists.txt                  |   1 +
 libc/src/math/generic/CMakeLists.txt          |  12 ++
 libc/src/math/generic/lgammabf16.cpp          |  18 ++
 libc/src/math/lgammabf16.h                    |  21 ++
 libc/test/shared/CMakeLists.txt               |   1 +
 libc/test/shared/shared_math_test.cpp         |   3 +-
 libc/test/src/math/CMakeLists.txt             |  12 ++
 libc/test/src/math/lgammabf16_test.cpp        |  26 +++
 libc/test/src/math/smoke/CMakeLists.txt       |  12 ++
 libc/test/src/math/smoke/lgammabf16_test.cpp  |  32 +++
 libc/utils/MPFRWrapper/MPCommon.cpp           |   7 +
 libc/utils/MPFRWrapper/MPCommon.h             |   1 +
 libc/utils/MPFRWrapper/MPFRUtils.cpp          |   2 +
 libc/utils/MPFRWrapper/MPFRUtils.h            |   1 +
 .../llvm-project-overlay/libc/BUILD.bazel     |  23 +++
 31 files changed, 416 insertions(+), 1 deletion(-)
 create mode 100644 libc/shared/math/lgammabf16.h
 create mode 100644 libc/src/__support/math/lgammabf16.h
 create mode 100644 libc/src/math/generic/lgammabf16.cpp
 create mode 100644 libc/src/math/lgammabf16.h
 create mode 100644 libc/test/src/math/lgammabf16_test.cpp
 create mode 100644 libc/test/src/math/smoke/lgammabf16_test.cpp

diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt
index dcb50135232e2..2c27769fe0786 100644
--- a/libc/config/baremetal/aarch64/entrypoints.txt
+++ b/libc/config/baremetal/aarch64/entrypoints.txt
@@ -835,6 +835,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.iscanonicalbf16
   libc.src.math.issignalingbf16
   libc.src.math.ldexpbf16
+  libc.src.math.lgammabf16
   libc.src.math.llogbbf16
   libc.src.math.llrintbf16
   libc.src.math.llroundbf16
diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index fac62bac939cc..78b0ee578f472 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -846,6 +846,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.iscanonicalbf16
   libc.src.math.issignalingbf16
   libc.src.math.ldexpbf16
+  libc.src.math.lgammabf16
   libc.src.math.llogbbf16
   libc.src.math.llrintbf16
   libc.src.math.llroundbf16
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index a3b96225ff09d..9893ee44d4e18 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -843,6 +843,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.iscanonicalbf16
   libc.src.math.issignalingbf16
   libc.src.math.ldexpbf16
+  libc.src.math.lgammabf16
   libc.src.math.llogbbf16
   libc.src.math.llrintbf16
   libc.src.math.llroundbf16
diff --git a/libc/config/darwin/aarch64/entrypoints.txt b/libc/config/darwin/aarch64/entrypoints.txt
index 914d2b7918da1..56abccb09dce7 100644
--- a/libc/config/darwin/aarch64/entrypoints.txt
+++ b/libc/config/darwin/aarch64/entrypoints.txt
@@ -656,6 +656,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.iscanonicalbf16
   libc.src.math.issignalingbf16
   libc.src.math.ldexpbf16
+  libc.src.math.lgammabf16
   libc.src.math.llogbbf16
   libc.src.math.llrintbf16
   libc.src.math.llroundbf16
diff --git a/libc/config/darwin/x86_64/entrypoints.txt b/libc/config/darwin/x86_64/entrypoints.txt
index b941c968255e8..bc164e4fcd3f6 100644
--- a/libc/config/darwin/x86_64/entrypoints.txt
+++ b/libc/config/darwin/x86_64/entrypoints.txt
@@ -278,6 +278,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.iscanonicalbf16
   libc.src.math.issignalingbf16
   libc.src.math.ldexpbf16
+  libc.src.math.lgammabf16
   libc.src.math.llogbbf16
   libc.src.math.llrintbf16
   libc.src.math.llroundbf16
diff --git a/libc/config/gpu/amdgpu/entrypoints.txt b/libc/config/gpu/amdgpu/entrypoints.txt
index c76900a8371f7..913db74f49f12 100644
--- a/libc/config/gpu/amdgpu/entrypoints.txt
+++ b/libc/config/gpu/amdgpu/entrypoints.txt
@@ -684,6 +684,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.iscanonicalbf16
   libc.src.math.issignalingbf16
   libc.src.math.ldexpbf16
+  libc.src.math.lgammabf16
   libc.src.math.llogbbf16
   libc.src.math.llrintbf16
   libc.src.math.llroundbf16
diff --git a/libc/config/gpu/nvptx/entrypoints.txt b/libc/config/gpu/nvptx/entrypoints.txt
index 6538732f785f5..1fdcd32ff10ee 100644
--- a/libc/config/gpu/nvptx/entrypoints.txt
+++ b/libc/config/gpu/nvptx/entrypoints.txt
@@ -686,6 +686,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.iscanonicalbf16
   libc.src.math.issignalingbf16
   libc.src.math.ldexpbf16
+  libc.src.math.lgammabf16
   libc.src.math.llogbbf16
   libc.src.math.llrintbf16
   libc.src.math.llroundbf16
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index a50923fddec54..e7d42623cd56f 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -948,6 +948,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.iscanonicalbf16
   libc.src.math.issignalingbf16
   libc.src.math.ldexpbf16
+  libc.src.math.lgammabf16
   libc.src.math.llogbbf16
   libc.src.math.llrintbf16
   libc.src.math.llroundbf16
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 49b30ef1830f3..8bac9164441d6 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -526,6 +526,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.iscanonicalbf16
   libc.src.math.issignalingbf16
   libc.src.math.ldexpbf16
+  libc.src.math.lgammabf16
   libc.src.math.llogbbf16
   libc.src.math.llrintbf16
   libc.src.math.llroundbf16
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 51c769d853a52..5374674401b65 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -969,6 +969,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.iscanonicalbf16
   libc.src.math.issignalingbf16
   libc.src.math.ldexpbf16
+  libc.src.math.lgammabf16
   libc.src.math.llogbbf16
   libc.src.math.llrintbf16
   libc.src.math.llroundbf16
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 5545790fecd85..c3d284b758254 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1034,6 +1034,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.iscanonicalbf16
   libc.src.math.issignalingbf16
   libc.src.math.ldexpbf16
+  libc.src.math.lgammabf16
   libc.src.math.llogbbf16
   libc.src.math.llrintbf16
   libc.src.math.llroundbf16
diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index 94d1d00e676d9..5f14967e3c8a7 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -368,6 +368,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS
   libc.src.math.iscanonicalbf16
   libc.src.math.issignalingbf16
   libc.src.math.ldexpbf16
+  libc.src.math.lgammabf16
   libc.src.math.llogbbf16
   libc.src.math.llrintbf16
   libc.src.math.llroundbf16
diff --git a/libc/shared/math.h b/libc/shared/math.h
index 2baeb07294a3b..9482efb1dc1b7 100644
--- a/libc/shared/math.h
+++ b/libc/shared/math.h
@@ -305,6 +305,7 @@
 #include "math/ldexpf128.h"
 #include "math/ldexpf16.h"
 #include "math/ldexpl.h"
+#include "math/lgammabf16.h"
 #include "math/llogb.h"
 #include "math/llogbbf16.h"
 #include "math/llogbf.h"
diff --git a/libc/shared/math/lgammabf16.h b/libc/shared/math/lgammabf16.h
new file mode 100644
index 0000000000000..85fdd03ff60ab
--- /dev/null
+++ b/libc/shared/math/lgammabf16.h
@@ -0,0 +1,23 @@
+//===-- Shared header for lgammabf16 ----------------------------*- 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_LGAMMABF16_H
+#define LLVM_LIBC_SHARED_MATH_LGAMMABF16_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/math/lgammabf16.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace shared {
+
+using math::lgammabf16;
+
+} // namespace shared
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SHARED_MATH_LGAMMABF16_H
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index 9e3ec26cdc881..189d1d004abac 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -46,6 +46,22 @@ add_header_library(
     libc.src.__support.macros.properties.types
 )
 
+add_header_library(
+  lgammabf16
+  HDRS
+    lgammabf16.h
+  DEPENDS
+    libc.src.__support.CPP.bit
+    libc.src.__support.FPUtil.fp_bits
+    libc.src.__support.FPUtil.bfloat16
+    libc.src.__support.FPUtil.cast
+    libc.src.__support.FPUtil.fenv_impl
+    libc.src.__support.macros.config
+    libc.src.__support.macros.optimization
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
+)
+
 add_header_library(
   acosh_float_constants
   HDRS
diff --git a/libc/src/__support/math/lgammabf16.h b/libc/src/__support/math/lgammabf16.h
new file mode 100644
index 0000000000000..70694544fcc33
--- /dev/null
+++ b/libc/src/__support/math/lgammabf16.h
@@ -0,0 +1,193 @@
+//===-- Implementation of lgammabf16 ----------------------------*- 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_LGAMMABF16_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_LGAMMABF16_H
+
+#include "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
+#include "src/__support/CPP/bit.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/macros/config.h"
+#include "src/__support/macros/optimization.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
+
+// Compute natural log of positive float x using range reduction.
+// x = 2^e * m, m in [1, 2)
+// ln(x) = e * ln(2) + ln(m)
+// ln(m) approximated by degree-5 poly centered at 1.5
+// Maximum relative error: ~1.71e-05 (well within bfloat16 precision)
+LIBC_INLINE float lgamma_logf(float x) {
+  constexpr float LN_COEFFS[6] = {
+      0x1.9f309cp-2f,  // c0
+      0x1.555720p-1f,  // c1
+      -0x1.c615ecp-3f, // c2
+      0x1.929d98p-4f,  // c3
+      -0x1.c2e22ap-5f, // c4
+      0x1.ef2630p-6f,  // c5
+  };
+  constexpr float LN2 = 0x1.62e430p-1f;
+
+  uint32_t bits = cpp::bit_cast<uint32_t>(x);
+  int e_tmp = (bits >> 23) & 0xFFU;
+
+  // Normalize subnormal float32 values
+  if (e_tmp == 0) {
+    x *= 0x1.0p23f; // Multiply by 2^23
+    bits = cpp::bit_cast<uint32_t>(x);
+    e_tmp = ((bits >> 23) & 0xFFU) - 23;
+  }
+
+  int e = e_tmp - 127;
+
+  // Set exponent to 127 (i.e. value in [1,2))
+  bits = (bits & 0x807FFFFFU) | (127U << 23);
+  float m = cpp::bit_cast<float>(bits);
+
+  float t = m - 1.5f;
+  return static_cast<float>(e) * LN2 +
+         fputil::polyeval(t, LN_COEFFS[0], LN_COEFFS[1], LN_COEFFS[2],
+                          LN_COEFFS[3], LN_COEFFS[4], LN_COEFFS[5]);
+}
+
+// Coefficients for lgamma on [n, n+1), centered at n+0.5
+// Each row: {c0, c1, c2, c3, c4} for fputil::polyeval in (x - (n+0.5))
+// Generated by numpy.polyfit with degree 4
+// Intervals: n = 1..7
+// (Maximum relative errors per intrvel)
+LIBC_INLINE_VAR constexpr float LGAMMA_POLY[7][5] = {
+    // [1,2), center=1.5, max_relative_err=1.29e-04
+    {-0x1.eeb280p-4f, 0x1.2f128ap-5f, 0x1.de1488p-2f, -0x1.2d373cp-3f,
+     0x1.08d8aep-4f},
+    // [2,3), center=2.5, max_rel_err=9.98e-06
+    {0x1.2383fcp-2f, 0x1.6809bep-1f, 0x1.f61322p-3f, -0x1.48c82ap-5f,
+     0x1.3b3cccp-7f},
+    // [3,4), center=3.5, max_rel_err=2.06e-06
+    {0x1.337302p+0f, 0x1.1a6912p+0f, 0x1.52475cp-3f, -0x1.2a2876p-6f,
+     0x1.859be8p-9f},
+    // [4,5), center=4.5, max_rel_err=6.61e-07
+    {0x1.3a140ap+1f, 0x1.638d3ep+0f, 0x1.fd62a0p-4f, -0x1.51efeep-7f,
+     0x1.4e023cp-10f},
+    // [5,6), center=5.5, max_rel_err=2.72e-07
+    {0x1.fa99a6p+1f, 0x1.9c70aep+0f, 0x1.984080p-4f, -0x1.b21838p-8f,
+     0x1.58a5b2p-11f},
+    // [6,7), center=6.5, max_rel_err=1.32e-07
+    {0x1.6a676ap+2f, 0x1.cafc46p+0f, 0x1.548cdap-4f, -0x1.2e0b0cp-8f,
+     0x1.909642p-12f},
+    // [7,8), center=7.5, max_rel_err=7.10e-08
+    {0x1.e23306p+2f, 0x1.f25eb8p+0f, 0x1.2413bep-4f, -0x1.bc5850p-9f,
+     0x1.f9d4bep-13f},
+};
+
+// Compute lgamma for x >= 1 using polynomial or Stirling
+LIBC_INLINE float lgamma_positive(float x) {
+  if (LIBC_UNLIKELY(x == 1.0f || x == 2.0f))
+    return 0.0f;
+  // For x >= 8: Stirling approximation
+  // lgamma(x) ~ (x-0.5)*ln(x) - x + 0.5*ln(2*pi)
+  if (x >= 8.0f) {
+    constexpr float HALF_LN_2PI = 0x1.6840e6p-1f;
+    float lx = lgamma_logf(x);
+    // using FMA: (x - 0.5)*ln(x) - x + 0.5*ln(2*pi)
+    return fputil::multiply_add(x - 0.5f, lx, -x + HALF_LN_2PI);
+  }
+
+  // For x in [1, 8): use piecewise polynomial
+  int n = static_cast<int>(x); // floor for x >= 1
+  if (n >= 7)
+    n = 7;
+  float t = x - (static_cast<float>(n) + 0.5f);
+  const float *c = LGAMMA_POLY[n - 1];
+  // Co-efficients stored as {c0, c1, c2, c3, c4}
+  return fputil::polyeval(t, c[0], c[1], c[2], c[3], c[4]);
+}
+
+LIBC_INLINE bfloat16 lgammabf16(bfloat16 x) {
+  using FPBits = fputil::FPBits<bfloat16>;
+  FPBits x_bits(x);
+
+  // Handle 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;
+  }
+
+  uint16_t x_u = x_bits.uintval();
+  uint16_t x_abs = x_u & 0x7fffU;
+
+  // +Inf or -Inf -> +Inf
+  if (LIBC_UNLIKELY(x_abs == 0x7f80U))
+    return FPBits::inf(Sign::POS).get_val();
+
+  // +-0 -> +Inf (pole error)
+  if (LIBC_UNLIKELY(x_abs == 0U)) {
+    fputil::set_errno_if_required(ERANGE);
+    fputil::raise_except_if_required(FE_DIVBYZERO);
+    return FPBits::inf(Sign::POS).get_val();
+  }
+
+  float xf = static_cast<float>(x);
+
+  // Negative integers -> +Inf (pole error)
+  if (LIBC_UNLIKELY(x_bits.is_neg())) {
+    int biased_exp = x_abs >> FPBits::FRACTION_LEN;
+    if (biased_exp >= FPBits::EXP_BIAS) {
+      int e = biased_exp - FPBits::EXP_BIAS;
+      if (e >= FPBits::FRACTION_LEN ||
+          (x_bits.get_mantissa() &
+           static_cast<uint16_t>((1U << (FPBits::FRACTION_LEN - e)) - 1U)) ==
+              0U) {
+        fputil::set_errno_if_required(ERANGE);
+        fputil::raise_except_if_required(FE_DIVBYZERO);
+        return FPBits::inf(Sign::POS).get_val();
+      }
+    }
+
+    // Negative non-integer: reflection formula
+    // lgamma(x) = ln(pi) - ln|sin(pi*x)| - lgamma(1-x)
+    constexpr float LN_PI = 0x1.250d06p+0f; // ln(pi)
+    float ax = -xf;
+    float frac = ax - static_cast<float>(static_cast<int>(ax));
+
+    constexpr float A1 = 0x1.55553cp-2f; // pi^2/6 approx
+    constexpr float A2 = 0x1.11100ap-7f; // pi^4/120 approx
+    constexpr float PI = 0x1.921fb6p+1f;
+    float frac2 = frac * frac;
+    // sin(pi*frac) = PI * frac * polyeval(frac^2, 1, -A1, A2)
+    float sin_pi_frac = PI * frac * fputil::polyeval(frac2, 1.0f, -A1, A2);
+    if (sin_pi_frac < 0.0f)
+      sin_pi_frac = -sin_pi_frac;
+
+    float log_sin = lgamma_logf(sin_pi_frac);
+    float result = LN_PI - log_sin - lgamma_positive(1.0f + ax);
+    return fputil::cast<bfloat16>(result);
+  }
+
+  // Positive x in (0, 1): use recurrence lgamma(x) = lgamma(x+1) - ln(x)
+  if (xf < 1.0f) {
+    float lnx = lgamma_logf(xf);
+    return fputil::cast<bfloat16>(lgamma_positive(xf + 1.0f) - lnx);
+  }
+
+  // Positive x >= 1
+  return fputil::cast<bfloat16>(lgamma_positive(xf));
+}
+
+} // namespace math
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LGAMMABF16_H
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index b53817e2a1729..b50b848df999e 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -596,6 +596,7 @@ add_math_entrypoint_object(tanpif16)
 add_math_entrypoint_object(tgamma)
 add_math_entrypoint_object(tgammaf)
 add_math_entrypoint_object(lgamma)
+add_math_entrypoint_object(lgammabf16)
 add_math_entrypoint_object(lgamma_r)
 
 add_math_entrypoint_object(totalorder)
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 7ccbddba07b8d..c03843f2fcfb3 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -4869,6 +4869,18 @@ add_entrypoint_object(
     libc.src.__support.math.bf16fmal
 )
 
+
+add_entrypoint_object(
+  lgammabf16
+  SRCS
+    lgammabf16.cpp
+  HDRS
+    ../lgammabf16.h
+  DEPENDS
+    libc.src.__support.math.lgammabf16
+    libc.src.__support.FPUtil.bfloat16
+)
+
 add_entrypoint_object(
   bf16fmaf128
   SRCS
diff --git a/libc/src/math/generic/lgammabf16.cpp b/libc/src/math/generic/lgammabf16.cpp
new file mode 100644
index 0000000000000..a26e5fe437a90
--- /dev/null
+++ b/libc/src/math/generic/lgammabf16.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of lgammabf16 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/lgammabf16.h"
+#include "src/__support/math/lgammabf16.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(bfloat16, lgammabf16, (bfloat16 x)) {
+  return math::lgammabf16(x);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/lgammabf16.h b/libc/src/math/lgammabf16.h
new file mode 100644
index 0000000000000..965c8c881eb03
--- /dev/null
+++ b/libc/src/math/lgammabf16.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for lgammabf16 --------------------*- 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_LGAMMABF16_H
+#define LLVM_LIBC_SRC_MATH_LGAMMABF16_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+bfloat16 lgammabf16(bfloat16 x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_LGAMMABF16_H
diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt
index 84a8d4bf79b3d..237a7b1e209f1 100644
--- a/libc/test/shared/CMakeLists.txt
+++ b/libc/test/shared/CMakeLists.txt
@@ -297,6 +297,7 @@ add_fp_unittest(
     libc.src.__support.math.ldexpbf16
     libc.src.__support.math.ldexpf
     libc.src.__support.math.ldexpl
+    libc.src.__support.math.lgammabf16
     libc.src.__support.math.llogb
     libc.src.__support.math.llogbbf16
     libc.src.__support.math.llrint
diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp
index 634778380dc8e..c42c2ffd12f53 100644
--- a/libc/test/shared/shared_math_test.cpp
+++ b/libc/test/shared/shared_math_test.cpp
@@ -785,7 +785,8 @@ TEST(LlvmLibcSharedMathTest, AllBFloat16) {
 
   EXPECT_FP_EQ(bfloat16(5.0),
                LIBC_NAMESPACE::shared::hypotbf16(bfloat16(4.0), bfloat16(3.0)));
-
+  EXPECT_FP_EQ(bfloat16(0.0f),
+               LIBC_NAMESPACE::shared::lgammabf16(bfloat16(1.0f)));
   EXPECT_FP_EQ(bfloat16(0.0), LIBC_NAMESPACE::shared::logbbf16(bfloat16(1.0f)));
 
   bfloat16 setpayloadbf16_res = bfloat16(0.0);
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 4213c11eca515..ac7a1963ad6ce 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -30,6 +30,18 @@ add_fp_unittest(
     FMA_OPT__ONLY
 )
 
+add_fp_unittest(
+  lgammabf16_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    lgammabf16_test.cpp
+  DEPENDS
+    libc.src.math.lgammabf16
+    libc.src.__support.FPUtil.bfloat16
+)
+
 add_fp_unittest(
   cos_test
   NEED_MPFR
diff --git a/libc/test/src/math/lgammabf16_test.cpp b/libc/test/src/math/lgammabf16_test.cpp
new file mode 100644
index 0000000000000..509df108158d9
--- /dev/null
+++ b/libc/test/src/math/lgammabf16_test.cpp
@@ -0,0 +1,26 @@
+//===-- Exhaustive test for lgammabf16 ------------------------------------===//
+//
+// 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/lgammabf16.h"
+#include "test/src/math/exhaustive/exhaustive_test.h"
+
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
+
+using LlvmLibcLgammabf16ExhaustiveTest =
+    LlvmLibcUnaryOpExhaustiveMathTest<LIBC_NAMESPACE::fputil::BFloat16,
+                                      mpfr::Operation::Lgamma,
+                                      LIBC_NAMESPACE::lgammabf16>;
+
+TEST_F(LlvmLibcLgammabf16ExhaustiveTest, PositiveRange) {
+  test_full_range_all_roundings(0x0000U, 0x7F80U);
+}
+
+TEST_F(LlvmLibcLgammabf16ExhaustiveTest, NegativeRange) {
+  test_full_range_all_roundings(0x8000U, 0xFF80U);
+}
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 28b85b1a25bbd..ad7387a52d41c 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -36,6 +36,18 @@ add_fp_unittest(
     libc.src.__support.FPUtil.fp_bits
 )
 
+add_fp_unittest(
+  lgammabf16_test
+  UNIT_TEST_ONLY
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    lgammabf16_test.cpp
+  DEPENDS
+    libc.src.math.lgammabf16
+    libc.src.__support.FPUtil.bfloat16
+)
+
 add_fp_unittest(
   cospif16_test
   SUITE
diff --git a/libc/test/src/math/smoke/lgammabf16_test.cpp b/libc/test/src/math/smoke/lgammabf16_test.cpp
new file mode 100644
index 0000000000000..393cae08fd10c
--- /dev/null
+++ b/libc/test/src/math/smoke/lgammabf16_test.cpp
@@ -0,0 +1,32 @@
+//===-- Unittests for lgammabf16 ------------------------------------------===//
+//
+// 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 "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
+#include "src/__support/FPUtil/bfloat16.h"
+#include "src/math/lgammabf16.h"
+#include "test/UnitTest/FEnvSafeTest.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+
+class LlvmLibcLgammaBf16Test : public LIBC_NAMESPACE::testing::FEnvSafeTest {
+  DECLARE_SPECIAL_CONSTANTS(bfloat16)
+public:
+  void test_special_numbers() {
+    EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::lgammabf16(aNaN));
+    EXPECT_FP_EQ(inf, LIBC_NAMESPACE::lgammabf16(zero));
+    EXPECT_FP_EQ(inf, LIBC_NAMESPACE::lgammabf16(neg_zero));
+    EXPECT_FP_EQ(inf, LIBC_NAMESPACE::lgammabf16(inf));
+    EXPECT_FP_EQ(inf, LIBC_NAMESPACE::lgammabf16(neg_inf));
+    EXPECT_FP_EQ(zero, LIBC_NAMESPACE::lgammabf16(bfloat16(1.0f)));
+    EXPECT_FP_EQ(zero, LIBC_NAMESPACE::lgammabf16(bfloat16(2.0f)));
+    EXPECT_FP_EQ(inf, LIBC_NAMESPACE::lgammabf16(bfloat16(-1.0f)));
+    EXPECT_FP_EQ(inf, LIBC_NAMESPACE::lgammabf16(bfloat16(-2.0f)));
+  }
+};
+
+TEST_F(LlvmLibcLgammaBf16Test, SpecialNumbers) { test_special_numbers(); }
diff --git a/libc/utils/MPFRWrapper/MPCommon.cpp b/libc/utils/MPFRWrapper/MPCommon.cpp
index bdd8286148641..2d95148cc2a0b 100644
--- a/libc/utils/MPFRWrapper/MPCommon.cpp
+++ b/libc/utils/MPFRWrapper/MPCommon.cpp
@@ -379,6 +379,13 @@ MPFRNumber MPFRNumber::log1p() const {
   return result;
 }
 
+MPFRNumber MPFRNumber::lgamma() const {
+  MPFRNumber result(*this);
+  int signp;
+  mpfr_lgamma(result.value, &signp, value, mpfr_rounding);
+  return result;
+}
+
 MPFRNumber MPFRNumber::pow(const MPFRNumber &b) {
   MPFRNumber result(*this);
   mpfr_pow(result.value, value, b.value, mpfr_rounding);
diff --git a/libc/utils/MPFRWrapper/MPCommon.h b/libc/utils/MPFRWrapper/MPCommon.h
index 935a2614968a2..47bebffef9fec 100644
--- a/libc/utils/MPFRWrapper/MPCommon.h
+++ b/libc/utils/MPFRWrapper/MPCommon.h
@@ -218,6 +218,7 @@ class MPFRNumber {
   MPFRNumber log10() const;
   MPFRNumber log10p1() const;
   MPFRNumber log1p() const;
+  MPFRNumber lgamma() const;
   MPFRNumber pow(const MPFRNumber &b);
   MPFRNumber remquo(const MPFRNumber &divisor, int &quotient);
   MPFRNumber round() const;
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index 356764302bda8..2330ec05003b6 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -87,6 +87,8 @@ unary_operation(Operation op, InputType input, unsigned int precision,
     return mpfrInput.log10p1();
   case Operation::Log1p:
     return mpfrInput.log1p();
+  case Operation::Lgamma:
+    return mpfrInput.lgamma();
   case Operation::Mod2PI:
     return mpfrInput.mod_2pi();
   case Operation::ModPIOver2:
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h
index 6c1b15598b0f2..a9029b83c1e2f 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.h
+++ b/libc/utils/MPFRWrapper/MPFRUtils.h
@@ -54,6 +54,7 @@ enum class Operation : int {
   Log10,
   Log10p1,
   Log1p,
+  Lgamma,
   Mod2PI,
   ModPIOver2,
   ModPIOver4,
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 87963e4524b39..297f0fa2e4720 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -6233,6 +6233,22 @@ libc_support_library(
     ],
 )
 
+libc_support_library(
+    name = "__support_math_lgammabf16",
+    hdrs = ["src/__support/math/lgammabf16.h"],
+    deps = [
+        ":__support_cpp_bit",
+        ":__support_fputil_bfloat16",
+        ":__support_fputil_cast",
+        ":__support_fputil_fenv_impl",
+        ":__support_fputil_fp_bits",
+        ":__support_macros_config",
+        ":__support_macros_optimization",
+        ":hdr_errno_macros",
+        ":hdr_fenv_macros",
+    ],
+)
+
 libc_support_library(
     name = "__support_math_llogbbf16",
     hdrs = ["src/__support/math/llogbbf16.h"],
@@ -11397,6 +11413,13 @@ libc_math_function(
     ],
 )
 
+libc_math_function(
+    name = "lgammabf16",
+    additional_deps = [
+        ":__support_math_lgammabf16",
+    ],
+)
+
 libc_math_function(
     name = "llogb",
     additional_deps = [

>From b4f798b71d6891e9778f26d85e70f34bb9f0fa54 Mon Sep 17 00:00:00 2001
From: udaykiriti <udaykiriti9 at gmail.com>
Date: Mon, 25 May 2026 13:56:47 +0530
Subject: [PATCH 2/2] [libc][math] Implement lgammabf16 function

Signed-off-by: udaykiriti <udaykiriti9 at gmail.com>
---
 libc/src/__support/math/CMakeLists.txt        |  2 +
 libc/test/src/math/lgammabf16_test.cpp        | 73 ++++++++++++++++---
 .../llvm-project-overlay/libc/BUILD.bazel     |  2 +
 3 files changed, 67 insertions(+), 10 deletions(-)

diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index 189d1d004abac..792c77bea06ab 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -56,6 +56,8 @@ add_header_library(
     libc.src.__support.FPUtil.bfloat16
     libc.src.__support.FPUtil.cast
     libc.src.__support.FPUtil.fenv_impl
+    libc.src.__support.FPUtil.PolyEval  
+    libc.src.__support.FPUtil.multiply_add 
     libc.src.__support.macros.config
     libc.src.__support.macros.optimization
     libc.hdr.errno_macros
diff --git a/libc/test/src/math/lgammabf16_test.cpp b/libc/test/src/math/lgammabf16_test.cpp
index 509df108158d9..a137257381e84 100644
--- a/libc/test/src/math/lgammabf16_test.cpp
+++ b/libc/test/src/math/lgammabf16_test.cpp
@@ -1,4 +1,4 @@
-//===-- Exhaustive test for lgammabf16 ------------------------------------===//
+//===-- Unittests for lgammabf16 ------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -8,19 +8,72 @@
 
 #include "src/__support/FPUtil/bfloat16.h"
 #include "src/math/lgammabf16.h"
-#include "test/src/math/exhaustive/exhaustive_test.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+using LlvmLibcLgammabf16Test = LIBC_NAMESPACE::testing::FPTest<bfloat16>;
 
 namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
 
-using LlvmLibcLgammabf16ExhaustiveTest =
-    LlvmLibcUnaryOpExhaustiveMathTest<LIBC_NAMESPACE::fputil::BFloat16,
-                                      mpfr::Operation::Lgamma,
-                                      LIBC_NAMESPACE::lgammabf16>;
+// Subnormal positive range
+static constexpr uint16_t SUBNORM_POS_START = 0x0001U;
+static constexpr uint16_t SUBNORM_POS_STOP = 0x007FU;
+
+// Normal positive range
+static constexpr uint16_t NORMAL_POS_START = 0x0080U;
+static constexpr uint16_t NORMAL_POS_STOP = 0x7F7FU;
+
+// Subnormal negative range
+static constexpr uint16_t SUBNORM_NEG_START = 0x8001U;
+static constexpr uint16_t SUBNORM_NEG_STOP = 0x807FU;
 
-TEST_F(LlvmLibcLgammabf16ExhaustiveTest, PositiveRange) {
-  test_full_range_all_roundings(0x0000U, 0x7F80U);
+// Normal negative range
+static constexpr uint16_t NORMAL_NEG_START = 0x8080U;
+static constexpr uint16_t NORMAL_NEG_STOP = 0xFF7FU;
+
+TEST_F(LlvmLibcLgammabf16Test, SpecialNumbers) {
+  EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::lgammabf16(aNaN));
+  EXPECT_FP_EQ(inf, LIBC_NAMESPACE::lgammabf16(zero));
+  EXPECT_FP_EQ(inf, LIBC_NAMESPACE::lgammabf16(neg_zero));
+  EXPECT_FP_EQ(inf, LIBC_NAMESPACE::lgammabf16(inf));
+  EXPECT_FP_EQ(inf, LIBC_NAMESPACE::lgammabf16(neg_inf));
+  // lgamma(1) = lgamma(2) = 0
+  EXPECT_FP_EQ(zero, LIBC_NAMESPACE::lgammabf16(bfloat16(1.0f)));
+  EXPECT_FP_EQ(zero, LIBC_NAMESPACE::lgammabf16(bfloat16(2.0f)));
+  // Negative integers are poles -> +inf
+  EXPECT_FP_EQ(inf, LIBC_NAMESPACE::lgammabf16(bfloat16(-1.0f)));
+  EXPECT_FP_EQ(inf, LIBC_NAMESPACE::lgammabf16(bfloat16(-2.0f)));
 }
 
-TEST_F(LlvmLibcLgammabf16ExhaustiveTest, NegativeRange) {
-  test_full_range_all_roundings(0x8000U, 0xFF80U);
+TEST_F(LlvmLibcLgammabf16Test, SubnormalPositiveRange) {
+  for (uint16_t v = SUBNORM_POS_START; v <= SUBNORM_POS_STOP; ++v) {
+    bfloat16 x = FPBits(v).get_val();
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Lgamma, x,
+                                   LIBC_NAMESPACE::lgammabf16(x), 0.5);
+  }
 }
+
+TEST_F(LlvmLibcLgammabf16Test, NormalPositiveRange) {
+  for (uint16_t v = NORMAL_POS_START; v <= NORMAL_POS_STOP; ++v) {
+    bfloat16 x = FPBits(v).get_val();
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Lgamma, x,
+                                   LIBC_NAMESPACE::lgammabf16(x), 0.5);
+  }
+}
+
+TEST_F(LlvmLibcLgammabf16Test, SubnormalNegativeRange) {
+  for (uint16_t v = SUBNORM_NEG_START; v <= SUBNORM_NEG_STOP; ++v) {
+    bfloat16 x = FPBits(v).get_val();
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Lgamma, x,
+                                   LIBC_NAMESPACE::lgammabf16(x), 0.5);
+  }
+}
+
+TEST_F(LlvmLibcLgammabf16Test, NormalNegativeRange) {
+  for (uint16_t v = NORMAL_NEG_START; v <= NORMAL_NEG_STOP; ++v) {
+    bfloat16 x = FPBits(v).get_val();
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Lgamma, x,
+                                   LIBC_NAMESPACE::lgammabf16(x), 0.5);
+  }
+}
\ No newline at end of file
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 297f0fa2e4720..55daa7e103e42 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -6242,6 +6242,8 @@ libc_support_library(
         ":__support_fputil_cast",
         ":__support_fputil_fenv_impl",
         ":__support_fputil_fp_bits",
+        ":__support_fputil_multiply_add",
+        ":__support_fputil_polyeval",
         ":__support_macros_config",
         ":__support_macros_optimization",
         ":hdr_errno_macros",



More information about the libc-commits mailing list