[libc-commits] [libc] [llvm] [libc][math] Implement half precision tgamma function (PR #192590)

via libc-commits libc-commits at lists.llvm.org
Fri Apr 17 06:12:35 PDT 2026


https://github.com/AnonMiraj updated https://github.com/llvm/llvm-project/pull/192590

>From bd9d24caed88ae2034300980ccd92c10aa3dc4d2 Mon Sep 17 00:00:00 2001
From: Anonmiraj <ezzibrahimx at gmail.com>
Date: Fri, 17 Apr 2026 06:09:48 +0200
Subject: [PATCH 1/2] [libc][math] Implement half precision tgamma function

---
 libc/config/gpu/amdgpu/entrypoints.txt        |   2 +
 libc/config/gpu/nvptx/entrypoints.txt         |   2 +
 libc/config/linux/aarch64/entrypoints.txt     |   1 +
 libc/config/linux/riscv/entrypoints.txt       |   1 +
 libc/config/linux/x86_64/entrypoints.txt      |   1 +
 libc/include/math.yaml                        |   7 +
 libc/shared/math.h                            |   1 +
 libc/shared/math/tgammaf16.h                  |  27 +++
 libc/src/__support/math/CMakeLists.txt        |  16 ++
 libc/src/__support/math/tgammaf16.h           | 166 ++++++++++++++++++
 libc/src/math/CMakeLists.txt                  |   1 +
 libc/src/math/generic/CMakeLists.txt          |  12 ++
 libc/src/math/generic/tgammaf16.cpp           |  19 ++
 libc/src/math/tgammaf16.h                     |  21 +++
 libc/test/shared/CMakeLists.txt               |   1 +
 libc/test/shared/shared_math_test.cpp         |   2 +
 libc/test/src/math/CMakeLists.txt             |  12 ++
 libc/test/src/math/smoke/CMakeLists.txt       |  11 ++
 libc/test/src/math/smoke/tgammaf16_test.cpp   |  89 ++++++++++
 libc/test/src/math/tgammaf16_test.cpp         |  42 +++++
 libc/utils/MPFRWrapper/MPCommon.cpp           |   6 +
 libc/utils/MPFRWrapper/MPCommon.h             |   1 +
 libc/utils/MPFRWrapper/MPFRUtils.cpp          |   2 +
 libc/utils/MPFRWrapper/MPFRUtils.h            |   1 +
 .../llvm-project-overlay/libc/BUILD.bazel     |  21 +++
 25 files changed, 465 insertions(+)
 create mode 100644 libc/shared/math/tgammaf16.h
 create mode 100644 libc/src/__support/math/tgammaf16.h
 create mode 100644 libc/src/math/generic/tgammaf16.cpp
 create mode 100644 libc/src/math/tgammaf16.h
 create mode 100644 libc/test/src/math/smoke/tgammaf16_test.cpp
 create mode 100644 libc/test/src/math/tgammaf16_test.cpp

diff --git a/libc/config/gpu/amdgpu/entrypoints.txt b/libc/config/gpu/amdgpu/entrypoints.txt
index c76900a8371f7..d5275ead3abb1 100644
--- a/libc/config/gpu/amdgpu/entrypoints.txt
+++ b/libc/config/gpu/amdgpu/entrypoints.txt
@@ -509,6 +509,7 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.sqrtl
     libc.src.math.tan
     libc.src.math.tanf
+    libc.src.math.tgammaf16
     libc.src.math.tanhf
     libc.src.math.tanpif
     libc.src.math.tgamma
@@ -629,6 +630,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.sinpif16
     libc.src.math.sqrtf16
     libc.src.math.tanf16
+    libc.src.math.tgammaf16
     libc.src.math.tanhf16
     libc.src.math.tanpif16
     libc.src.math.totalorderf16
diff --git a/libc/config/gpu/nvptx/entrypoints.txt b/libc/config/gpu/nvptx/entrypoints.txt
index 6538732f785f5..944c16c248dfe 100644
--- a/libc/config/gpu/nvptx/entrypoints.txt
+++ b/libc/config/gpu/nvptx/entrypoints.txt
@@ -510,6 +510,7 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.sqrtl
     libc.src.math.tan
     libc.src.math.tanf
+    libc.src.math.tgammaf16
     libc.src.math.tanhf
     libc.src.math.tanpif
     libc.src.math.tgamma
@@ -631,6 +632,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.sinpif16
     libc.src.math.sqrtf16
     libc.src.math.tanf16
+    libc.src.math.tgammaf16
     libc.src.math.tanhf16
     libc.src.math.tanpif16
     libc.src.math.totalorderf16
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 6f7567cf3789f..443b15212e316 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -773,6 +773,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.sqrtf16
     libc.src.math.totalorderf16
     libc.src.math.totalordermagf16
+    libc.src.math.tgammaf16
     libc.src.math.truncf16
     libc.src.math.ufromfpf16
     libc.src.math.ufromfpxf16
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 1856d8edba7de..b67a0b48798e0 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -792,6 +792,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.tanf16
     libc.src.math.tanhf16
     libc.src.math.tanpif16
+    libc.src.math.tgammaf16
     libc.src.math.totalorderf16
     libc.src.math.totalordermagf16
     libc.src.math.truncf16
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index fe5991c695e25..e6376258a4053 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -846,6 +846,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.tanf16
     libc.src.math.tanhf16
     libc.src.math.tanpif16
+    libc.src.math.tgammaf16
     libc.src.math.totalorderf16
     libc.src.math.totalordermagf16
     libc.src.math.truncf16
diff --git a/libc/include/math.yaml b/libc/include/math.yaml
index 3984a665b234b..667419999f95a 100644
--- a/libc/include/math.yaml
+++ b/libc/include/math.yaml
@@ -2696,6 +2696,13 @@ functions:
     arguments:
       - type: _Float16
     guard: LIBC_TYPES_HAS_FLOAT16
+  - name: tgammaf16
+    standards:
+      - stdc
+    return_type: _Float16
+    arguments:
+      - type: _Float16
+    guard: LIBC_TYPES_HAS_FLOAT16
   - name: totalorder
     standards:
       - stdc
diff --git a/libc/shared/math.h b/libc/shared/math.h
index 83cd6196b146b..02560c3f3cf47 100644
--- a/libc/shared/math.h
+++ b/libc/shared/math.h
@@ -269,5 +269,6 @@
 #include "math/tanhf16.h"
 #include "math/tanpif.h"
 #include "math/tanpif16.h"
+#include "math/tgammaf16.h"
 
 #endif // LLVM_LIBC_SHARED_MATH_H
diff --git a/libc/shared/math/tgammaf16.h b/libc/shared/math/tgammaf16.h
new file mode 100644
index 0000000000000..1ed3ed739ea0a
--- /dev/null
+++ b/libc/shared/math/tgammaf16.h
@@ -0,0 +1,27 @@
+//===-- Shared tgammaf16 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_TGAMMAF16_H
+#define LLVM_LIBC_SHARED_MATH_TGAMMAF16_H
+
+#ifdef LIBC_TYPES_HAS_FLOAT16
+
+#include "shared/libc_common.h"
+#include "src/__support/math/tgammaf16.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace shared {
+
+using math::tgammaf16;
+
+} // namespace shared
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+#endif // LLVM_LIBC_SHARED_MATH_TGAMMAF16_H
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index d1c42afbaafe1..46f1feaab3ea5 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -3400,3 +3400,19 @@ add_header_library(
     libc.src.__support.FPUtil.multiply_add
     libc.src.__support.macros.optimization
 )
+
+add_header_library(
+  tgammaf16
+  HDRS
+    tgammaf16.h
+  DEPENDS
+    libc.src.__support.CPP.bit
+    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.nearest_integer_operations
+    libc.src.__support.macros.config
+    libc.src.__support.macros.optimization
+)
diff --git a/libc/src/__support/math/tgammaf16.h b/libc/src/__support/math/tgammaf16.h
new file mode 100644
index 0000000000000..9df373021ea29
--- /dev/null
+++ b/libc/src/__support/math/tgammaf16.h
@@ -0,0 +1,166 @@
+//===-- Implementation header for tgammaf16 ---------------------*- 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_TGAMMAF16_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_TGAMMAF16_H
+
+#include "include/llvm-libc-macros/float16-macros.h"
+
+#ifdef LIBC_TYPES_HAS_FLOAT16
+
+#include "src/__support/CPP/bit.h"
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/NearestIntegerOperations.h"
+#include "src/__support/FPUtil/cast.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/FPUtil/nearest_integer.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace math {
+
+LIBC_INLINE constexpr bool is_integer(float16 x) {
+  using FPBits = fputil::FPBits<float16>;
+  FPBits xbits(x);
+  uint16_t x_u = xbits.uintval();
+  unsigned x_e = static_cast<unsigned>(xbits.get_biased_exponent());
+  unsigned lsb = static_cast<unsigned>(
+      cpp::countr_zero(static_cast<uint16_t>(x_u | FPBits::EXP_MASK)));
+  constexpr unsigned UNIT_EXPONENT =
+      static_cast<unsigned>(FPBits::EXP_BIAS + FPBits::FRACTION_LEN);
+  return x_e + lsb >= UNIT_EXPONENT;
+}
+
+LIBC_INLINE float16 tgammaf16(float16 x) {
+  using FPBits = typename fputil::FPBits<float16>;
+  FPBits xbits(x);
+  uint16_t x_abs = xbits.abs().uintval();
+
+  if (LIBC_UNLIKELY(x_abs >= 0x7c00U)) {
+    if (x_abs == 0x7c00U) {
+      // tgamma(-Inf) = NaN, tgamma(+Inf) = +Inf
+      if (xbits.is_neg()) {
+        fputil::raise_except_if_required(FE_INVALID);
+        fputil::set_errno_if_required(EDOM);
+        return FPBits::quiet_nan().get_val();
+      }
+      return x;
+    }
+    if (xbits.is_signaling_nan()) {
+      fputil::raise_except_if_required(FE_INVALID);
+      return FPBits::quiet_nan().get_val();
+    }
+    return x;
+  }
+
+  // -+0 pole error
+  if (LIBC_UNLIKELY(x_abs == 0)) {
+    fputil::raise_except_if_required(FE_DIVBYZERO);
+    fputil::set_errno_if_required(ERANGE);
+    return FPBits::inf(xbits.sign()).get_val();
+  }
+
+  double xd = fputil::cast<double>(x);
+
+  // |x| <= 2^-16
+  if (LIBC_UNLIKELY(x_abs <= 0x0100U)) {
+    double d = (0x1.fa658c23b1578p-1 - 0x1.d0a118f324b63p-1 * xd) * xd -
+               0x1.2788cfc6fb619p-1;
+    double f = 1.0 / xd + d;
+    float16 result = fputil::cast<float16>(f);
+    if (LIBC_UNLIKELY(FPBits(result).is_inf())) {
+      fputil::raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
+      fputil::set_errno_if_required(ERANGE);
+    } else {
+      fputil::raise_except_if_required(FE_INEXACT);
+    }
+    return result;
+  }
+
+  // |x| >= 9.2265625 overflows float16
+  if (LIBC_UNLIKELY(!xbits.is_neg() && x_abs >= 0x489DU)) {
+    fputil::raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
+    fputil::set_errno_if_required(ERANGE);
+    return fputil::cast<float16>(fputil::FPBits<float>::max_normal().get_val());
+  }
+
+  // x is a non-zero integer
+  if (LIBC_UNLIKELY(is_integer(x))) {
+    int32_t k = static_cast<int32_t>(fputil::floor(xd));
+    if (xbits.is_neg()) {
+      fputil::raise_except_if_required(FE_INVALID);
+      fputil::set_errno_if_required(EDOM);
+      return FPBits::quiet_nan().get_val();
+    }
+    // gamma(n) = (n-1)! for n = 1..9 (n >= 10 overflows float16)
+    static constexpr float16 FACTORIAL[9] = {1.0,   1.0,   2.0,    6.0,    24.0,
+                                             120.0, 720.0, 5040.0, 40320.0};
+    return FACTORIAL[k - 1];
+  }
+
+  // |x| < -16
+  if (LIBC_UNLIKELY(x_abs > 0x4C00U)) {
+    fputil::set_errno_if_required(ERANGE);
+    float res =
+        (static_cast<int32_t>(fputil::floor(x)) & 1) ? -0x1p-127f : 0x1p-127f;
+
+    return fputil::cast<float16>(res);
+  }
+
+  double m = xd - 0x1.7p+1;
+  double i = fputil::nearest_integer(m);
+  double step = fputil::FPBits<double>(i).is_neg() ? -1.0 : 1.0;
+  int32_t jm = static_cast<int32_t>(i < 0.0 ? -i : i);
+
+  double d = m - i;
+
+  // Polynomial approximating tgamma(d + 2.875) on [-0.5, 0.5] generated by
+  // Sollya with: > P = fpminimax(tgamma(x + 2.875),
+  //                              [|0,1,2,3,4,5,6,7|], [|D...|], [-0.5, 0.5]);
+
+  static constexpr double COEFFS[8] = {
+      0x1.c9a76b7de6f60p+0, 0x1.8f2754874fe83p+0, 0x1.0d11cba0c229fp+0,
+      0x1.e1f47c012064dp-2, 0x1.828b9f2afb74fp-3, 0x1.e1cc49d830795p-5,
+      0x1.2c9af3e686836p-6, 0x1.1bf60c7e311f6p-8};
+  double d2 = d * d, d4 = d2 * d2;
+  double p01 = fputil::multiply_add(d, COEFFS[1], COEFFS[0]);
+  double p23 = fputil::multiply_add(d, COEFFS[3], COEFFS[2]);
+  double p45 = fputil::multiply_add(d, COEFFS[5], COEFFS[4]);
+  double p67 = fputil::multiply_add(d, COEFFS[7], COEFFS[6]);
+  double p03 = fputil::multiply_add(d2, p23, p01);
+  double p47 = fputil::multiply_add(d2, p67, p45);
+  double f = fputil::multiply_add(d4, p47, p03);
+
+  // Reduce to the base interval by multiplying the appropriate
+  // falling/rising factorial then invert for the negative-argument case
+  double z = xd;
+  double w = 1.0;
+  if (jm) {
+    z -= 0.5 + step * 0.5;
+    w = z;
+    for (int32_t j = jm - 1; j; j--) {
+      z -= step;
+      w *= z;
+    }
+  }
+  if (i <= -0.5)
+    w = 1.0 / w;
+
+  return fputil::cast<float16>(f * w);
+}
+
+} // namespace math
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_TGAMMAF16_H
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index b53817e2a1729..bc726991af15e 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -595,6 +595,7 @@ add_math_entrypoint_object(tanpif16)
 
 add_math_entrypoint_object(tgamma)
 add_math_entrypoint_object(tgammaf)
+add_math_entrypoint_object(tgammaf16)
 add_math_entrypoint_object(lgamma)
 add_math_entrypoint_object(lgamma_r)
 
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 740b78418492b..9a78d9760a5d0 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -5278,3 +5278,15 @@ add_entrypoint_object(
   DEPENDS
     libc.src.__support.math.bf16subf128
 )
+
+add_entrypoint_object(
+  tgammaf16
+  SRCS
+    tgammaf16.cpp
+  HDRS
+    ../tgammaf16.h
+  DEPENDS
+    libc.src.__support.common
+    libc.src.__support.math.tgammaf16
+    libc.src.errno.errno
+)
diff --git a/libc/src/math/generic/tgammaf16.cpp b/libc/src/math/generic/tgammaf16.cpp
new file mode 100644
index 0000000000000..01d71bc700a3c
--- /dev/null
+++ b/libc/src/math/generic/tgammaf16.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of tgammaf16 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/tgammaf16.h"
+#include "src/__support/common.h"
+#include "src/__support/math/tgammaf16.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(float16, tgammaf16, (float16 x)) {
+  return math::tgammaf16(x);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/tgammaf16.h b/libc/src/math/tgammaf16.h
new file mode 100644
index 0000000000000..583f65d8bedfe
--- /dev/null
+++ b/libc/src/math/tgammaf16.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for tgammaf16 ---------------------*- 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_TGAMMAF16_H
+#define LLVM_LIBC_SRC_MATH_TGAMMAF16_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+float16 tgammaf16(float16 x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_TGAMMAF16_H
diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt
index 3289321f25dd4..4fa95d92764b9 100644
--- a/libc/test/shared/CMakeLists.txt
+++ b/libc/test/shared/CMakeLists.txt
@@ -267,6 +267,7 @@ add_fp_unittest(
     libc.src.__support.math.tanhf16
     libc.src.__support.math.tanpif
     libc.src.__support.math.tanpif16
+    libc.src.__support.math.tgammaf16
 )
 
 add_fp_unittest(
diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp
index 5d83ce22af4ab..3efe2ee970f1c 100644
--- a/libc/test/shared/shared_math_test.cpp
+++ b/libc/test/shared/shared_math_test.cpp
@@ -67,6 +67,8 @@ TEST(LlvmLibcSharedMathTest, AllFloat16) {
   EXPECT_FP_EQ(0.0f16, LIBC_NAMESPACE::shared::tanhf16(0.0f16));
   EXPECT_FP_EQ(0.0f16, LIBC_NAMESPACE::shared::tanpif16(0.0f16));
 
+  EXPECT_FP_EQ(1.0f16, LIBC_NAMESPACE::shared::tgammaf16(1.0f16));
+
   float16 canonicalizef16_cx = 0.0f16;
   float16 canonicalizef16_x = 0.0f16;
   EXPECT_EQ(0, LIBC_NAMESPACE::shared::canonicalizef16(&canonicalizef16_cx,
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 4213c11eca515..9b643878a76e8 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -3633,3 +3633,15 @@ if(NOT LLVM_LIBC_FULL_BUILD)
   add_subdirectory(exhaustive)
   add_subdirectory(performance_testing)
 endif()
+
+add_fp_unittest(
+  tgammaf16_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    tgammaf16_test.cpp
+  DEPENDS
+    libc.src.__support.FPUtil.fp_bits
+    libc.src.math.tgammaf16
+)
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 28b85b1a25bbd..e77ff61991d92 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -6686,3 +6686,14 @@ add_fp_unittest(
     libc.src.__support.FPUtil.bfloat16
     libc.src.__support.macros.properties.os
 )
+
+add_fp_unittest(
+  tgammaf16_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    tgammaf16_test.cpp
+  DEPENDS
+    libc.src.__support.FPUtil.fp_bits
+    libc.src.math.tgammaf16
+)
diff --git a/libc/test/src/math/smoke/tgammaf16_test.cpp b/libc/test/src/math/smoke/tgammaf16_test.cpp
new file mode 100644
index 0000000000000..50cf8554e7616
--- /dev/null
+++ b/libc/test/src/math/smoke/tgammaf16_test.cpp
@@ -0,0 +1,89 @@
+//===-- Unittests for tgammaf16 -------------------------------------------===//
+//
+// 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 "src/math/tgammaf16.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using LlvmLibcTgammaf16Test = LIBC_NAMESPACE::testing::FPTest<float16>;
+
+TEST_F(LlvmLibcTgammaf16Test, SpecialNumbers) {
+  // sNaN -> qNaN + FE_INVALID
+  EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tgammaf16(sNaN),
+                              FE_INVALID);
+  EXPECT_MATH_ERRNO(0);
+
+  // qNaN -> qNaN
+  EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::tgammaf16(aNaN));
+
+  // +Inf -> +Inf
+  EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::tgammaf16(inf));
+
+  // -Inf -> NaN + FE_INVALID (domain error)
+  EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tgammaf16(neg_inf),
+                              FE_INVALID);
+  EXPECT_MATH_ERRNO(EDOM);
+
+  // +0 -> +Inf + FE_DIVBYZERO (pole error)
+  EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::tgammaf16(zero),
+                              FE_DIVBYZERO);
+  EXPECT_MATH_ERRNO(ERANGE);
+
+  // -0 -> -Inf + FE_DIVBYZERO (pole error)
+  EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, LIBC_NAMESPACE::tgammaf16(neg_zero),
+                              FE_DIVBYZERO);
+  EXPECT_MATH_ERRNO(ERANGE);
+}
+
+TEST_F(LlvmLibcTgammaf16Test, PositiveIntegers) {
+  EXPECT_FP_EQ_ALL_ROUNDING(1.0f16, LIBC_NAMESPACE::tgammaf16(1.0f16));
+  EXPECT_FP_EQ_ALL_ROUNDING(1.0f16, LIBC_NAMESPACE::tgammaf16(2.0f16));
+  EXPECT_FP_EQ_ALL_ROUNDING(2.0f16, LIBC_NAMESPACE::tgammaf16(3.0f16));
+  EXPECT_FP_EQ_ALL_ROUNDING(6.0f16, LIBC_NAMESPACE::tgammaf16(4.0f16));
+  EXPECT_FP_EQ_ALL_ROUNDING(24.0f16, LIBC_NAMESPACE::tgammaf16(5.0f16));
+}
+
+TEST_F(LlvmLibcTgammaf16Test, NegativeIntegers) {
+  // tgamma of negative integer -> NaN + FE_INVALID (domain error)
+  EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tgammaf16(-1.0f16),
+                              FE_INVALID);
+  EXPECT_MATH_ERRNO(EDOM);
+
+  EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tgammaf16(-2.0f16),
+                              FE_INVALID);
+  EXPECT_MATH_ERRNO(EDOM);
+}
+
+TEST_F(LlvmLibcTgammaf16Test, Overflow) {
+  // x >= 9.2265625 overflows float16
+  EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::tgammaf16(9.25f16),
+                              FE_OVERFLOW | FE_INEXACT);
+  EXPECT_MATH_ERRNO(ERANGE);
+}
+
+#ifdef LIBC_TEST_FTZ_DAZ
+
+using namespace LIBC_NAMESPACE::testing;
+
+TEST_F(LlvmLibcTgammaf16Test, FTZMode) {
+  ModifyMXCSR mxcsr(FTZ);
+  EXPECT_FP_EQ(inf, LIBC_NAMESPACE::tgammaf16(min_denormal));
+}
+
+TEST_F(LlvmLibcTgammaf16Test, DAZMode) {
+  ModifyMXCSR mxcsr(DAZ);
+  EXPECT_FP_EQ(inf, LIBC_NAMESPACE::tgammaf16(min_denormal));
+}
+
+TEST_F(LlvmLibcTgammaf16Test, FTZDAZMode) {
+  ModifyMXCSR mxcsr(FTZ | DAZ);
+  EXPECT_FP_EQ(inf, LIBC_NAMESPACE::tgammaf16(min_denormal));
+}
+
+#endif
diff --git a/libc/test/src/math/tgammaf16_test.cpp b/libc/test/src/math/tgammaf16_test.cpp
new file mode 100644
index 0000000000000..9fd18a256c252
--- /dev/null
+++ b/libc/test/src/math/tgammaf16_test.cpp
@@ -0,0 +1,42 @@
+//===-- Unittests for tgammaf16 -------------------------------------------===//
+//
+// 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/tgammaf16.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+using LlvmLibcTgammaf16Test = LIBC_NAMESPACE::testing::FPTest<float16>;
+
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
+
+// Range: ]0, Inf[
+static constexpr uint16_t POS_START = 0x0001U;
+static constexpr uint16_t POS_STOP = 0x7bffU;
+
+// Range: ]-Inf, 0[
+static constexpr uint16_t NEG_START = 0x8001U;
+static constexpr uint16_t NEG_STOP = 0xfbffU;
+
+TEST_F(LlvmLibcTgammaf16Test, PositiveRange) {
+  for (uint16_t v = POS_START; v <= POS_STOP; ++v) {
+    float16 x = FPBits(v).get_val();
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Tgamma, x,
+                                   LIBC_NAMESPACE::tgammaf16(x), 0.5);
+  }
+}
+
+TEST_F(LlvmLibcTgammaf16Test, NegativeRange) {
+  for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) {
+    float16 x = FPBits(v).get_val();
+    if (FPBits(v).is_nan())
+      continue;
+    EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Tgamma, x,
+                                   LIBC_NAMESPACE::tgammaf16(x), 0.5);
+  }
+}
diff --git a/libc/utils/MPFRWrapper/MPCommon.cpp b/libc/utils/MPFRWrapper/MPCommon.cpp
index bdd8286148641..b2ade7ab34878 100644
--- a/libc/utils/MPFRWrapper/MPCommon.cpp
+++ b/libc/utils/MPFRWrapper/MPCommon.cpp
@@ -575,6 +575,12 @@ MPFRNumber MPFRNumber::tanpi() const {
 #endif
 }
 
+MPFRNumber MPFRNumber::tgamma() const {
+  MPFRNumber result(*this);
+  mpfr_gamma(result.value, value, mpfr_rounding);
+  return result;
+}
+
 MPFRNumber MPFRNumber::trunc() const {
   MPFRNumber result(*this);
   mpfr_trunc(result.value, value);
diff --git a/libc/utils/MPFRWrapper/MPCommon.h b/libc/utils/MPFRWrapper/MPCommon.h
index 935a2614968a2..96149487170a5 100644
--- a/libc/utils/MPFRWrapper/MPCommon.h
+++ b/libc/utils/MPFRWrapper/MPCommon.h
@@ -237,6 +237,7 @@ class MPFRNumber {
   MPFRNumber tan() const;
   MPFRNumber tanh() const;
   MPFRNumber tanpi() const;
+  MPFRNumber tgamma() const;
   MPFRNumber trunc() const;
   MPFRNumber fma(const MPFRNumber &b, const MPFRNumber &c);
   MPFRNumber mul(const MPFRNumber &b);
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index 356764302bda8..2fadaf4bc8388 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -113,6 +113,8 @@ unary_operation(Operation op, InputType input, unsigned int precision,
     return mpfrInput.tanh();
   case Operation::Tanpi:
     return mpfrInput.tanpi();
+  case Operation::Tgamma:
+    return mpfrInput.tgamma();
   case Operation::Trunc:
     return mpfrInput.trunc();
   default:
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h
index 6c1b15598b0f2..d265f4ae2cad4 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.h
+++ b/libc/utils/MPFRWrapper/MPFRUtils.h
@@ -67,6 +67,7 @@ enum class Operation : int {
   Tan,
   Tanh,
   Tanpi,
+  Tgamma,
   Trunc,
   EndUnaryOperationsSingleOutput,
 
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index eb4a97b457ca8..1c20e4ffa8865 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -6377,6 +6377,22 @@ libc_support_library(
     ],
 )
 
+libc_support_library(
+    name = "__support_math_tgammaf16",
+    hdrs = ["src/__support/math/tgammaf16.h"],
+    deps = [
+        ":__support_cpp_bit",
+        ":__support_fputil_cast",
+        ":__support_fputil_fenv_impl",
+        ":__support_fputil_fp_bits",
+        ":__support_fputil_multiply_add",
+        ":__support_fputil_nearest_integer",
+        ":__support_fputil_nearest_integer_operations",
+        ":__support_macros_config",
+        ":__support_macros_optimization",
+    ],
+)
+
 ############################### complex targets ################################
 
 libc_function(
@@ -8854,6 +8870,11 @@ libc_math_function(
     additional_deps = [":__support_math_tanpif16"],
 )
 
+libc_math_function(
+    name = "tgammaf16",
+    additional_deps = [":__support_math_tgammaf16"],
+)
+
 libc_math_function(name = "totalorder")
 
 libc_math_function(name = "totalorderf")

>From 7eace73c8c51c617f9414e2101a3390ddbed4d21 Mon Sep 17 00:00:00 2001
From: Anonmiraj <ezzibrahimx at gmail.com>
Date: Fri, 17 Apr 2026 15:12:20 +0200
Subject: [PATCH 2/2] fix nits

---
 libc/config/baremetal/aarch64/entrypoints.txt |  1 +
 libc/config/baremetal/arm/entrypoints.txt     |  1 +
 libc/config/baremetal/riscv/entrypoints.txt   |  1 +
 libc/src/__support/math/CMakeLists.txt        |  2 ++
 libc/src/__support/math/tgammaf16.h           |  1 +
 libc/src/math/generic/CMakeLists.txt          |  1 +
 libc/src/math/generic/tgammaf16.cpp           |  1 +
 libc/test/src/math/CMakeLists.txt             | 18 +++++++++---------
 libc/test/src/math/smoke/CMakeLists.txt       |  2 +-
 9 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt
index 452abd985b3a5..eaa94c81147ac 100644
--- a/libc/config/baremetal/aarch64/entrypoints.txt
+++ b/libc/config/baremetal/aarch64/entrypoints.txt
@@ -691,6 +691,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.tanpif16
     libc.src.math.totalorderf16
     libc.src.math.totalordermagf16
+    libc.src.math.tgammaf16
     libc.src.math.truncf16
     libc.src.math.ufromfpf16
     libc.src.math.ufromfpxf16
diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index 9c0e71b2beec0..7acbf343aff2b 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -700,6 +700,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.tanpif16
     libc.src.math.totalorderf16
     libc.src.math.totalordermagf16
+    libc.src.math.tgammaf16
     libc.src.math.truncf16
     libc.src.math.ufromfpf16
     libc.src.math.ufromfpxf16
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index 5c88bc4ae1fb7..2d50e43665662 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -697,6 +697,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.tanpif16
     libc.src.math.totalorderf16
     libc.src.math.totalordermagf16
+    libc.src.math.tgammaf16
     libc.src.math.truncf16
     libc.src.math.ufromfpf16
     libc.src.math.ufromfpxf16
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index 46f1feaab3ea5..a78075de8d178 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -3406,6 +3406,7 @@ add_header_library(
   HDRS
     tgammaf16.h
   DEPENDS
+    libc.include.llvm-libc-macros.float16_macros
     libc.src.__support.CPP.bit
     libc.src.__support.FPUtil.cast
     libc.src.__support.FPUtil.fenv_impl
@@ -3415,4 +3416,5 @@ add_header_library(
     libc.src.__support.FPUtil.nearest_integer_operations
     libc.src.__support.macros.config
     libc.src.__support.macros.optimization
+    libc.src.__support.macros.properties.types
 )
diff --git a/libc/src/__support/math/tgammaf16.h b/libc/src/__support/math/tgammaf16.h
index 9df373021ea29..f0d956c9f0ae2 100644
--- a/libc/src/__support/math/tgammaf16.h
+++ b/libc/src/__support/math/tgammaf16.h
@@ -22,6 +22,7 @@
 #include "src/__support/FPUtil/nearest_integer.h"
 #include "src/__support/macros/config.h"
 #include "src/__support/macros/optimization.h"
+#include "src/__support/macros/properties/types.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 9a78d9760a5d0..51c28bf32057b 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -5287,6 +5287,7 @@ add_entrypoint_object(
     ../tgammaf16.h
   DEPENDS
     libc.src.__support.common
+    libc.src.__support.macros.config
     libc.src.__support.math.tgammaf16
     libc.src.errno.errno
 )
diff --git a/libc/src/math/generic/tgammaf16.cpp b/libc/src/math/generic/tgammaf16.cpp
index 01d71bc700a3c..1b15d41f20e36 100644
--- a/libc/src/math/generic/tgammaf16.cpp
+++ b/libc/src/math/generic/tgammaf16.cpp
@@ -8,6 +8,7 @@
 
 #include "src/math/tgammaf16.h"
 #include "src/__support/common.h"
+#include "src/__support/macros/config.h"
 #include "src/__support/math/tgammaf16.h"
 
 namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 9b643878a76e8..130cd07bc3024 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -3626,14 +3626,6 @@ add_fp_unittest(
     libc.src.__support.FPUtil.bfloat16
 )
 
-add_subdirectory(generic)
-add_subdirectory(smoke)
-
-if(NOT LLVM_LIBC_FULL_BUILD)
-  add_subdirectory(exhaustive)
-  add_subdirectory(performance_testing)
-endif()
-
 add_fp_unittest(
   tgammaf16_test
   NEED_MPFR
@@ -3642,6 +3634,14 @@ add_fp_unittest(
   SRCS
     tgammaf16_test.cpp
   DEPENDS
-    libc.src.__support.FPUtil.fp_bits
     libc.src.math.tgammaf16
 )
+
+add_subdirectory(generic)
+add_subdirectory(smoke)
+
+if(NOT LLVM_LIBC_FULL_BUILD)
+  add_subdirectory(exhaustive)
+  add_subdirectory(performance_testing)
+endif()
+
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index e77ff61991d92..20ac8c09343cd 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -6694,6 +6694,6 @@ add_fp_unittest(
   SRCS
     tgammaf16_test.cpp
   DEPENDS
-    libc.src.__support.FPUtil.fp_bits
+    libc.hdr.errno_macros
     libc.src.math.tgammaf16
 )



More information about the libc-commits mailing list