[libc-commits] [libc] 7855812 - [libc][math] Implement C23 half precision erf function (#179251)
via libc-commits
libc-commits at lists.llvm.org
Fri Mar 13 07:17:05 PDT 2026
Author: Anonmiraj
Date: 2026-03-13T10:16:59-04:00
New Revision: 785581213c3988c98376ec48abc56456566559f8
URL: https://github.com/llvm/llvm-project/commit/785581213c3988c98376ec48abc56456566559f8
DIFF: https://github.com/llvm/llvm-project/commit/785581213c3988c98376ec48abc56456566559f8.diff
LOG: [libc][math] Implement C23 half precision erf function (#179251)
The implementation reuses the approach in `erff`
Closes #133112
Added:
libc/shared/math/erff16.h
libc/src/__support/math/erff16.h
libc/src/math/erff16.h
libc/src/math/generic/erff16.cpp
libc/test/src/math/erff16_test.cpp
libc/test/src/math/smoke/erff16_test.cpp
Modified:
libc/config/gpu/amdgpu/entrypoints.txt
libc/config/gpu/nvptx/entrypoints.txt
libc/config/linux/aarch64/entrypoints.txt
libc/config/linux/riscv/entrypoints.txt
libc/config/linux/x86_64/entrypoints.txt
libc/include/math.yaml
libc/shared/math.h
libc/src/__support/math/CMakeLists.txt
libc/src/math/CMakeLists.txt
libc/src/math/generic/CMakeLists.txt
libc/test/shared/CMakeLists.txt
libc/test/shared/shared_math_test.cpp
libc/test/src/math/CMakeLists.txt
libc/test/src/math/smoke/CMakeLists.txt
utils/bazel/llvm-project-overlay/libc/BUILD.bazel
Removed:
################################################################################
diff --git a/libc/config/gpu/amdgpu/entrypoints.txt b/libc/config/gpu/amdgpu/entrypoints.txt
index f71b7991ff160..3647c2fe053fa 100644
--- a/libc/config/gpu/amdgpu/entrypoints.txt
+++ b/libc/config/gpu/amdgpu/entrypoints.txt
@@ -530,6 +530,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.cosf16
libc.src.math.coshf16
libc.src.math.cospif16
+ libc.src.math.erff16
libc.src.math.exp10f16
libc.src.math.exp10m1f16
libc.src.math.exp2f16
diff --git a/libc/config/gpu/nvptx/entrypoints.txt b/libc/config/gpu/nvptx/entrypoints.txt
index 097c626358c7f..82e5aa2b00d30 100644
--- a/libc/config/gpu/nvptx/entrypoints.txt
+++ b/libc/config/gpu/nvptx/entrypoints.txt
@@ -532,6 +532,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.cosf16
libc.src.math.coshf16
libc.src.math.cospif16
+ libc.src.math.erff16
libc.src.math.exp10f16
libc.src.math.exp10m1f16
libc.src.math.exp2f16
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index b91a736f6853b..c8522b316269d 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -682,6 +682,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.ceilf16
libc.src.math.copysignf16
libc.src.math.cospif16
+ libc.src.math.erff16
libc.src.math.expf16
libc.src.math.f16add
libc.src.math.f16addf
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index a906d602a7aae..9e049f277a165 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -696,6 +696,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.cosf16
libc.src.math.coshf16
libc.src.math.cospif16
+ libc.src.math.erff16
libc.src.math.exp10f16
libc.src.math.exp10m1f16
libc.src.math.exp2f16
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 202ee74e73293..9faeaa31eb195 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -745,6 +745,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.cosf16
libc.src.math.coshf16
libc.src.math.cospif16
+ libc.src.math.erff16
libc.src.math.exp10f16
libc.src.math.exp10m1f16
libc.src.math.exp2f16
diff --git a/libc/include/math.yaml b/libc/include/math.yaml
index 3a5c962020bc7..8cf29c1a8cff1 100644
--- a/libc/include/math.yaml
+++ b/libc/include/math.yaml
@@ -396,6 +396,13 @@ functions:
return_type: float
arguments:
- type: float
+ - name: erff16
+ standards:
+ - stdc
+ return_type: _Float16
+ arguments:
+ - type: _Float16
+ guard: LIBC_TYPES_HAS_FLOAT16
- name: exp
standards:
- stdc
diff --git a/libc/shared/math.h b/libc/shared/math.h
index 3d6e1c1796856..9f06272286425 100644
--- a/libc/shared/math.h
+++ b/libc/shared/math.h
@@ -74,6 +74,7 @@
#include "math/dfmal.h"
#include "math/dsqrtl.h"
#include "math/erff.h"
+#include "math/erff16.h"
#include "math/exp.h"
#include "math/exp10.h"
#include "math/exp10f.h"
diff --git a/libc/shared/math/erff16.h b/libc/shared/math/erff16.h
new file mode 100644
index 0000000000000..9e9f3f5c8e13e
--- /dev/null
+++ b/libc/shared/math/erff16.h
@@ -0,0 +1,27 @@
+//===-- Shared erff16 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_ERFF16_H
+#define LLVM_LIBC_SHARED_MATH_ERFF16_H
+
+#ifdef LIBC_TYPES_HAS_FLOAT16
+
+#include "shared/libc_common.h"
+#include "src/__support/math/erff16.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace shared {
+
+using math::erff16;
+
+} // namespace shared
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+#endif // LLVM_LIBC_SHARED_MATH_ERFF16_H
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index ca80655b4bd0c..73e8290107ec5 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -871,6 +871,18 @@ add_header_library(
libc.src.__support.macros.optimization
)
+add_header_library(
+ erff16
+ HDRS
+ erff16.h
+ DEPENDS
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.FPUtil.except_value_utils
+ libc.src.__support.FPUtil.multiply_add
+ libc.src.__support.FPUtil.polyeval
+ libc.src.__support.macros.optimization
+)
+
add_header_library(
exp_float_constants
HDRS
diff --git a/libc/src/__support/math/erff16.h b/libc/src/__support/math/erff16.h
new file mode 100644
index 0000000000000..8e3a92c092e22
--- /dev/null
+++ b/libc/src/__support/math/erff16.h
@@ -0,0 +1,181 @@
+//===-- Implementation header for erff16 ------------------------*- 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_ERFF16_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_ERFF16_H
+
+#include "include/llvm-libc-macros/float16-macros.h"
+
+#ifdef LIBC_TYPES_HAS_FLOAT16
+
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/except_value_utils.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace math {
+
+LIBC_INLINE float16 erff16(float16 x) {
+
+ // Polynomials approximating erf(x)/x on ( k/8, (k + 1)/8 ) generated by
+ // Sollya with: > P = fpminimax(erf(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14|],
+ // [|D...|],
+ // [k/8, (k + 1)/8]);
+ // for k = 0..31.
+ constexpr float ERFF16_COEFFS[32][8] = {
+ {0x1.20dd76p+0f, -0x1.812746p-2f, 0x1.ce2f22p-4f, -0x1.b82cdap-6f,
+ 0x1.564792p-8f, -0x1.8b3ac6p-11f, -0x1.126fcap-8f, 0x1.2d0bdcp-4f},
+ {0x1.20dd76p+0f, -0x1.812746p-2f, 0x1.ce2f22p-4f, -0x1.b82ce4p-6f,
+ 0x1.565bcap-8f, -0x1.c02c66p-11f, 0x1.f92f68p-14f, -0x1.def402p-17f},
+ {0x1.20dd76p+0f, -0x1.812746p-2f, 0x1.ce2f22p-4f, -0x1.b82ce2p-6f,
+ 0x1.565b9ep-8f, -0x1.c021f2p-11f, 0x1.f7c6d2p-14f, -0x1.c9e442p-17f},
+ {0x1.20dd76p+0f, -0x1.812746p-2f, 0x1.ce2f22p-4f, -0x1.b82cccp-6f,
+ 0x1.56597p-8f, -0x1.bfde2p-11f, 0x1.f31a9ep-14f, -0x1.a5a436p-17f},
+ {0x1.20dd76p+0f, -0x1.812746p-2f, 0x1.ce2f18p-4f, -0x1.b82be4p-6f,
+ 0x1.564becp-8f, -0x1.bee87p-11f, 0x1.e94436p-14f, -0x1.79c0f2p-17f},
+ {0x1.20dd74p+0f, -0x1.812744p-2f, 0x1.ce2ecp-4f, -0x1.b8265cp-6f,
+ 0x1.5615a2p-8f, -0x1.bc63aep-11f, 0x1.d87c22p-14f, -0x1.49584cp-17f},
+ {0x1.20dd74p+0f, -0x1.81272ap-2f, 0x1.ce2cbp-4f, -0x1.b80ecap-6f,
+ 0x1.5572e2p-8f, -0x1.b715e6p-11f, 0x1.bfbb1ap-14f, -0x1.177a56p-17f},
+ {0x1.20dd7p+0f, -0x1.812692p-2f, 0x1.ce23ap-4f, -0x1.b7c1dcp-6f,
+ 0x1.53e93p-8f, -0x1.ad97ccp-11f, 0x1.9f028cp-14f, -0x1.cdc4dap-18f},
+ {0x1.20dd58p+0f, -0x1.8123e6p-2f, 0x1.ce0458p-4f, -0x1.b6f52ep-6f,
+ 0x1.50c292p-8f, -0x1.9ea246p-11f, 0x1.776546p-14f, -0x1.737c12p-18f},
+ {0x1.20dce6p+0f, -0x1.811a5ap-2f, 0x1.cdab54p-4f, -0x1.b526d2p-6f,
+ 0x1.4b1d32p-8f, -0x1.896314p-11f, 0x1.4ad57p-14f, -0x1.231e1p-18f},
+ {0x1.20db48p+0f, -0x1.80fdd8p-2f, 0x1.ccd34p-4f, -0x1.b196a2p-6f,
+ 0x1.4210c2p-8f, -0x1.6dbdfcp-11f, 0x1.1bca2ep-14f, -0x1.bca37p-19f},
+ {0x1.20d64cp+0f, -0x1.80b4d4p-2f, 0x1.cb0882p-4f, -0x1.ab51fep-6f,
+ 0x1.34e1e6p-8f, -0x1.4c6638p-11f, 0x1.d9ad26p-15f, -0x1.4b0df8p-19f},
+ {0x1.20c8fcp+0f, -0x1.8010ccp-2f, 0x1.c7a47ep-4f, -0x1.a155bep-6f,
+ 0x1.233502p-8f, -0x1.26c94cp-11f, 0x1.8094f2p-15f, -0x1.e0e3d8p-20f},
+ {0x1.20a9bep+0f, -0x1.7ec7fcp-2f, 0x1.c1d758p-4f, -0x1.92c16p-6f,
+ 0x1.0d3072p-8f, -0x1.fda5bp-12f, 0x1.2fdd7cp-15f, -0x1.54eed4p-20f},
+ {0x1.206828p+0f, -0x1.7c73f8p-2f, 0x1.b8c2dcp-4f, -0x1.7f0e5p-6f,
+ 0x1.e7061ep-9f, -0x1.ad36e8p-12f, 0x1.d39222p-16f, -0x1.d83dacp-21f},
+ {0x1.1feb8ep+0f, -0x1.789834p-2f, 0x1.aba346p-4f, -0x1.663adcp-6f,
+ 0x1.ae99fcp-9f, -0x1.602f96p-12f, 0x1.5e9718p-16f, -0x1.3fca1p-21f},
+ {0x1.1f12fep+0f, -0x1.72b1d2p-2f, 0x1.99fc0ep-4f, -0x1.48db0ap-6f,
+ 0x1.73e368p-9f, -0x1.19b35ep-12f, 0x1.007988p-16f, -0x1.a7edcep-22f},
+ {0x1.1db7bp+0f, -0x1.6a4e4ap-2f, 0x1.83bbdep-4f, -0x1.2809b4p-6f,
+ 0x1.39c08cp-9f, -0x1.b7b45ap-13f, 0x1.6e99b4p-17f, -0x1.13619cp-22f},
+ {0x1.1bb1c8p+0f, -0x1.5f23bap-2f, 0x1.694c92p-4f, -0x1.053e1cp-6f,
+ 0x1.02bf72p-9f, -0x1.4f479p-13f, 0x1.005f8p-17f, -0x1.5f2446p-23f},
+ {0x1.18dec4p+0f, -0x1.5123f6p-2f, 0x1.4b8a1cp-4f, -0x1.c4243p-7f,
+ 0x1.a1a8ap-10f, -0x1.f466b4p-14f, 0x1.5f835ep-18f, -0x1.b83166p-24f},
+ {0x1.152804p+0f, -0x1.4084cep-2f, 0x1.2ba2e8p-4f, -0x1.800f2ep-7f,
+ 0x1.4a6dbp-10f, -0x1.6e326ap-14f, 0x1.d9761ap-19f, -0x1.0fca34p-24f},
+ {0x1.1087aep+0f, -0x1.2dbb04p-2f, 0x1.0aea8cp-4f, -0x1.40b516p-7f,
+ 0x1.00c9ep-10f, -0x1.076afcp-14f, 0x1.39fadep-19f, -0x1.4b5762p-25f},
+ {0x1.0b0a7ap+0f, -0x1.19699p-2f, 0x1.d5551ep-5f, -0x1.07cce2p-7f,
+ 0x1.890348p-11f, -0x1.757ecap-15f, 0x1.9b258ap-20f, -0x1.8fc6d2p-26f},
+ {0x1.04ce2cp+0f, -0x1.0449e4p-2f, 0x1.97f742p-5f, -0x1.ac8254p-8f,
+ 0x1.28f5f6p-11f, -0x1.05b69ap-15f, 0x1.0a888ep-20f, -0x1.deace2p-27f},
+ {0x1.fbf9fcp-1f, -0x1.de264p-3f, 0x1.5f5b2p-5f, -0x1.588bc8p-8f,
+ 0x1.bc6a0ap-12f, -0x1.6b9faep-16f, 0x1.573204p-21f, -0x1.1d3806p-27f},
+ {0x1.ed8f18p-1f, -0x1.b4cb6ap-3f, 0x1.2c7f3ep-5f, -0x1.13052p-8f,
+ 0x1.4a5028p-12f, -0x1.f672bap-17f, 0x1.b83c76p-22f, -0x1.534f1ap-28f},
+ {0x1.debd34p-1f, -0x1.8d7cdap-3f, 0x1.ff9958p-6f, -0x1.b50be6p-9f,
+ 0x1.e92c8ep-13f, -0x1.5a4b88p-17f, 0x1.1a2774p-22f, -0x1.942ae6p-29f},
+ {0x1.cfdbfp-1f, -0x1.68e33ep-3f, 0x1.b2683ep-6f, -0x1.5a9174p-9f,
+ 0x1.69ddd4p-13f, -0x1.dd8f3ap-18f, 0x1.6a755p-23f, -0x1.e366ep-30f},
+ {0x1.c132aep-1f, -0x1.475a8ap-3f, 0x1.70a432p-6f, -0x1.12e3d4p-9f,
+ 0x1.0c16bp-13f, -0x1.4a47f8p-18f, 0x1.d3d494p-24f, -0x1.2302c6p-30f},
+ {0x1.b2f5fep-1f, -0x1.28fefp-3f, 0x1.3923acp-6f, -0x1.b4ff7ap-10f,
+ 0x1.8ea0ecp-14f, -0x1.cb31ecp-19f, 0x1.30011ep-24f, -0x1.61771p-31f},
+ {0x1.a54854p-1f, -0x1.0dbdbap-3f, 0x1.0a93e2p-6f, -0x1.5c96ap-10f,
+ 0x1.29e0ccp-14f, -0x1.4160d8p-19f, 0x1.8e7b68p-25f, -0x1.b1cf2cp-32f},
+ {0x1.983ceep-1f, -0x1.eacc78p-4f, 0x1.c74418p-7f, -0x1.1756ap-10f,
+ 0x1.bff366p-15f, -0x1.c56c02p-20f, 0x1.07b492p-25f, -0x1.0d4be8p-32f},
+ };
+#ifndef LIBC_TARGET_CPU_HAS_FMA
+ constexpr size_t N_ERFF16_EXCEPTS = 5;
+#else
+ constexpr size_t N_ERFF16_EXCEPTS = 4;
+#endif
+
+ constexpr fputil::ExceptValues<float16, N_ERFF16_EXCEPTS> ERFF16_EXCEPTS{{
+ {0x1612, 0x16D9, 1, 0, 0},
+ {0x165C, 0x172C, 1, 0, 1},
+ {0x16F0, 0x17D3, 1, 0, 1},
+ {0x3BF2, 0x3AB7, 1, 0, 1},
+#ifndef LIBC_TARGET_CPU_HAS_FMA
+ {0x3FF6, 0x3BF5, 1, 0, 1},
+#endif
+ }};
+ using FPBits = typename fputil::FPBits<float16>;
+ FPBits xbits(x);
+ uint16_t x_abs = xbits.abs().uintval();
+ bool is_neg = xbits.is_neg();
+
+ float xf = fputil::cast<float16>(x);
+ if (auto r = ERFF16_EXCEPTS.lookup_odd(x_abs, is_neg);
+ LIBC_UNLIKELY(r.has_value()))
+ return r.value();
+
+ // |x| >= 4.0
+ if (LIBC_UNLIKELY(x_abs >= 0x4200U)) {
+ // Check for NaN or Inf
+ if (LIBC_UNLIKELY(x_abs >= 0x7c00U)) {
+ if (x_abs > 0x7c00U) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ return x;
+ }
+ // Inf -> returns 1.0 or -1.0
+ return is_neg ? -1.0f16 : 1.0f16;
+ }
+
+ return fputil::cast<float16>(is_neg ? -1.0f - xf * 0x1.0p-28f
+ : 1.0f - xf * 0x1.0p-28f);
+ }
+
+ // Polynomial approximation:
+ // erf(x) ~ x * (c0 + c1 * x^2 + c2 * x^4 + ... + c7 * x^14)
+
+ int idx = static_cast<int>(xbits.abs().get_val() * 8.0f16);
+
+ float xsq = xf * xf;
+ float x4 = xsq * xsq;
+ float c0 = fputil::multiply_add(xsq, (ERFF16_COEFFS[idx][1]),
+ (ERFF16_COEFFS[idx][0]));
+ float c1 = fputil::multiply_add(xsq, (ERFF16_COEFFS[idx][3]),
+ (ERFF16_COEFFS[idx][2]));
+ float c2 = fputil::multiply_add(xsq, (ERFF16_COEFFS[idx][5]),
+ (ERFF16_COEFFS[idx][4]));
+ float c3 = fputil::multiply_add(xsq, (ERFF16_COEFFS[idx][7]),
+ (ERFF16_COEFFS[idx][6]));
+
+ float x8 = x4 * x4;
+ float p0 = fputil::multiply_add(x4, c1, c0);
+ float p1 = fputil::multiply_add(x4, c3, c2);
+
+ float result = xf * fputil::multiply_add(x8, p1, p0);
+
+ // Clamp result to just inside [-1, 1]
+ if (LIBC_UNLIKELY(result > 1.0f))
+ return fputil::cast<float16>(1.0f - xf * 0x1.0p-28f);
+ else if (LIBC_UNLIKELY(result < -1.0f))
+ return fputil::cast<float16>(-1.0f - xf * 0x1.0p-28f);
+
+ return fputil::cast<float16>(result);
+}
+
+} // namespace math
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ERFF16_H
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index db13fcad47c48..893e5e35d90bb 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -138,6 +138,7 @@ add_math_entrypoint_object(dsubf128)
add_math_entrypoint_object(erf)
add_math_entrypoint_object(erff)
+add_math_entrypoint_object(erff16)
add_math_entrypoint_object(exp)
add_math_entrypoint_object(expf)
diff --git a/libc/src/math/erff16.h b/libc/src/math/erff16.h
new file mode 100644
index 0000000000000..922fe09df7911
--- /dev/null
+++ b/libc/src/math/erff16.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for erff16 ------------------------*- 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_ERFF16_H
+#define LLVM_LIBC_SRC_MATH_ERFF16_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+float16 erff16(float16 x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_ERFF16_H
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 405276b0801f1..b9fa480b05bc5 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -1285,6 +1285,17 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ erff16
+ SRCS
+ erff16.cpp
+ HDRS
+ ../erff16.h
+ DEPENDS
+ libc.src.__support.math.erff16
+ libc.src.errno.errno
+)
+
add_entrypoint_object(
exp
SRCS
diff --git a/libc/src/math/generic/erff16.cpp b/libc/src/math/generic/erff16.cpp
new file mode 100644
index 0000000000000..d7e4f207a818e
--- /dev/null
+++ b/libc/src/math/generic/erff16.cpp
@@ -0,0 +1,16 @@
+//===-- Half-precision erf(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/erff16.h"
+#include "src/__support/math/erff16.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(float16, erff16, (float16 x)) { return math::erff16(x); }
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt
index 7bda654fd24de..97b7637a29c23 100644
--- a/libc/test/shared/CMakeLists.txt
+++ b/libc/test/shared/CMakeLists.txt
@@ -73,6 +73,7 @@ add_fp_unittest(
libc.src.__support.math.exp10m1f
libc.src.__support.math.exp10m1f16
libc.src.__support.math.erff
+ libc.src.__support.math.erff16
libc.src.__support.math.exp
libc.src.__support.math.exp2
libc.src.__support.math.exp2f
diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp
index 758d8e583b0b3..ad5176e4de380 100644
--- a/libc/test/shared/shared_math_test.cpp
+++ b/libc/test/shared/shared_math_test.cpp
@@ -29,6 +29,7 @@ TEST(LlvmLibcSharedMathTest, AllFloat16) {
EXPECT_FP_EQ(0x1p+0f16, LIBC_NAMESPACE::shared::cosf16(0.0f16));
EXPECT_FP_EQ(0x1p+0f16, LIBC_NAMESPACE::shared::coshf16(0.0f16));
EXPECT_FP_EQ(0x1p+0f16, LIBC_NAMESPACE::shared::cospif16(0.0f16));
+ EXPECT_FP_EQ(0x0p+0f16, LIBC_NAMESPACE::shared::erff16(0.0f16));
EXPECT_FP_EQ(0x1p+0f16, LIBC_NAMESPACE::shared::exp10f16(0.0f16));
EXPECT_FP_EQ(0x0p+0f16, LIBC_NAMESPACE::shared::exp10m1f16(0.0f16));
EXPECT_FP_EQ(0x1p+0f16, LIBC_NAMESPACE::shared::exp2f16(0.0f16));
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 2802be73639bf..66a28a71c49c1 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -2699,6 +2699,18 @@ add_fp_unittest(
libc.src.__support.FPUtil.fp_bits
)
+add_fp_unittest(
+ erff16_test
+ NEED_MPFR
+ SUITE
+ libc-math-unittests
+ SRCS
+ erff16_test.cpp
+ DEPENDS
+ libc.src.math.erff16
+ libc.src.__support.FPUtil.fp_bits
+)
+
add_fp_unittest(
pow_test
NEED_MPFR
diff --git a/libc/test/src/math/erff16_test.cpp b/libc/test/src/math/erff16_test.cpp
new file mode 100644
index 0000000000000..522cc85ab15d6
--- /dev/null
+++ b/libc/test/src/math/erff16_test.cpp
@@ -0,0 +1,43 @@
+//===-- Exhaustive test for erff16 ----------------------------------------===//
+//
+// 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/macros/optimization.h"
+#include "src/math/erff16.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+using LlvmLibcErff16Test = LIBC_NAMESPACE::testing::FPTest<float16>;
+
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
+
+// Range: [0, Inf];
+// 0x0000 is +0.0, 0x7c00 is +Inf.
+static constexpr uint16_t POS_START = 0x0000U;
+static constexpr uint16_t POS_STOP = 0x7c00U;
+
+// Range: [-0, -Inf];
+// 0x8000 is -0.0, 0xfc00 is -Inf.
+static constexpr uint16_t NEG_START = 0x8000U;
+static constexpr uint16_t NEG_STOP = 0xfc00U;
+
+TEST_F(LlvmLibcErff16Test, PositiveRange) {
+ for (uint16_t v = POS_START; v <= POS_STOP; ++v) {
+ float16 x = FPBits(v).get_val();
+ EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Erf, x,
+ LIBC_NAMESPACE::erff16(x), 0.5);
+ }
+}
+
+TEST_F(LlvmLibcErff16Test, NegativeRange) {
+ for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) {
+ float16 x = FPBits(v).get_val();
+ EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Erf, x,
+ LIBC_NAMESPACE::erff16(x), 0.5);
+ }
+}
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index d735058c1affc..84e9cc363a6fc 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -5148,6 +5148,16 @@ add_fp_unittest(
libc.src.__support.FPUtil.fp_bits
)
+add_fp_unittest(
+ erff16_test
+ SUITE
+ libc-math-smoke-tests
+ SRCS
+ erff16_test.cpp
+ DEPENDS
+ libc.src.math.erff16
+)
+
add_fp_unittest(
pow_test
SUITE
diff --git a/libc/test/src/math/smoke/erff16_test.cpp b/libc/test/src/math/smoke/erff16_test.cpp
new file mode 100644
index 0000000000000..71a6814fb5761
--- /dev/null
+++ b/libc/test/src/math/smoke/erff16_test.cpp
@@ -0,0 +1,51 @@
+//===-- Unittests for erff16 ----------------------------------------------===//
+//
+// 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/math_macros.h"
+#include "hdr/stdint_proxy.h"
+#include "src/math/erff16.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using LlvmLibcErffTest = LIBC_NAMESPACE::testing::FPTest<float16>;
+
+TEST_F(LlvmLibcErffTest, SpecialNumbers) {
+ EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::erff16(sNaN), FE_INVALID);
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::erff16(aNaN));
+ EXPECT_FP_EQ_ALL_ROUNDING(1.0f16, LIBC_NAMESPACE::erff16(inf));
+ EXPECT_FP_EQ_ALL_ROUNDING(-1.0f16, LIBC_NAMESPACE::erff16(neg_inf));
+ EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::erff16(zero));
+ EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, LIBC_NAMESPACE::erff16(neg_zero));
+}
+
+#ifdef LIBC_TEST_FTZ_DAZ
+
+using namespace LIBC_NAMESPACE::testing;
+
+TEST_F(LlvmLibcErffTest, FTZMode) {
+ ModifyMXCSR mxcsr(FTZ);
+ EXPECT_FP_EQ(0x1p-24f16, LIBC_NAMESPACE::erff16(min_denormal));
+ EXPECT_FP_EQ(0x1.208p-14f16, LIBC_NAMESPACE::erff16(max_denormal));
+}
+
+TEST_F(LlvmLibcErffTest, DAZMode) {
+ ModifyMXCSR mxcsr(DAZ);
+ EXPECT_FP_EQ(0x1p-24f16, LIBC_NAMESPACE::erff16(min_denormal));
+ EXPECT_FP_EQ(0x1.208p-14f16, LIBC_NAMESPACE::erff16(max_denormal));
+}
+
+TEST_F(LlvmLibcErffTest, FTZDAZMode) {
+ ModifyMXCSR mxcsr(FTZ | DAZ);
+
+ EXPECT_FP_EQ(0x1p-24f16, LIBC_NAMESPACE::erff16(min_denormal));
+ EXPECT_FP_EQ(0x1.208p-14f16, LIBC_NAMESPACE::erff16(max_denormal));
+}
+
+#endif
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index e9e4601c56f30..814cc3eb8f505 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -3589,6 +3589,19 @@ libc_support_library(
":__support_fputil_polyeval",
":__support_macros_config",
":__support_macros_optimization",
+ ":__support_math_common_constants",
+ ],
+)
+
+libc_support_library(
+ name = "__support_math_erff16",
+ hdrs = ["src/__support/math/erff16.h"],
+ deps = [
+ ":__support_fputil_fenv_impl",
+ ":__support_fputil_fp_bits",
+ ":__support_fputil_multiply_add",
+ ":__support_macros_optimization",
+ ":__support_math_common_constants",
],
)
@@ -6419,6 +6432,13 @@ libc_math_function(
additional_deps = [":__support_math_erff"],
)
+libc_math_function(
+ name = "erff16",
+ additional_deps = [
+ ":__support_math_erff16",
+ ],
+)
+
libc_math_function(
name = "exp",
additional_deps = [
More information about the libc-commits
mailing list