[libc-commits] [libc] [libc][math] Implement C23 half precision erfc function (PR #180930)
via libc-commits
libc-commits at lists.llvm.org
Wed Feb 11 04:27:23 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-risc-v
@llvm/pr-subscribers-libc
Author: Anonmiraj (AnonMiraj)
<details>
<summary>Changes</summary>
Add support for the half-precision complementary error function erfcf16, using a Sollya-generated polynomial implementation with proper handling of special cases.
Extend the MPFR utilities with erfc support to allow tests.
closes: #<!-- -->180927
---
Patch is 24.23 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/180930.diff
24 Files Affected:
- (modified) libc/config/gpu/amdgpu/entrypoints.txt (+1)
- (modified) libc/config/gpu/nvptx/entrypoints.txt (+1)
- (modified) libc/config/linux/aarch64/entrypoints.txt (+1)
- (modified) libc/config/linux/arm/entrypoints.txt (+1)
- (modified) libc/config/linux/riscv/entrypoints.txt (+1)
- (modified) libc/config/linux/x86_64/entrypoints.txt (+1)
- (modified) libc/config/windows/entrypoints.txt (+1)
- (modified) libc/include/math.yaml (+6)
- (modified) libc/shared/math.h (+1)
- (added) libc/shared/math/erfcf16.h (+27)
- (modified) libc/src/__support/math/CMakeLists.txt (+11)
- (added) libc/src/__support/math/erfcf16.h (+195)
- (modified) libc/src/math/CMakeLists.txt (+2)
- (added) libc/src/math/erfcf16.h (+21)
- (modified) libc/src/math/generic/CMakeLists.txt (+11)
- (added) libc/src/math/generic/erfcf16.cpp (+16)
- (modified) libc/test/src/math/CMakeLists.txt (+12)
- (added) libc/test/src/math/erfcf16_test.cpp (+43)
- (modified) libc/test/src/math/smoke/CMakeLists.txt (+10)
- (added) libc/test/src/math/smoke/erfcf16_test.cpp (+51)
- (modified) libc/utils/MPFRWrapper/MPCommon.cpp (+6)
- (modified) libc/utils/MPFRWrapper/MPCommon.h (+1)
- (modified) libc/utils/MPFRWrapper/MPFRUtils.cpp (+2)
- (modified) libc/utils/MPFRWrapper/MPFRUtils.h (+1)
``````````diff
diff --git a/libc/config/gpu/amdgpu/entrypoints.txt b/libc/config/gpu/amdgpu/entrypoints.txt
index 0dda7d5c683ec..551fe8bd5693a 100644
--- a/libc/config/gpu/amdgpu/entrypoints.txt
+++ b/libc/config/gpu/amdgpu/entrypoints.txt
@@ -311,6 +311,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.dfmal
libc.src.math.dmull
libc.src.math.dsqrtl
+ libc.src.math.erfcf16
libc.src.math.erff
libc.src.math.exp
libc.src.math.exp10
diff --git a/libc/config/gpu/nvptx/entrypoints.txt b/libc/config/gpu/nvptx/entrypoints.txt
index 6070fb5b17b3c..1cf9cb3fc9c7b 100644
--- a/libc/config/gpu/nvptx/entrypoints.txt
+++ b/libc/config/gpu/nvptx/entrypoints.txt
@@ -311,6 +311,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.dfmal
libc.src.math.dmull
libc.src.math.dsqrtl
+ libc.src.math.erfcf16
libc.src.math.erff
libc.src.math.exp
libc.src.math.exp10
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 970c825bbfc96..8c65e1c7de90c 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -452,6 +452,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.dmull
libc.src.math.dsqrtl
libc.src.math.dsubl
+ libc.src.math.erfcf16
libc.src.math.erff
libc.src.math.exp
libc.src.math.exp10
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index f04ac40145d3a..ab5bebbdf7516 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -274,6 +274,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.coshf
libc.src.math.dfmal
libc.src.math.dsqrtl
+ libc.src.math.erfcf16
libc.src.math.erff
libc.src.math.exp
libc.src.math.exp10
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 7baf4de9d8a5b..f9728ec3a4b13 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -456,6 +456,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.dmull
libc.src.math.dsqrtl
libc.src.math.dsubl
+ libc.src.math.erfcf16
libc.src.math.erff
libc.src.math.exp
libc.src.math.exp10
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 9399b284fa2da..906e6699e5f16 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -498,6 +498,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.daddl
libc.src.math.ddivl
libc.src.math.dsubl
+ libc.src.math.erfcf16
libc.src.math.erff
libc.src.math.exp
libc.src.math.exp10
diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index 3a76595b258e2..93eb84d9ac2b5 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -156,6 +156,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.ddivl
libc.src.math.dfmal
libc.src.math.dsubl
+ libc.src.math.erfcf16
libc.src.math.erff
libc.src.math.exp
libc.src.math.expf
diff --git a/libc/include/math.yaml b/libc/include/math.yaml
index afd3ae33305c1..540925a71aa5a 100644
--- a/libc/include/math.yaml
+++ b/libc/include/math.yaml
@@ -396,6 +396,12 @@ functions:
return_type: float
arguments:
- type: float
+ - name: erfcf16
+ standards:
+ - stdc
+ return_type: _Float16
+ arguments:
+ - type: _Float16
- name: exp
standards:
- stdc
diff --git a/libc/shared/math.h b/libc/shared/math.h
index 4b0f2c67b0c86..b2e2632cbb0b0 100644
--- a/libc/shared/math.h
+++ b/libc/shared/math.h
@@ -42,6 +42,7 @@
#include "math/dfmaf128.h"
#include "math/dfmal.h"
#include "math/dsqrtl.h"
+#include "math/erfcf16.h"
#include "math/erff.h"
#include "math/exp.h"
#include "math/exp10.h"
diff --git a/libc/shared/math/erfcf16.h b/libc/shared/math/erfcf16.h
new file mode 100644
index 0000000000000..779401fe5dc09
--- /dev/null
+++ b/libc/shared/math/erfcf16.h
@@ -0,0 +1,27 @@
+//===-- Shared erfcf16 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_ERFCF16_H
+#define LLVM_LIBC_SHARED_MATH_ERFCF16_H
+
+#ifdef LIBC_TYPES_HAS_FLOAT16
+
+#include "shared/libc_common.h"
+#include "src/__support/math/erfcf16.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace shared {
+
+using math::erfcf16;
+
+} // namespace shared
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+#endif // LLVM_LIBC_SHARED_MATH_ERFCF16_H
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index 6705a2a08f3a7..7d2cb24e6bd57 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -508,6 +508,17 @@ add_header_library(
libc.src.__support.macros.properties.cpu_features
)
+add_header_library(
+ erfcf16
+ HDRS
+ erfcf16.h
+ DEPENDS
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.FPUtil.multiply_add
+ libc.src.__support.macros.config
+ libc.src.__support.macros.optimization
+)
+
add_header_library(
erff
HDRS
diff --git a/libc/src/__support/math/erfcf16.h b/libc/src/__support/math/erfcf16.h
new file mode 100644
index 0000000000000..afddceb44aab3
--- /dev/null
+++ b/libc/src/__support/math/erfcf16.h
@@ -0,0 +1,195 @@
+//===-- Implementation header for erfcf16 -----------------------*- 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_ERFCF16_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_ERFCF16_H
+
+#include "include/llvm-libc-macros/float16-macros.h"
+
+#ifdef LIBC_TYPES_HAS_FLOAT16
+
+#include "src/__support/FPUtil/FPBits.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 erfcf16(float16 x) {
+ // Polynomials approximating erfc(|x|) on ( k/8, (k + 1)/8 ) generated by
+ // Sollya with: > P = fpminimax(erfc(x), [|0, 1, 2, 3, 4, 5, 6, 7|], [|D...|],
+ // [k/8, (k + 1)/8]);
+ // for k = 0..31.
+ constexpr double COEFFS[32][8] = {
+ {0x1.000000000001ap0, -0x1.20dd75042fe11p0, 0x1.eedc6f1918987p-31,
+ 0x1.812743003751cp-2, 0x1.b64a20332eb3dp-20, -0x1.ce4a3020c5e8dp-4,
+ 0x1.c23deea13dadap-13, 0x1.ab4a28f5e2202p-6},
+ {0x1.000000261e1a9p0, -0x1.20dd7ba6be17dp0, 0x1.feaa7936695dep-18,
+ 0x1.8111aee222bb3p-2, 0x1.1e49370dc07e5p-11, -0x1.d7628d2f099dfp-4,
+ 0x1.64a9012704b63p-8, 0x1.507b7d761dbbdp-6},
+ {0x1.00000e7d6c906p0, -0x1.20deeb74e7ceep0, 0x1.06dc8c97aa061p-12,
+ 0x1.7f85253e7aa3fp-2, 0x1.9a4f9aedbda2ap-8, -0x1.06934bb956303p-3,
+ 0x1.6f9b296bf2cp-6, 0x1.6725f01ebef61p-7},
+ {0x1.0000f0d17e652p0, -0x1.20eec49f1bb9fp0, 0x1.15bf700a3afecp-9,
+ 0x1.7742179b9b76p-2, 0x1.bf4cf873dfcc7p-6, -0x1.4a7453b65895cp-3,
+ 0x1.a7171b2b94f65p-5, -0x1.3db6226bfb07ep-13},
+ {0x1.00064f5d99b02p0, -0x1.21388015af14dp0, 0x1.1f337b73afb37p-7,
+ 0x1.60d75bce880c8p-2, 0x1.21bee64bd2bfep-4, -0x1.b4c9b7cc4d861p-3,
+ 0x1.6156b46d67517p-4, -0x1.4a6ad4a1a9a6dp-7},
+ {0x1.001646fa41f93p0, -0x1.21ea485326f4dp0, 0x1.64386e40081f9p-6,
+ 0x1.3d6f1181dc1f2p-2, 0x1.025fb3fbb9694p-3, -0x1.111c22989270ep-2,
+ 0x1.d6df1d011e6a5p-4, -0x1.11af42f321738p-6},
+ {0x1.00277226071fep0, -0x1.228d8a26ceba9p0, 0x1.056317058c132p-5,
+ 0x1.25cda1a141e98p-2, 0x1.42d4218a6d87p-3, -0x1.2b8395261188dp-2,
+ 0x1.038075602477dp-3, -0x1.3754fc0d6d03dp-6},
+ {0x1.ffdf656fd5544p-1, -0x1.20dbf015167a4p0, 0x1.426f915ba02ccp-7,
+ 0x1.4fb39034f18e7p-2, 0x1.cb1896449b52p-4, -0x1.0c5791c048cfbp-2,
+ 0x1.d8acdd7692448p-4, -0x1.19cd761c2fcbfp-6},
+ {0x1.fd52aab04431fp-1, -0x1.18084cdb7869fp0, -0x1.7b239d67be2f2p-4,
+ 0x1.fce1bd937aa95p-2, -0x1.c7f53c1a8860cp-5, -0x1.4c0be3dd60746p-3,
+ 0x1.511a1822165ccp-4, -0x1.997b355ae9313p-7},
+ {0x1.f630da3ca180fp-1, -0x1.01f9cdebb8a42p0, -0x1.48d5e3d9e3bbbp-2,
+ 0x1.ab0c1d54fd42p-1, -0x1.6abcd4a981266p-2, -0x1.b62df36853d2ap-9,
+ 0x1.219207ea8070cp-5, -0x1.acb65c612c3cbp-8},
+ {0x1.e8518d1829bdep-1, -0x1.b680bb7f5ca05p-1, -0x1.5dd957f485f26p-1,
+ 0x1.50ed752c29101p0, -0x1.7a989bc66b636p-1, 0x1.73a7c29911c75p-3,
+ -0x1.c8f687bc29284p-7, -0x1.d9a2c5e81906dp-11},
+ {0x1.d455b8759924bp-1, -0x1.50d550bd0031ap-1, -0x1.1dd31217d772dp0,
+ 0x1.d768acdc964e1p0, -0x1.1f325385cfea3p0, 0x1.64f5ef1e1b149p-2,
+ -0x1.becf19e32832cp-5, 0x1.b3d95b8249dc2p-9},
+ {0x1.c03fc3d1dfd52p-1, -0x1.e5be0a5eb8ea1p-2, -0x1.7c0ea4743a94ap0,
+ 0x1.203ad2e0bb23dp1, -0x1.657e5f6a3a7bfp0, 0x1.d5e86ba1d05p-2,
+ -0x1.44444f5e3e2f1p-4, 0x1.7465b9882b39bp-8},
+ {0x1.b82e3874361f8p-1, -0x1.9f1c5ba9f25b5p-2, -0x1.9d2f419b75126p0,
+ 0x1.317ed738c38e5p1, -0x1.7b17d3b23fc5cp0, 0x1.f656370d9a5a4p-2,
+ -0x1.5f519dd3bee19p-4, 0x1.9b165d0ccb0fep-8},
+ {0x1.cba592d21041ap-1, -0x1.1c9e2f4ac28efp-1, -0x1.5bcbe8415d66fp0,
+ 0x1.12aa2de5d021cp1, -0x1.58324c5f23234p0, 0x1.c6ed4ac6a2edfp-2,
+ -0x1.3b86d3a3e85c9p-4, 0x1.6cc0ec77d11b9p-8},
+ {0x1.03caf33285512p0, -0x1.fb887e48a3eedp-1, -0x1.5431e46bb9a3fp-1,
+ 0x1.87e44d6713845p0, -0x1.047b2b206c351p0, 0x1.5c0fe8541e1e5p-2,
+ -0x1.df700bfe6dee5p-5, 0x1.1089feecce9f6p-8},
+ {0x1.37baad7246b3cp0, -0x1.b333d66d61c0cp0, 0x1.9673eefbcd456p-2,
+ 0x1.4b8e581c9bd57p-1, -0x1.271a5001975b3p-1, 0x1.a9544c9bc6f69p-3,
+ -0x1.2b04fcf02cfe4p-5, 0x1.52f61b5bf2013p-9},
+ {0x1.7c8089dfc728fp0, -0x1.4aca78f669032p1, 0x1.a50b5166895f1p0,
+ -0x1.52bccda96d2ddp-2, -0x1.db1a7723e7021p-4, 0x1.3e221766f1413p-4,
+ -0x1.07c689c1529d4p-6, 0x1.3e28897c72f86p-10},
+ {0x1.c677ecd59f0c9p0, -0x1.bddee5876d025p1, 0x1.6c05470bf9855p1,
+ -0x1.3838ea389805p0, 0x1.1e0da063ba588p-2, -0x1.c8701de42abb8p-6,
+ -0x1.d505f665736f4p-12, 0x1.ca3e25ddd2f8ep-13},
+ {0x1.0346dd8ccf496p1, -0x1.0e36567843072p2, 0x1.e39ee1779480ap1,
+ -0x1.e05781af98971p0, 0x1.1cd860f207bc6p-1, -0x1.91471b20d7ea7p-4,
+ 0x1.3472b380bd896p-7, -0x1.8a32a1c029365p-12},
+ {0x1.175cf188a8137p1, -0x1.2a6aea014a1a7p2, 0x1.13c3894652ae3p2,
+ -0x1.1d97a2368998p1, 0x1.65c57ae4f9a2ep-1, -0x1.0ee6b7e8303e8p-3,
+ 0x1.cae7deaf84ca3p-7, -0x1.4f32ea2cd38e3p-11},
+ {0x1.1b0bf6d5ea90bp1, -0x1.2f6bcdbfd2bf8p2, 0x1.199682b413d76p2,
+ -0x1.251f9f5a8b0dap1, 0x1.7174a7ecafc0ep-1, -0x1.19c6a1d04557fp-3,
+ 0x1.e164b9a559bfdp-7, -0x1.6320142d50654p-11},
+ {0x1.0d8865040d536p1, -0x1.1e4d7b5aadcb3p2, 0x1.06ffcd830db2p2,
+ -0x1.0eb1633113f1fp1, 0x1.50f8dac72a8f9p-1, -0x1.fb183d2925a88p-4,
+ 0x1.aadfbeb9cff03p-7, -0x1.35fe3091fd72bp-11},
+ {0x1.e30746fa5c05ap0, -0x1.f8814cab9a532p1, 0x1.c70d7871e1e66p1,
+ -0x1.cb40d988d46f7p0, 0x1.17ea520e30ee5p-1, -0x1.9bf4656539b33p-4,
+ 0x1.52ba88a712da3p-7, -0x1.dff8c68511d54p-12},
+ {0x1.980594d76c9c6p0, -0x1.a1111fecc5d33p1, 0x1.6fac90467734ap1,
+ -0x1.6a38a8cadbc1dp0, 0x1.ae83820056a13p-2, -0x1.3489645378924p-4,
+ 0x1.eda542162eab4p-8, -0x1.53f0f5d191e15p-12},
+ {0x1.4593f0667381p0, -0x1.44c18f230e828p1, 0x1.17126063fa673p1,
+ -0x1.0bb8315d99e44p0, 0x1.358c4f8bf482ep-2, -0x1.af3eebe9cb455p-5,
+ 0x1.4f090acf146ep-8, -0x1.bfc7954478304p-13},
+ {0x1.ebcae3fdca674p-1, -0x1.dde1bcf5a5146p0, 0x1.8fb142f724b27p0,
+ -0x1.74e2bafe8789fp-1, 0x1.a2f67a40275d7p-3, -0x1.1b6406e10fca4p-5,
+ 0x1.ab4ed0d6da84fp-9, -0x1.14f03579c96fep-13},
+ {0x1.6038027133b66p-1, -0x1.4d18991ed6939p0, 0x1.0ef1d6fa80951p0,
+ -0x1.eb55a8112702cp-2, 0x1.0c19cb48e5a46p-3, -0x1.60151a50d69f3p-6,
+ 0x1.018b2a2cf7aa6p-9, -0x1.43bda617ae0e6p-14},
+ {0x1.df3b0de232601p-2, -0x1.b8e05100448c4p-1, 0x1.5ca6e2528e8d1p-1,
+ -0x1.332de46c2acb5p-2, 0x1.4595849385e42p-4, -0x1.9f152046c7178p-7,
+ 0x1.26a2e0a31e9fp-10, -0x1.67436e13d44ddp-15},
+ {0x1.3628cccb902e9p-2, -0x1.1587e442957f9p-1, 0x1.aabedffc2818p-2,
+ -0x1.6d5f4f24a94a1p-3, 0x1.782f957586c48p-5, -0x1.d1b4c8cd3d9ap-8,
+ 0x1.40e4007f68b4dp-11, -0x1.7bb3eac541f35p-16},
+ {0x1.7e774f23dd5d8p-3, -0x1.4ce552c93ab17p-2, 0x1.f1ba61425c57ap-3,
+ -0x1.9e391990469f7p-4, 0x1.9e6adf17223b9p-6, -0x1.f2601fc8d5f7ep-9,
+ 0x1.4d7f6c4dab8cap-12, -0x1.7f24e1a9c9b8ap-17},
+ {0x1.c0bbabb6ec859p-4, -0x1.7bf5902ff3dfcp-3, 0x1.143e24f2802a6p-3,
+ -0x1.bf08869d7e41p-5, 0x1.b2b78fe704f97p-7, -0x1.fc05ca0a46accp-10,
+ 0x1.4a472fc484f8ap-13, -0x1.7091cb146f95ap-18},
+ };
+
+ using FPBits = typename fputil::FPBits<float16>;
+ FPBits xbits(x);
+ uint16_t x_abs = xbits.abs().uintval();
+
+ // Special cases: NaN and 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;
+ }
+ // erfc(+Inf) = 0, erfc(-Inf) = 2
+ return xbits.is_neg() ? static_cast<float16>(2.0)
+ : static_cast<float16>(0.0);
+ }
+
+ if (LIBC_UNLIKELY(x_abs == 0))
+ return 1.0f16;
+
+ // Asymptotic behavior: erfc(x) rounds to 0 or 2 for |x| >= 4.0.
+ if (LIBC_UNLIKELY(x_abs >= 0x4400U)) { // |x| >= 4.0
+ if (xbits.is_neg()) {
+ // 0x1.0p-12 is ~0.25 ULP of 2.0 in float16, small enough to round
+ // to 2.0 in RN, but large enough to round down in RD/RZ.
+ double xd = static_cast<double>(x);
+ return static_cast<float16>(2.0 - 0x1.0p-12 * (4.0 / -xd));
+ }
+ return 0.0f16;
+ }
+
+ // Polynomial approximation:
+ // erfc(x) ~ erfc(|x|) if x >= 0
+ // erfc(x) ~ 2 - erfc(|x|) if x < 0
+ // erfc(|x|) is evaluated using a degree-7 polynomial on each sub-interval.
+
+ float xf = static_cast<float>(xbits.abs().get_val());
+ int idx = static_cast<int>(xf * 8.0f);
+
+ double xd = static_cast<double>(xbits.abs().get_val());
+ double xsq = xd * xd;
+ double x4 = xsq * xsq;
+
+ double p01 = fputil::multiply_add(xd, COEFFS[idx][1], COEFFS[idx][0]);
+ double p23 = fputil::multiply_add(xd, COEFFS[idx][3], COEFFS[idx][2]);
+ double p45 = fputil::multiply_add(xd, COEFFS[idx][5], COEFFS[idx][4]);
+ double p67 = fputil::multiply_add(xd, COEFFS[idx][7], COEFFS[idx][6]);
+
+ double p03 = fputil::multiply_add(xsq, p23, p01);
+ double p47 = fputil::multiply_add(xsq, p67, p45);
+
+ double erfc_abs = fputil::multiply_add(x4, p47, p03);
+
+ if (xbits.is_neg())
+ return static_cast<float16>(2.0 - erfc_abs);
+
+ return static_cast<float16>(erfc_abs);
+}
+
+} // namespace math
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ERFCF16_H
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index e37e22fdb58e6..233a1afec55ef 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -136,6 +136,8 @@ add_math_entrypoint_object(dsubf128)
add_math_entrypoint_object(erf)
add_math_entrypoint_object(erff)
+add_math_entrypoint_object(erfcf16)
+
add_math_entrypoint_object(exp)
add_math_entrypoint_object(expf)
add_math_entrypoint_object(expf16)
diff --git a/libc/src/math/erfcf16.h b/libc/src/math/erfcf16.h
new file mode 100644
index 0000000000000..9f6f983e7000d
--- /dev/null
+++ b/libc/src/math/erfcf16.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for erfcf16 -----------------------*- 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_ERFCF16_H
+#define LLVM_LIBC_SRC_MATH_ERFCF16_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+float16 erfcf16(float16 x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_ERFCF16_H
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 1a3588a71219b..b9b921fb374a4 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -1358,6 +1358,17 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ erfcf16
+ SRCS
+ erfcf16.cpp
+ HDRS
+ ../erfcf16.h
+ DEPENDS
+ libc.src.__support.math.erfcf16
+ libc.src.errno.errno
+)
+
add_entrypoint_object(
exp
SRCS
diff --git a/libc/src/math/generic/erfcf16.cpp b/libc/src/math/generic/erfcf16.cpp
new file mode 100644
index 0000000000000..a1f7397c3b58c
--- /dev/null
+++ b/libc/src/math/generic/erfcf16.cpp
@@ -0,0 +1,16 @@
+//===-- Half-precision erfc(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/erfcf16.h"
+#include "src/__support/math/erfcf16.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(float16, erfcf16, (float16 x)) { return math::erfcf16(x); }
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index ff5c511922171..363ae42ed0a1e 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -2625,6 +2625,18 @@ add_fp_unittest(
libc.src.__support.FPUtil.fp_bits
)
+add_fp_unittest(
+ erfcf16_test
+ NEED_MPFR
+ SUITE
+ libc-math-unittests
+ SRCS
+ erfcf16_test.cpp
+ DEPENDS
+ libc.src.math.erfcf16
+ libc.src.__support.FPUtil.fp_bits
+)
+
add_fp_unittest(
pow_test
NEED_MPFR
diff --git a/libc/test/src/math/erfcf16_test.cpp b/libc/test/src/math/erfcf16_test.cpp
new file mode 100644
index 0000000000000..d06bca5dc23a6
--- /dev/null
+++ b/libc/test/src/math/erfcf16_test.cpp
@@ -0,0 +1,43 @@
+//===-- Exhaustive test for erfcf16 ---------------------------------------===//
+//
+// 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/erfcf16.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+using LlvmLibcErfcf16Test = 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(LlvmLibcErfcf16Test, PositiveRange) {
+ for (uint16_t v = POS_START; v <= POS_STOP; ++v) {
+ float16 x = FPBits(v).get_val();
+ EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Erfc, x,
+ LIBC_NAMESPACE::erfcf16(x), 0.5);
+ }
+}
+
+TEST_F(LlvmLibcErfcf16Test, NegativeRange) {
+ for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) {
+ float16 x = FPBits(v).get_val();
+ EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Erfc, x,
+ LIBC_NAMESPACE::erfcf16(x), 0.5);
+ }
+}
diff --git a/libc/test/src/math/smok...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/180930
More information about the libc-commits
mailing list