Skip to content

[libc][math] Refactor sinf16 implementation to header-only in src/__support/math folder.#178062

Merged
nico merged 5 commits intollvm:mainfrom
nico:libm-sinf16
Jan 27, 2026
Merged

[libc][math] Refactor sinf16 implementation to header-only in src/__support/math folder.#178062
nico merged 5 commits intollvm:mainfrom
nico:libm-sinf16

Conversation

@nico
Copy link
Copy Markdown
Contributor

@nico nico commented Jan 26, 2026

@nico nico requested a review from bassiounix January 26, 2026 21:56
@llvmbot llvmbot added libc bazel "Peripheral" support tier build system: utils/bazel labels Jan 26, 2026
@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Jan 26, 2026

@llvm/pr-subscribers-libc

Author: Nico Weber (nico)

Changes

Part of #147386

in preparation for:
https://discourse.llvm.org/t/rfc-make-clang-builtin-math-functions-constexpr-with-llvm-libc-to-support-c-23-constexpr-math-functions/86450


Full diff: https://github.com/llvm/llvm-project/pull/178062.diff

9 Files Affected:

  • (modified) libc/shared/math.h (+1)
  • (added) libc/shared/math/sinf16.h (+23)
  • (modified) libc/src/__support/math/CMakeLists.txt (+17)
  • (added) libc/src/__support/math/sinf16.h (+130)
  • (modified) libc/src/math/generic/CMakeLists.txt (+1-12)
  • (modified) libc/src/math/generic/sinf16.cpp (+2-102)
  • (modified) libc/test/shared/CMakeLists.txt (+1)
  • (modified) libc/test/shared/shared_math_test.cpp (+1)
  • (modified) utils/bazel/llvm-project-overlay/libc/BUILD.bazel (+11-3)
diff --git a/libc/shared/math.h b/libc/shared/math.h
index f7fa175234296..ba37bd52ee8ab 100644
--- a/libc/shared/math.h
+++ b/libc/shared/math.h
@@ -87,6 +87,7 @@
 #include "math/rsqrtf16.h"
 #include "math/sin.h"
 #include "math/sinf.h"
+#include "math/sinf16.h"
 #include "math/tan.h"
 #include "math/tanf.h"
 
diff --git a/libc/shared/math/sinf16.h b/libc/shared/math/sinf16.h
new file mode 100644
index 0000000000000..4c39d8225f672
--- /dev/null
+++ b/libc/shared/math/sinf16.h
@@ -0,0 +1,23 @@
+//===-- Shared sinf16 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_SINF16_H
+#define LLVM_LIBC_SHARED_MATH_SINF16_H
+
+#include "shared/libc_common.h"
+#include "src/__support/math/sinf16.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace shared {
+
+using math::sinf16;
+
+} // namespace shared
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SHARED_MATH_SINF16_H
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index d37dbe6be6864..6863164a55988 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -1276,6 +1276,23 @@ add_header_library(
     libc.src.__support.macros.optimization
 )
 
+add_header_library(
+  sinf16
+  HDRS
+    sinf16.h
+  DEPENDS
+    .sincosf16_utils
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
+    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.macros.optimization
+    libc.src.__support.macros.properties.types
+)
+
 add_header_library(
   dfmal
   HDRS
diff --git a/libc/src/__support/math/sinf16.h b/libc/src/__support/math/sinf16.h
new file mode 100644
index 0000000000000..2fcc4e28e1cc9
--- /dev/null
+++ b/libc/src/__support/math/sinf16.h
@@ -0,0 +1,130 @@
+//===-- Half-precision sin(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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_SINF16_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_SINF16_H
+
+#include "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
+#include "sincosf16_utils.h"
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.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/macros/optimization.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace math {
+
+namespace sinf16_internal {
+
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+LIBC_INLINE_VAR constexpr size_t N_EXCEPTS = 4;
+
+LIBC_INLINE_VAR constexpr fputil::ExceptValues<float16, N_EXCEPTS>
+    SINF16_EXCEPTS{{
+        // (input, RZ output, RU offset, RD offset, RN offset)
+        {0x2b45, 0x2b43, 1, 0, 1},
+        {0x585c, 0x3ba3, 1, 0, 1},
+        {0x5cb0, 0xbbff, 0, 1, 0},
+        {0x51f5, 0xb80f, 0, 1, 0},
+    }};
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+} // namespace sinf16_internal
+
+LIBC_INLINE static float16 sinf16(float16 x) {
+  using namespace sinf16_internal;
+  using namespace sincosf16_internal;
+  using FPBits = fputil::FPBits<float16>;
+  FPBits xbits(x);
+
+  uint16_t x_u = xbits.uintval();
+  uint16_t x_abs = x_u & 0x7fff;
+  float xf = x;
+
+  // Range reduction:
+  // For |x| > pi/32, we perform range reduction as follows:
+  // Find k and y such that:
+  //   x = (k + y) * pi/32
+  //   k is an integer, |y| < 0.5
+  //
+  // This is done by performing:
+  //   k = round(x * 32/pi)
+  //   y = x * 32/pi - k
+  //
+  // Once k and y are computed, we then deduce the answer by the sine of sum
+  // formula:
+  //   sin(x) = sin((k + y) * pi/32)
+  //   	      = sin(k * pi/32) * cos(y * pi/32) +
+  //   	        sin(y * pi/32) * cos(k * pi/32)
+
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+  // Handle exceptional values
+  bool x_sign = x_u >> 15;
+
+  if (auto r = SINF16_EXCEPTS.lookup_odd(x_abs, x_sign);
+      LIBC_UNLIKELY(r.has_value()))
+    return r.value();
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+  int rounding = fputil::quick_get_round();
+
+  // Exhaustive tests show that for |x| <= 0x1.f4p-11, 1ULP rounding errors
+  // occur. To fix this, the following apply:
+  if (LIBC_UNLIKELY(x_abs <= 0x13d0)) {
+    // sin(+/-0) = +/-0
+    if (LIBC_UNLIKELY(x_abs == 0U))
+      return x;
+
+    // When x > 0, and rounding upward, sin(x) == x.
+    // When x < 0, and rounding downward, sin(x) == x.
+    if ((rounding == FE_UPWARD && xbits.is_pos()) ||
+        (rounding == FE_DOWNWARD && xbits.is_neg()))
+      return x;
+
+    // When x < 0, and rounding upward, sin(x) == (x - 1ULP)
+    if (rounding == FE_UPWARD && xbits.is_neg()) {
+      x_u--;
+      return FPBits(x_u).get_val();
+    }
+  }
+
+  if (xbits.is_inf_or_nan()) {
+    if (xbits.is_signaling_nan()) {
+      fputil::raise_except_if_required(FE_INVALID);
+      return FPBits::quiet_nan().get_val();
+    }
+
+    if (xbits.is_inf()) {
+      fputil::set_errno_if_required(EDOM);
+      fputil::raise_except_if_required(FE_INVALID);
+    }
+
+    return x + FPBits::quiet_nan().get_val();
+  }
+
+  float sin_k, cos_k, sin_y, cosm1_y;
+  sincosf16_eval(xf, sin_k, cos_k, sin_y, cosm1_y);
+
+  if (LIBC_UNLIKELY(sin_y == 0 && sin_k == 0))
+    return FPBits::zero(xbits.sign()).get_val();
+
+  // Since, cosm1_y = cos_y - 1, therefore:
+  //   sin(x) = cos_k * sin_y + sin_k + (cosm1_y * sin_k)
+  return fputil::cast<float16>(fputil::multiply_add(
+      sin_y, cos_k, fputil::multiply_add(cosm1_y, sin_k, sin_k)));
+}
+
+} // namespace math
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_SINF16_H
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 11b87ca93a97c..6a50ec6061eae 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -383,18 +383,7 @@ add_entrypoint_object(
   HDRS
     ../sinf16.h
   DEPENDS
-    libc.hdr.errno_macros
-    libc.hdr.fenv_macros
-    libc.src.__support.FPUtil.cast
-    libc.src.__support.FPUtil.fenv_impl
-    libc.src.__support.FPUtil.fp_bits
-    libc.src.__support.FPUtil.except_value_utils
-    libc.src.__support.FPUtil.multiply_add
-    libc.src.__support.macros.optimization
-    libc.src.__support.macros.properties.types
-    libc.src.__support.math.sincosf16_utils
-  COMPILE_OPTIONS
-    ${libc_opt_high_flag}
+    libc.src.__support.math.sinf16
 )
 
 add_entrypoint_object(
diff --git a/libc/src/math/generic/sinf16.cpp b/libc/src/math/generic/sinf16.cpp
index 2b579202ea111..611897026cd8f 100644
--- a/libc/src/math/generic/sinf16.cpp
+++ b/libc/src/math/generic/sinf16.cpp
@@ -7,110 +7,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/math/sinf16.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/cast.h"
-#include "src/__support/FPUtil/except_value_utils.h"
-#include "src/__support/FPUtil/multiply_add.h"
-#include "src/__support/macros/optimization.h"
-#include "src/__support/math/sincosf16_utils.h"
+#include "src/__support/math/sinf16.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
-#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-constexpr size_t N_EXCEPTS = 4;
-
-constexpr fputil::ExceptValues<float16, N_EXCEPTS> SINF16_EXCEPTS{{
-    // (input, RZ output, RU offset, RD offset, RN offset)
-    {0x2b45, 0x2b43, 1, 0, 1},
-    {0x585c, 0x3ba3, 1, 0, 1},
-    {0x5cb0, 0xbbff, 0, 1, 0},
-    {0x51f5, 0xb80f, 0, 1, 0},
-}};
-#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-
-LLVM_LIBC_FUNCTION(float16, sinf16, (float16 x)) {
-  using namespace sincosf16_internal;
-  using FPBits = fputil::FPBits<float16>;
-  FPBits xbits(x);
-
-  uint16_t x_u = xbits.uintval();
-  uint16_t x_abs = x_u & 0x7fff;
-  float xf = x;
-
-  // Range reduction:
-  // For |x| > pi/32, we perform range reduction as follows:
-  // Find k and y such that:
-  //   x = (k + y) * pi/32
-  //   k is an integer, |y| < 0.5
-  //
-  // This is done by performing:
-  //   k = round(x * 32/pi)
-  //   y = x * 32/pi - k
-  //
-  // Once k and y are computed, we then deduce the answer by the sine of sum
-  // formula:
-  //   sin(x) = sin((k + y) * pi/32)
-  //   	      = sin(k * pi/32) * cos(y * pi/32) +
-  //   	        sin(y * pi/32) * cos(k * pi/32)
-
-#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-  // Handle exceptional values
-  bool x_sign = x_u >> 15;
-
-  if (auto r = SINF16_EXCEPTS.lookup_odd(x_abs, x_sign);
-      LIBC_UNLIKELY(r.has_value()))
-    return r.value();
-#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-
-  int rounding = fputil::quick_get_round();
-
-  // Exhaustive tests show that for |x| <= 0x1.f4p-11, 1ULP rounding errors
-  // occur. To fix this, the following apply:
-  if (LIBC_UNLIKELY(x_abs <= 0x13d0)) {
-    // sin(+/-0) = +/-0
-    if (LIBC_UNLIKELY(x_abs == 0U))
-      return x;
-
-    // When x > 0, and rounding upward, sin(x) == x.
-    // When x < 0, and rounding downward, sin(x) == x.
-    if ((rounding == FE_UPWARD && xbits.is_pos()) ||
-        (rounding == FE_DOWNWARD && xbits.is_neg()))
-      return x;
-
-    // When x < 0, and rounding upward, sin(x) == (x - 1ULP)
-    if (rounding == FE_UPWARD && xbits.is_neg()) {
-      x_u--;
-      return FPBits(x_u).get_val();
-    }
-  }
-
-  if (xbits.is_inf_or_nan()) {
-    if (xbits.is_signaling_nan()) {
-      fputil::raise_except_if_required(FE_INVALID);
-      return FPBits::quiet_nan().get_val();
-    }
-
-    if (xbits.is_inf()) {
-      fputil::set_errno_if_required(EDOM);
-      fputil::raise_except_if_required(FE_INVALID);
-    }
-
-    return x + FPBits::quiet_nan().get_val();
-  }
-
-  float sin_k, cos_k, sin_y, cosm1_y;
-  sincosf16_eval(xf, sin_k, cos_k, sin_y, cosm1_y);
-
-  if (LIBC_UNLIKELY(sin_y == 0 && sin_k == 0))
-    return FPBits::zero(xbits.sign()).get_val();
-
-  // Since, cosm1_y = cos_y - 1, therefore:
-  //   sin(x) = cos_k * sin_y + sin_k + (cosm1_y * sin_k)
-  return fputil::cast<float16>(fputil::multiply_add(
-      sin_y, cos_k, fputil::multiply_add(cosm1_y, sin_k, sin_k)));
-}
+LLVM_LIBC_FUNCTION(float16, sinf16, (float16 x)) { return math::sinf16(x); }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt
index ef472992fea40..6ee2cba6e1658 100644
--- a/libc/test/shared/CMakeLists.txt
+++ b/libc/test/shared/CMakeLists.txt
@@ -84,6 +84,7 @@ add_fp_unittest(
     libc.src.__support.math.rsqrtf16
     libc.src.__support.math.sin
     libc.src.__support.math.sinf
+    libc.src.__support.math.sinf16
     libc.src.__support.math.tan
     libc.src.__support.math.tanf
 )
diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp
index 45a7934a83621..cbb32d295389a 100644
--- a/libc/test/shared/shared_math_test.cpp
+++ b/libc/test/shared/shared_math_test.cpp
@@ -51,6 +51,7 @@ TEST(LlvmLibcSharedMathTest, AllFloat16) {
 
   EXPECT_FP_EQ(0x1.921fb6p+0f16, LIBC_NAMESPACE::shared::acosf16(0.0f16));
   EXPECT_FP_EQ(0x1p+0f16, LIBC_NAMESPACE::shared::f16sqrtl(1.0L));
+  EXPECT_FP_EQ(0.0f16, LIBC_NAMESPACE::shared::sinf16(0.0f16));
 }
 
 #endif // LIBC_TYPES_HAS_FLOAT16
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 09b0a5a8e584a..ba4889a5bdf96 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -3497,6 +3497,16 @@ libc_support_library(
     ],
 )
 
+libc_support_library(
+    name = "__support_math_sinf16",
+    hdrs = ["src/__support/math/sinf16.h"],
+    deps = [
+        ":__support_fputil_nearest_integer",
+        ":__support_fputil_polyeval",
+        ":__support_math_sincosf16_utils",
+    ],
+)
+
 libc_support_library(
     name = "__support_math_sinhfcoshf_utils",
     hdrs = ["src/__support/math/sinhfcoshf_utils.h"],
@@ -5103,9 +5113,7 @@ libc_math_function(
 libc_math_function(
     name = "sinf16",
     additional_deps = [
-        ":__support_fputil_nearest_integer",
-        ":__support_fputil_polyeval",
-        ":__support_math_sincosf16_utils",
+        ":__support_math_sinf16",
     ],
 )
 

Copy link
Copy Markdown
Member

@bassiounix bassiounix left a comment

Choose a reason for hiding this comment

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

We need guard macros for float16 type.
Not all platforms has this type so we need to add a guard.
LIBC_TYPES_HAS_FLOAT16 found in include/llvm-libc-macros/float16-macros.h

Also please add the deps accordingly

@bassiounix
Copy link
Copy Markdown
Member

To have the build running, please resolve conflicts

@nico
Copy link
Copy Markdown
Contributor Author

nico commented Jan 27, 2026

Done!

Comment on lines +3514 to +3517
":__support_fputil_nearest_integer",
":__support_fputil_polyeval",
":__support_math_sincosf16_utils",
":llvm_libc_macros_float16_macros",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think for each and every include we want to add its deps

#include "hdr/errno_macros.h"
#include "hdr/fenv_macros.h"
#include "sincosf16_utils.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.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/macros/optimization.h"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Per utils/bazel/README.md / https://llvm.org/docs/SupportPolicy.html#peripheral-tier, the bazel build is not supported. If the existing bazel files are missing so much stuff (I'm just moving things around and putting in a best effort), I feel it's not my job to fix them up. The other bots are happy.

@nico nico merged commit 90829e5 into llvm:main Jan 27, 2026
28 of 29 checks passed
@nico nico deleted the libm-sinf16 branch January 27, 2026 13:17
he-weiwen added a commit to he-weiwen/llvm-project that referenced this pull request Feb 12, 2026
Move the tanpif16 implementation from libc/src/math/generic/tanpif16.cpp
into a header-only library at libc/src/__support/math/tanpif16.h, enabling
reuse from multiple contexts (libc entrypoint, shared/GPU) without code
duplication.

The entrypoint .cpp becomes a thin wrapper delegating to math::tanpif16().
A shared header (libc/shared/math/tanpif16.h) re-exports into namespace
shared. CMake and Bazel build targets are updated accordingly.

Follows the established pattern from cospif16 (llvm#154222) and sinf16 (llvm#178062).

Fixes part of llvm#147386.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bazel "Peripheral" support tier build system: utils/bazel libc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants