Project import generated by Copybara.
GitOrigin-RevId: b994299e59c9aac01ca0a494b2b861ebd5acc190
Change-Id: I0b7b67a51319af75213a1713a792a4cdc1006ce7
diff --git a/hdr/stdlib_overlay.h b/hdr/stdlib_overlay.h
index f095caf..53c32ec 100644
--- a/hdr/stdlib_overlay.h
+++ b/hdr/stdlib_overlay.h
@@ -19,6 +19,11 @@
// functions, causing external alias errors. They are guarded by
// `__USE_FORTIFY_LEVEL`, which will be temporarily disabled.
+#ifdef _FORTIFY_SOURCE
+#define LIBC_OLD_FORTIFY_SOURCE _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+
#ifdef __USE_FORTIFY_LEVEL
#define LIBC_OLD_USE_FORTIFY_LEVEL __USE_FORTIFY_LEVEL
#undef __USE_FORTIFY_LEVEL
@@ -27,6 +32,11 @@
#include <stdlib.h>
+#ifdef LIBC_OLD_FORTIFY_SOURCE
+#define _FORTIFY_SOURCE LIBC_OLD_FORTIFY_SOURCE
+#undef LIBC_OLD_FORTIFY_SOURCE
+#endif
+
#ifdef LIBC_OLD_USE_FORTIFY_LEVEL
#undef __USE_FORTIFY_LEVEL
#define __USE_FORTIFY_LEVEL LIBC_OLD_USE_FORTIFY_LEVEL
diff --git a/src/math/atanf16.h b/src/math/atanf16.h
new file mode 100644
index 0000000..96ae35c
--- /dev/null
+++ b/src/math/atanf16.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for atanf16 -----------------------*- 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_ATANF16_H
+#define LLVM_LIBC_SRC_MATH_ATANF16_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+float16 atanf16(float16 x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_ATANF16_H
diff --git a/src/math/generic/atanf16.cpp b/src/math/generic/atanf16.cpp
new file mode 100644
index 0000000..9b6ec65
--- /dev/null
+++ b/src/math/generic/atanf16.cpp
@@ -0,0 +1,107 @@
+//===-- Half-precision atanf16(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/atanf16.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/PolyEval.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/FPUtil/sqrt.h"
+#include "src/__support/macros/optimization.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// Generated by Solly using the following command:
+// > round(pi/2, SG, RN);
+static constexpr float PI_2 = 0x1.921fb6p0;
+
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+static constexpr size_t N_EXCEPTS = 6;
+
+static constexpr fputil::ExceptValues<float16, N_EXCEPTS> ATANF16_EXCEPTS{{
+ // (input, RZ output, RU offset, RD offset, RN offset)
+ {0x2745, 0x2744, 1, 0, 1},
+ {0x3099, 0x3090, 1, 0, 1},
+ {0x3c6c, 0x3aae, 1, 0, 1},
+ {0x466e, 0x3daa, 1, 0, 1},
+ {0x48ae, 0x3ddb, 1, 0, 0},
+ {0x5619, 0x3e3d, 1, 0, 1},
+}};
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+LLVM_LIBC_FUNCTION(float16, atanf16, (float16 x)) {
+ using FPBits = fputil::FPBits<float16>;
+ FPBits xbits(x);
+
+ uint16_t x_u = xbits.uintval();
+ uint16_t x_abs = x_u & 0x7fff;
+ bool x_sign = x_u >> 15;
+ float sign = (x_sign ? -1.0 : 1.0);
+
+ // |x| >= +/-inf
+ if (LIBC_UNLIKELY(x_abs >= 0x7c00)) {
+ if (xbits.is_nan()) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ return x;
+ }
+
+ // atanf16(+/-inf) = +/-pi/2
+ return fputil::cast<float16>(sign * PI_2);
+ }
+
+ float xf = x;
+ float xsq = xf * xf;
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ // Handle exceptional values
+ if (auto r = ATANF16_EXCEPTS.lookup_odd(x_abs, x_sign);
+ LIBC_UNLIKELY(r.has_value()))
+ return r.value();
+#endif
+
+ // |x| <= 0x1p0, |x| <= 1
+ if (x_abs <= 0x3c00) {
+ // atanf16(+/-0) = +/-0
+ if (LIBC_UNLIKELY(x_abs == 0))
+ return x;
+
+ // Degree-14 minimax odd polynomial of atan(x) generated by Sollya with:
+ // > P = fpminimax(atan(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14|], [|SG...|],
+ // [0, 1]);
+ float result = fputil::polyeval(
+ xsq, 0x1.fffffcp-1f, -0x1.55519ep-2f, 0x1.98f6a8p-3f, -0x1.1f0a92p-3f,
+ 0x1.95b654p-4f, -0x1.e65492p-5f, 0x1.8c0c36p-6f, -0x1.32316ep-8f);
+ return fputil::cast<float16>(xf * result);
+ }
+
+ // If |x| > 1
+ // y = atan(x) = sign(x) * atan(|x|)
+ // atan(|x|) = pi/2 - atan(1/|x|)
+ // Recall, 1/|x| < 1
+ float x_inv_sq = 1.0f / xsq;
+ float x_inv = fputil::sqrt<float>(x_inv_sq);
+
+ // Degree-14 minimax odd polynomial of atan(x) generated by Sollya with:
+ // > P = fpminimax(atan(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14|], [|SG...|],
+ // [0, 1]);
+ float interm =
+ fputil::polyeval(x_inv_sq, 0x1.fffffcp-1f, -0x1.55519ep-2f,
+ 0x1.98f6a8p-3f, -0x1.1f0a92p-3f, 0x1.95b654p-4f,
+ -0x1.e65492p-5f, 0x1.8c0c36p-6f, -0x1.32316ep-8f);
+
+ return fputil::cast<float16>(sign *
+ fputil::multiply_add(x_inv, -interm, PI_2));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/src/wchar/wcscat.cpp b/src/wchar/wcscat.cpp
new file mode 100644
index 0000000..50d90c0
--- /dev/null
+++ b/src/wchar/wcscat.cpp
@@ -0,0 +1,29 @@
+//===-- Implementation of wcscat ------------------------------------------===//
+//
+// 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/wchar/wcscat.h"
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/string/string_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(wchar_t *, wcscat,
+ (wchar_t *__restrict s1, const wchar_t *__restrict s2)) {
+ size_t size_1 = internal::string_length(s1);
+ size_t i = 0;
+ for (; s2[i] != L'\0'; i++)
+ s1[size_1 + i] = s2[i];
+ s1[size_1 + i] = L'\0';
+ return s1;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/src/wchar/wcscat.h b/src/wchar/wcscat.h
new file mode 100644
index 0000000..b0b4455
--- /dev/null
+++ b/src/wchar/wcscat.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for wcscat ----------------------------------===//
+//
+// 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_WCHAR_WCSCAT_H
+#define LLVM_LIBC_SRC_WCHAR_WCSCAT_H
+
+#include "hdr/types/wchar_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+wchar_t *wcscat(wchar_t *__restrict s1, const wchar_t *__restrict s2);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCHAR_WCSCAT_H
diff --git a/src/wchar/wcscmp.cpp b/src/wchar/wcscmp.cpp
new file mode 100644
index 0000000..f285efd
--- /dev/null
+++ b/src/wchar/wcscmp.cpp
@@ -0,0 +1,30 @@
+//===-- Implementation of wcscmp ------------------------------------------===//
+//
+// 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/wchar/wcscmp.h"
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/null_check.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, wcscmp, (const wchar_t *left, const wchar_t *right)) {
+ LIBC_CRASH_ON_NULLPTR(left);
+ LIBC_CRASH_ON_NULLPTR(right);
+
+ auto comp = [](wchar_t l, wchar_t r) -> int { return l - r; };
+
+ for (; *left && !comp(*left, *right); ++left, ++right)
+ ;
+
+ return comp(*left, *right);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/src/wchar/wcscmp.h b/src/wchar/wcscmp.h
new file mode 100644
index 0000000..af82d06
--- /dev/null
+++ b/src/wchar/wcscmp.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for wcscmp ----------------------------------===//
+//
+// 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_WCHAR_WCSCMP_H
+#define LLVM_LIBC_SRC_WCHAR_WCSCMP_H
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int wcscmp(const wchar_t *left, const wchar_t *right);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCHAR_WCSCMP_H
diff --git a/src/wchar/wcscpy.cpp b/src/wchar/wcscpy.cpp
new file mode 100644
index 0000000..dc46b972
--- /dev/null
+++ b/src/wchar/wcscpy.cpp
@@ -0,0 +1,27 @@
+//===-- Implementation of wcscpy ------------------------------------------===//
+//
+// 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/wchar/wcscpy.h"
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/string/memory_utils/inline_memcpy.h"
+#include "src/string/string_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(wchar_t *, wcscpy,
+ (wchar_t *__restrict s1, const wchar_t *__restrict s2)) {
+ size_t size = internal::string_length(s2) + 1;
+ inline_memcpy(s1, s2, size * sizeof(wchar_t));
+ return s1;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/src/wchar/wcscpy.h b/src/wchar/wcscpy.h
new file mode 100644
index 0000000..c3f0e5f
--- /dev/null
+++ b/src/wchar/wcscpy.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for wcscpy ----------------------------------===//
+//
+// 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_WCHAR_WCSCPY_H
+#define LLVM_LIBC_SRC_WCHAR_WCSCPY_H
+
+#include "hdr/types/wchar_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+wchar_t *wcscpy(wchar_t *__restrict s1, const wchar_t *__restrict s2);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCHAR_WCSCPY_H
diff --git a/src/wchar/wcsncat.cpp b/src/wchar/wcsncat.cpp
new file mode 100644
index 0000000..62595b4
--- /dev/null
+++ b/src/wchar/wcsncat.cpp
@@ -0,0 +1,31 @@
+//===-- Implementation of wcsncat -----------------------------------------===//
+//
+// 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/wchar/wcsncat.h"
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/string/string_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(wchar_t *, wcsncat,
+ (wchar_t *__restrict s1, const wchar_t *__restrict s2,
+ size_t n)) {
+ size_t size = internal::string_length(s1);
+ size_t i = 0;
+ for (; s2[i] && i < n; ++i)
+ s1[size + i] = s2[i];
+ // Appending null character to the end of the result.
+ s1[size + i] = L'\0';
+ return s1;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/src/wchar/wcsncat.h b/src/wchar/wcsncat.h
new file mode 100644
index 0000000..978645e
--- /dev/null
+++ b/src/wchar/wcsncat.h
@@ -0,0 +1,23 @@
+//===-- Implementation header for wcsncat ---------------------------------===//
+//
+// 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_WCHAR_WCSNCAT_H
+#define LLVM_LIBC_SRC_WCHAR_WCSNCAT_H
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+wchar_t *wcsncat(wchar_t *__restrict s1, const wchar_t *__restrict s2,
+ size_t n);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCHAR_WCSNCAT_H
diff --git a/src/wchar/wcsncmp.cpp b/src/wchar/wcsncmp.cpp
new file mode 100644
index 0000000..f2e052b
--- /dev/null
+++ b/src/wchar/wcsncmp.cpp
@@ -0,0 +1,37 @@
+//===-- Implementation of wcsncmp -----------------------------------------===//
+//
+// 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/wchar/wcsncmp.h"
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/null_check.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, wcsncmp,
+ (const wchar_t *left, const wchar_t *right, size_t n)) {
+ LIBC_CRASH_ON_NULLPTR(left);
+ LIBC_CRASH_ON_NULLPTR(right);
+
+ if (n == 0)
+ return 0;
+
+ auto comp = [](wchar_t l, wchar_t r) -> int { return l - r; };
+
+ for (; n > 1; --n, ++left, ++right) {
+ wchar_t lc = *left;
+ if (!comp(lc, '\0') || comp(lc, *right))
+ break;
+ }
+ return comp(*reinterpret_cast<const wchar_t *>(left),
+ *reinterpret_cast<const wchar_t *>(right));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/src/wchar/wcsncmp.h b/src/wchar/wcsncmp.h
new file mode 100644
index 0000000..0b4187e73
--- /dev/null
+++ b/src/wchar/wcsncmp.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for wcsncmp ---------------------------------===//
+//
+// 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_WCHAR_WCSNCMP_H
+#define LLVM_LIBC_SRC_WCHAR_WCSNCMP_H
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int wcsncmp(const wchar_t *left, const wchar_t *right, size_t n);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCHAR_WCSNCMP_H
diff --git a/src/wchar/wcspbrk.cpp b/src/wchar/wcspbrk.cpp
index bf305a5..a00ba99 100644
--- a/src/wchar/wcspbrk.cpp
+++ b/src/wchar/wcspbrk.cpp
@@ -10,6 +10,7 @@
#include "hdr/types/wchar_t.h"
#include "src/__support/common.h"
+#include "src/__support/macros/null_check.h"
namespace LIBC_NAMESPACE_DECL {
@@ -23,6 +24,9 @@
LLVM_LIBC_FUNCTION(const wchar_t *, wcspbrk,
(const wchar_t *src, const wchar_t *breakset)) {
+ LIBC_CRASH_ON_NULLPTR(src);
+ LIBC_CRASH_ON_NULLPTR(breakset);
+
// currently O(n * m), can be further optimized to O(n + m) with a hash set
for (int src_idx = 0; src[src_idx] != 0; src_idx++)
if (contains_char(breakset, src[src_idx]))
diff --git a/src/wchar/wcsrchr.cpp b/src/wchar/wcsrchr.cpp
new file mode 100644
index 0000000..bb4e373
--- /dev/null
+++ b/src/wchar/wcsrchr.cpp
@@ -0,0 +1,31 @@
+//===-- Implementation of wcsrchr -----------------------------------------===//
+//
+// 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/wchar/wcsrchr.h"
+
+#include "hdr/types/wchar_t.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(const wchar_t *, wcsrchr, (const wchar_t *s, wchar_t c)) {
+ LIBC_CRASH_ON_NULLPTR(s);
+
+ const wchar_t *last_occurrence = nullptr;
+ while (true) {
+ if (*s == c)
+ last_occurrence = s;
+ if (*s == L'\0')
+ return last_occurrence;
+ ++s;
+ }
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/src/wchar/wcsrchr.h b/src/wchar/wcsrchr.h
new file mode 100644
index 0000000..5e9d8c3
--- /dev/null
+++ b/src/wchar/wcsrchr.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for wcsrchr ---------------------------------===//
+//
+// 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_WCHAR_WCSRCHR_H
+#define LLVM_LIBC_SRC_WCHAR_WCSRCHR_H
+
+#include "hdr/types/wchar_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+const wchar_t *wcsrchr(const wchar_t *s, wchar_t c);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCHAR_WCSRCHR_H
diff --git a/src/wchar/wcsstr.cpp b/src/wchar/wcsstr.cpp
new file mode 100644
index 0000000..961835a
--- /dev/null
+++ b/src/wchar/wcsstr.cpp
@@ -0,0 +1,38 @@
+//===-- Implementation of wcsstr ------------------------------------------===//
+//
+// 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/wchar/wcsstr.h"
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/string/string_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(const wchar_t *, wcsstr,
+ (const wchar_t *s1, const wchar_t *s2)) {
+ size_t s1_len = internal::string_length(s1);
+ size_t s2_len = internal::string_length(s2);
+ if (s2_len == 0)
+ return s1;
+ if (s2_len > s1_len)
+ return nullptr;
+ for (size_t i = 0; i <= (s1_len - s2_len); ++i) {
+ size_t j = 0;
+ // j will increment until the characters don't match or end of string.
+ for (; j < s2_len && s1[i + j] == s2[j]; ++j)
+ ;
+ if (j == s2_len)
+ return (s1 + i);
+ }
+ return nullptr;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/src/wchar/wcsstr.h b/src/wchar/wcsstr.h
new file mode 100644
index 0000000..af054d8
--- /dev/null
+++ b/src/wchar/wcsstr.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for wcsstr ----------------------------------===//
+//
+// 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_WCHAR_WCSSTR_H
+#define LLVM_LIBC_SRC_WCHAR_WCSSTR_H
+
+#include "hdr/types/wchar_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+const wchar_t *wcsstr(const wchar_t *s1, const wchar_t *s2);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCHAR_WCSSTR_H
diff --git a/src/wchar/wmempcpy.cpp b/src/wchar/wmempcpy.cpp
new file mode 100644
index 0000000..d8b89c0
--- /dev/null
+++ b/src/wchar/wmempcpy.cpp
@@ -0,0 +1,25 @@
+//===-- Implementation of wmempcpy ----------------------------------------===//
+//
+// 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/wchar/wmempcpy.h"
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/common.h"
+#include "src/string/memory_utils/inline_memcpy.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(wchar_t *, wmempcpy,
+ (wchar_t *__restrict to, const wchar_t *__restrict from,
+ size_t size)) {
+ inline_memcpy(to, from, size * sizeof(wchar_t));
+ return reinterpret_cast<wchar_t *>(to) + size;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/src/wchar/wmempcpy.h b/src/wchar/wmempcpy.h
new file mode 100644
index 0000000..580674b
--- /dev/null
+++ b/src/wchar/wmempcpy.h
@@ -0,0 +1,23 @@
+//===-- Implementation header for wmempcpy---------------------------------===//
+//
+// 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_WCHAR_WMEMPCPY_H
+#define LLVM_LIBC_SRC_WCHAR_WMEMPCPY_H
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/wchar_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+wchar_t *wmempcpy(wchar_t *__restrict from, const wchar_t *__restrict s2,
+ size_t n);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCHAR_WMEMPCPY_H
diff --git a/test/src/math/atanf16_test.cpp b/test/src/math/atanf16_test.cpp
new file mode 100644
index 0000000..fa383e7
--- /dev/null
+++ b/test/src/math/atanf16_test.cpp
@@ -0,0 +1,40 @@
+//===-- Exhaustive test for atanf16 ---------------------------------------===//
+//
+// 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/atanf16.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+using LlvmLibcAtanf16Test = LIBC_NAMESPACE::testing::FPTest<float16>;
+
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
+
+// Range: [0, Inf]
+static constexpr uint16_t POS_START = 0x0000U;
+static constexpr uint16_t POS_STOP = 0x7c00U;
+
+// Range: [-Inf, 0]
+static constexpr uint16_t NEG_START = 0x8000U;
+static constexpr uint16_t NEG_STOP = 0xfc00U;
+
+TEST_F(LlvmLibcAtanf16Test, PositiveRange) {
+ for (uint16_t v = POS_START; v <= POS_STOP; ++v) {
+ float16 x = FPBits(v).get_val();
+ EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Atan, x,
+ LIBC_NAMESPACE::atanf16(x), 0.5);
+ }
+}
+
+TEST_F(LlvmLibcAtanf16Test, NegativeRange) {
+ for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) {
+ float16 x = FPBits(v).get_val();
+ EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Atan, x,
+ LIBC_NAMESPACE::atanf16(x), 0.5);
+ }
+}
diff --git a/test/src/math/smoke/atanf16_test.cpp b/test/src/math/smoke/atanf16_test.cpp
new file mode 100644
index 0000000..af50287
--- /dev/null
+++ b/test/src/math/smoke/atanf16_test.cpp
@@ -0,0 +1,35 @@
+//===-- Unittests for atanf16 ---------------------------------------------===//
+//
+// 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/errno/libc_errno.h"
+#include "src/math/atanf16.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using LlvmLibcAtanf16Test = LIBC_NAMESPACE::testing::FPTest<float16>;
+
+TEST_F(LlvmLibcAtanf16Test, SpecialNumbers) {
+ LIBC_NAMESPACE::libc_errno = 0;
+ EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::atanf16(aNaN));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::atanf16(sNaN), FE_INVALID);
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ(zero, LIBC_NAMESPACE::atanf16(zero));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ(neg_zero, LIBC_NAMESPACE::atanf16(neg_zero));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ(0x1.92p0, LIBC_NAMESPACE::atanf16(inf));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ(-0x1.92p0, LIBC_NAMESPACE::atanf16(neg_inf));
+ EXPECT_MATH_ERRNO(0);
+}
diff --git a/test/src/wchar/wcscat_test.cpp b/test/src/wchar/wcscat_test.cpp
new file mode 100644
index 0000000..e91f796
--- /dev/null
+++ b/test/src/wchar/wcscat_test.cpp
@@ -0,0 +1,47 @@
+//===-- Unittests for wcscat ---------------------------------------------===//
+//
+// 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/types/wchar_t.h"
+#include "src/wchar/wcscat.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcWCSCatTest, EmptyDest) {
+ // Dest should be fully replaced with src.
+ wchar_t dest[4] = {L'\0'};
+ const wchar_t *src = L"abc";
+ LIBC_NAMESPACE::wcscat(dest, src);
+ ASSERT_TRUE(dest[0] == L'a');
+ ASSERT_TRUE(dest[1] == L'b');
+ ASSERT_TRUE(dest[2] == L'c');
+ ASSERT_TRUE(dest[3] == L'\0');
+}
+
+TEST(LlvmLibcWCSCatTest, NonEmptyDest) {
+ // Src should be appended on to dest.
+ wchar_t dest[7] = {L'x', L'y', L'z', L'\0'};
+ const wchar_t *src = L"abc";
+ LIBC_NAMESPACE::wcscat(dest, src);
+ ASSERT_TRUE(dest[0] == L'x');
+ ASSERT_TRUE(dest[1] == L'y');
+ ASSERT_TRUE(dest[2] == L'z');
+ ASSERT_TRUE(dest[3] == L'a');
+ ASSERT_TRUE(dest[4] == L'b');
+ ASSERT_TRUE(dest[5] == L'c');
+ ASSERT_TRUE(dest[6] == L'\0');
+}
+
+TEST(LlvmLibcWCSCatTest, EmptySrc) {
+ // Dest should remain intact.
+ wchar_t dest[4] = {L'x', L'y', L'z', L'\0'};
+ const wchar_t *src = L"";
+ LIBC_NAMESPACE::wcscat(dest, src);
+ ASSERT_TRUE(dest[0] == L'x');
+ ASSERT_TRUE(dest[1] == L'y');
+ ASSERT_TRUE(dest[2] == L'z');
+ ASSERT_TRUE(dest[3] == L'\0');
+}
diff --git a/test/src/wchar/wcscmp_test.cpp b/test/src/wchar/wcscmp_test.cpp
new file mode 100644
index 0000000..6572aad
--- /dev/null
+++ b/test/src/wchar/wcscmp_test.cpp
@@ -0,0 +1,97 @@
+//===-- Unittests for wcscmp ----------------------------------------------===//
+//
+// 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/wchar/wcscmp.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcWcscmpTest, EmptyStringsShouldReturnZero) {
+ const wchar_t *s1 = L"";
+ const wchar_t *s2 = L"";
+ int result = LIBC_NAMESPACE::wcscmp(s1, s2);
+ ASSERT_EQ(result, 0);
+
+ // Verify operands reversed.
+ result = LIBC_NAMESPACE::wcscmp(s2, s1);
+ ASSERT_EQ(result, 0);
+}
+
+TEST(LlvmLibcWcscmpTest, EmptyStringShouldNotEqualNonEmptyString) {
+ const wchar_t *empty = L"";
+ const wchar_t *s2 = L"abc";
+ int result = LIBC_NAMESPACE::wcscmp(empty, s2);
+ ASSERT_LT(result, 0);
+
+ // Similar case if empty string is second argument.
+ const wchar_t *s3 = L"123";
+ result = LIBC_NAMESPACE::wcscmp(s3, empty);
+ ASSERT_GT(result, 0);
+}
+
+TEST(LlvmLibcWcscmpTest, EqualStringsShouldReturnZero) {
+ const wchar_t *s1 = L"abc";
+ const wchar_t *s2 = L"abc";
+ int result = LIBC_NAMESPACE::wcscmp(s1, s2);
+ ASSERT_EQ(result, 0);
+
+ // Verify operands reversed.
+ result = LIBC_NAMESPACE::wcscmp(s2, s1);
+ ASSERT_EQ(result, 0);
+}
+
+TEST(LlvmLibcWcscmpTest, ShouldReturnResultOfFirstDifference) {
+ const wchar_t *s1 = L"___B42__";
+ const wchar_t *s2 = L"___C55__";
+ int result = LIBC_NAMESPACE::wcscmp(s1, s2);
+ ASSERT_LT(result, 0);
+
+ // Verify operands reversed.
+ result = LIBC_NAMESPACE::wcscmp(s2, s1);
+ ASSERT_GT(result, 0);
+}
+
+TEST(LlvmLibcWcscmpTest, CapitalizedLetterShouldNotBeEqual) {
+ const wchar_t *s1 = L"abcd";
+ const wchar_t *s2 = L"abCd";
+ int result = LIBC_NAMESPACE::wcscmp(s1, s2);
+ ASSERT_GT(result, 0);
+
+ // Verify operands reversed.
+ result = LIBC_NAMESPACE::wcscmp(s2, s1);
+ ASSERT_LT(result, 0);
+}
+
+TEST(LlvmLibcWcscmpTest, UnequalLengthStringsShouldNotReturnZero) {
+ const wchar_t *s1 = L"abc";
+ const wchar_t *s2 = L"abcd";
+ int result = LIBC_NAMESPACE::wcscmp(s1, s2);
+ ASSERT_LT(result, 0);
+
+ // Verify operands reversed.
+ result = LIBC_NAMESPACE::wcscmp(s2, s1);
+ ASSERT_GT(result, 0);
+}
+
+TEST(LlvmLibcWcscmpTest, StringArgumentSwapChangesSign) {
+ const wchar_t *a = L"a";
+ const wchar_t *b = L"b";
+ int result = LIBC_NAMESPACE::wcscmp(b, a);
+ ASSERT_GT(result, 0);
+
+ result = LIBC_NAMESPACE::wcscmp(a, b);
+ ASSERT_LT(result, 0);
+}
+
+#if defined(LIBC_ADD_NULL_CHECKS) && !defined(LIBC_HAS_SANITIZER)
+TEST(LlvmLibcWcscmpTest, NullptrCrash) {
+ // Passing in a nullptr should crash the program.
+ EXPECT_DEATH([] { LIBC_NAMESPACE::wcscmp(L"aaaaaaaaaaaaaa", nullptr); },
+ WITH_SIGNAL(-1));
+ EXPECT_DEATH([] { LIBC_NAMESPACE::wcscmp(nullptr, L"aaaaaaaaaaaaaa"); },
+ WITH_SIGNAL(-1));
+}
+#endif // LIBC_HAS_ADDRESS_SANITIZER
diff --git a/test/src/wchar/wcscpy_test.cpp b/test/src/wchar/wcscpy_test.cpp
new file mode 100644
index 0000000..7b71b2b
--- /dev/null
+++ b/test/src/wchar/wcscpy_test.cpp
@@ -0,0 +1,48 @@
+//===-- Unittests for wcscpy ---------------------------------------------===//
+//
+// 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/types/wchar_t.h"
+#include "src/wchar/wcscpy.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcWCSCpyTest, EmptySrc) {
+ // Empty src should lead to empty destination.
+ wchar_t dest[4] = {L'a', L'b', L'c', L'\0'};
+ const wchar_t *src = L"";
+ LIBC_NAMESPACE::wcscpy(dest, src);
+ ASSERT_TRUE(dest[0] == src[0]);
+ ASSERT_TRUE(dest[0] == L'\0');
+}
+
+TEST(LlvmLibcWCSCpyTest, EmptyDest) {
+ // Empty dest should result in src
+ const wchar_t *src = L"abc";
+ wchar_t dest[4];
+ LIBC_NAMESPACE::wcscpy(dest, src);
+ ASSERT_TRUE(dest[0] == L'a');
+ ASSERT_TRUE(dest[1] == L'b');
+ ASSERT_TRUE(dest[2] == L'c');
+ ASSERT_TRUE(dest[3] == L'\0');
+}
+
+TEST(LlvmLibcWCSCpyTest, OffsetDest) {
+ // Offsetting should result in a concatenation.
+ const wchar_t *src = L"abc";
+ wchar_t dest[7];
+ dest[0] = L'x';
+ dest[1] = L'y';
+ dest[2] = L'z';
+ LIBC_NAMESPACE::wcscpy(dest + 3, src);
+ ASSERT_TRUE(dest[0] == L'x');
+ ASSERT_TRUE(dest[1] == L'y');
+ ASSERT_TRUE(dest[2] == L'z');
+ ASSERT_TRUE(dest[3] == src[0]);
+ ASSERT_TRUE(dest[4] == src[1]);
+ ASSERT_TRUE(dest[5] == src[2]);
+ ASSERT_TRUE(dest[6] == src[3]);
+}
diff --git a/test/src/wchar/wcsncat_test.cpp b/test/src/wchar/wcsncat_test.cpp
new file mode 100644
index 0000000..47359f8
--- /dev/null
+++ b/test/src/wchar/wcsncat_test.cpp
@@ -0,0 +1,82 @@
+//===-- Unittests for wcscat ---------------------------------------------===//
+//
+// 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/types/wchar_t.h"
+#include "src/wchar/wcsncat.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcWCSNCatTest, EmptyDest) {
+ wchar_t dest[4] = {L'\0'};
+ const wchar_t *src = L"abc";
+
+ // Start by copying nothing
+ LIBC_NAMESPACE::wcsncat(dest, src, 0);
+ ASSERT_TRUE(dest[0] == L'\0');
+
+ // Copying part of it.
+ LIBC_NAMESPACE::wcsncat(dest, src, 1);
+ ASSERT_TRUE(dest[0] == L'a');
+ ASSERT_TRUE(dest[1] == L'\0');
+
+ // Resetting for the last test.
+ dest[0] = '\0';
+
+ // Copying all of it.
+ LIBC_NAMESPACE::wcsncat(dest, src, 3);
+ ASSERT_TRUE(dest[0] == L'a');
+ ASSERT_TRUE(dest[1] == L'b');
+ ASSERT_TRUE(dest[2] == L'c');
+ ASSERT_TRUE(dest[3] == L'\0');
+}
+
+TEST(LlvmLibcWCSNCatTest, NonEmptyDest) {
+ wchar_t dest[7] = {L'x', L'y', L'z', L'\0'};
+ const wchar_t *src = L"abc";
+
+ // Adding on only part of the string
+ LIBC_NAMESPACE::wcsncat(dest, src, 1);
+ ASSERT_TRUE(dest[0] == L'x');
+ ASSERT_TRUE(dest[1] == L'y');
+ ASSERT_TRUE(dest[2] == L'z');
+ ASSERT_TRUE(dest[3] == L'a');
+ ASSERT_TRUE(dest[4] == L'\0');
+
+ // Copying more without resetting
+ LIBC_NAMESPACE::wcsncat(dest, src, 2);
+ ASSERT_TRUE(dest[0] == L'x');
+ ASSERT_TRUE(dest[1] == L'y');
+ ASSERT_TRUE(dest[2] == L'z');
+ ASSERT_TRUE(dest[3] == L'a');
+ ASSERT_TRUE(dest[4] == L'a');
+ ASSERT_TRUE(dest[5] == L'b');
+ ASSERT_TRUE(dest[6] == L'\0');
+
+ // Setting end marker to make sure it overwrites properly.
+ dest[3] = L'\0';
+
+ // Copying all of it.
+ LIBC_NAMESPACE::wcsncat(dest, src, 3);
+ ASSERT_TRUE(dest[0] == L'x');
+ ASSERT_TRUE(dest[1] == L'y');
+ ASSERT_TRUE(dest[2] == L'z');
+ ASSERT_TRUE(dest[3] == L'a');
+ ASSERT_TRUE(dest[4] == L'b');
+ ASSERT_TRUE(dest[5] == L'c');
+ ASSERT_TRUE(dest[6] == L'\0');
+
+ // Check that copying still works when count > src length.
+ dest[0] = L'\0';
+ // And that it doesn't write beyond what is necessary.
+ dest[4] = L'Z';
+ LIBC_NAMESPACE::wcsncat(dest, src, 4);
+ ASSERT_TRUE(dest[0] == L'a');
+ ASSERT_TRUE(dest[1] == L'b');
+ ASSERT_TRUE(dest[2] == L'c');
+ ASSERT_TRUE(dest[3] == L'\0');
+ ASSERT_TRUE(dest[4] == L'Z');
+}
diff --git a/test/src/wchar/wcsncmp_test.cpp b/test/src/wchar/wcsncmp_test.cpp
new file mode 100644
index 0000000..28bbb52
--- /dev/null
+++ b/test/src/wchar/wcsncmp_test.cpp
@@ -0,0 +1,169 @@
+//===-- Unittests for wcsncmp ---------------------------------------------===//
+//
+// 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/wchar/wcsncmp.h"
+#include "test/UnitTest/Test.h"
+
+// This group is just copies of the wcscmp tests, since all the same cases still
+// need to be tested.
+
+TEST(LlvmLibcWcsncmpTest, EmptyStringsShouldReturnZeroWithSufficientLength) {
+ const wchar_t *s1 = L"";
+ const wchar_t *s2 = L"";
+ int result = LIBC_NAMESPACE::wcsncmp(s1, s2, 1);
+ ASSERT_EQ(result, 0);
+
+ // Verify operands reversed.
+ result = LIBC_NAMESPACE::wcsncmp(s2, s1, 1);
+ ASSERT_EQ(result, 0);
+}
+
+TEST(LlvmLibcWcsncmpTest,
+ EmptyStringShouldNotEqualNonEmptyStringWithSufficientLength) {
+ const wchar_t *empty = L"";
+ const wchar_t *s2 = L"abc";
+ int result = LIBC_NAMESPACE::wcsncmp(empty, s2, 3);
+ ASSERT_LT(result, 0);
+
+ // Similar case if empty string is second argument.
+ const wchar_t *s3 = L"123";
+ result = LIBC_NAMESPACE::wcsncmp(s3, empty, 3);
+ ASSERT_GT(result, 0);
+}
+
+TEST(LlvmLibcWcsncmpTest, EqualStringsShouldReturnZeroWithSufficientLength) {
+ const wchar_t *s1 = L"abc";
+ const wchar_t *s2 = L"abc";
+ int result = LIBC_NAMESPACE::wcsncmp(s1, s2, 3);
+ ASSERT_EQ(result, 0);
+
+ // Verify operands reversed.
+ result = LIBC_NAMESPACE::wcsncmp(s2, s1, 3);
+ ASSERT_EQ(result, 0);
+}
+
+TEST(LlvmLibcWcsncmpTest,
+ ShouldReturnResultOfFirstDifferenceWithSufficientLength) {
+ const wchar_t *s1 = L"___B42__";
+ const wchar_t *s2 = L"___C55__";
+ int result = LIBC_NAMESPACE::wcsncmp(s1, s2, 8);
+ ASSERT_LT(result, 0);
+
+ // Verify operands reversed.
+ result = LIBC_NAMESPACE::wcsncmp(s2, s1, 8);
+ ASSERT_GT(result, 0);
+}
+
+TEST(LlvmLibcWcsncmpTest,
+ CapitalizedLetterShouldNotBeEqualWithSufficientLength) {
+ const wchar_t *s1 = L"abcd";
+ const wchar_t *s2 = L"abCd";
+ int result = LIBC_NAMESPACE::wcsncmp(s1, s2, 4);
+ ASSERT_GT(result, 0);
+
+ // Verify operands reversed.
+ result = LIBC_NAMESPACE::wcsncmp(s2, s1, 4);
+ ASSERT_LT(result, 0);
+}
+
+TEST(LlvmLibcWcsncmpTest,
+ UnequalLengthStringsShouldNotReturnZeroWithSufficientLength) {
+ const wchar_t *s1 = L"abc";
+ const wchar_t *s2 = L"abcd";
+ int result = LIBC_NAMESPACE::wcsncmp(s1, s2, 4);
+ ASSERT_LT(result, 0);
+
+ // Verify operands reversed.
+ result = LIBC_NAMESPACE::wcsncmp(s2, s1, 4);
+ ASSERT_GT(result, 0);
+}
+
+TEST(LlvmLibcWcsncmpTest, StringArgumentSwapChangesSignWithSufficientLength) {
+ const wchar_t *a = L"a";
+ const wchar_t *b = L"b";
+ int result = LIBC_NAMESPACE::wcsncmp(b, a, 1);
+ ASSERT_GT(result, 0);
+
+ result = LIBC_NAMESPACE::wcsncmp(a, b, 1);
+ ASSERT_LT(result, 0);
+}
+
+#if defined(LIBC_ADD_NULL_CHECKS) && !defined(LIBC_HAS_SANITIZER)
+TEST(LlvmLibcWcsncmpTest, NullptrCrash) {
+ // Passing in a nullptr should crash the program.
+ EXPECT_DEATH([] { LIBC_NAMESPACE::wcsncmp(L"aaaaaaaaaaaaaa", nullptr, 3); },
+ WITH_SIGNAL(-1));
+ EXPECT_DEATH([] { LIBC_NAMESPACE::wcsncmp(nullptr, L"aaaaaaaaaaaaaa", 3); },
+ WITH_SIGNAL(-1));
+}
+#endif // LIBC_HAS_ADDRESS_SANITIZER
+
+// This group is actually testing wcsncmp functionality
+
+TEST(LlvmLibcWcsncmpTest, NonEqualStringsEqualWithLengthZero) {
+ const wchar_t *s1 = L"abc";
+ const wchar_t *s2 = L"def";
+ int result = LIBC_NAMESPACE::wcsncmp(s1, s2, 0);
+ ASSERT_EQ(result, 0);
+
+ // Verify operands reversed.
+ result = LIBC_NAMESPACE::wcsncmp(s2, s1, 0);
+ ASSERT_EQ(result, 0);
+}
+
+TEST(LlvmLibcWcsncmpTest, NonEqualStringsNotEqualWithLengthOne) {
+ const wchar_t *s1 = L"abc";
+ const wchar_t *s2 = L"def";
+ int result = LIBC_NAMESPACE::wcsncmp(s1, s2, 1);
+ ASSERT_LT(result, 0);
+
+ // Verify operands reversed.
+ result = LIBC_NAMESPACE::wcsncmp(s2, s1, 1);
+ ASSERT_GT(result, 0);
+}
+
+TEST(LlvmLibcWcsncmpTest, NonEqualStringsEqualWithShorterLength) {
+ const wchar_t *s1 = L"___B42__";
+ const wchar_t *s2 = L"___C55__";
+ int result = LIBC_NAMESPACE::wcsncmp(s1, s2, 3);
+ ASSERT_EQ(result, 0);
+
+ // This should return 'B' - 'C' = -1.
+ result = LIBC_NAMESPACE::wcsncmp(s1, s2, 4);
+ ASSERT_LT(result, 0);
+
+ // Verify operands reversed.
+ result = LIBC_NAMESPACE::wcsncmp(s2, s1, 3);
+ ASSERT_EQ(result, 0);
+
+ // This should return 'C' - 'B' = 1.
+ result = LIBC_NAMESPACE::wcsncmp(s2, s1, 4);
+ ASSERT_GT(result, 0);
+}
+
+TEST(LlvmLibcWcsncmpTest, StringComparisonEndsOnNullByteEvenWithLongerLength) {
+ const wchar_t *s1 = L"abc\0def";
+ const wchar_t *s2 = L"abc\0abc";
+ int result = LIBC_NAMESPACE::wcsncmp(s1, s2, 7);
+ ASSERT_EQ(result, 0);
+
+ // Verify operands reversed.
+ result = LIBC_NAMESPACE::wcsncmp(s2, s1, 7);
+ ASSERT_EQ(result, 0);
+}
+
+TEST(LlvmLibcWcsncmpTest, Case) {
+ const wchar_t *s1 = L"aB";
+ const wchar_t *s2 = L"ab";
+ int result = LIBC_NAMESPACE::wcsncmp(s1, s2, 2);
+ ASSERT_LT(result, 0);
+
+ // Verify operands reversed.
+ result = LIBC_NAMESPACE::wcsncmp(s2, s1, 2);
+ ASSERT_GT(result, 0);
+}
diff --git a/test/src/wchar/wcspbrk_test.cpp b/test/src/wchar/wcspbrk_test.cpp
index f7754c0..bca9bff 100644
--- a/test/src/wchar/wcspbrk_test.cpp
+++ b/test/src/wchar/wcspbrk_test.cpp
@@ -60,3 +60,13 @@
EXPECT_EQ(LIBC_NAMESPACE::wcspbrk(src, L"34"), src + 2);
EXPECT_EQ(LIBC_NAMESPACE::wcspbrk(src, L"43"), src + 2);
}
+
+#if defined(LIBC_ADD_NULL_CHECKS) && !defined(LIBC_HAS_SANITIZER)
+TEST(LlvmLibcWCSPBrkTest, NullptrCrash) {
+ // Passing in a nullptr should crash the program.
+ EXPECT_DEATH([] { LIBC_NAMESPACE::wcspbrk(L"aaaaaaaaaaaaaa", nullptr); },
+ WITH_SIGNAL(-1));
+ EXPECT_DEATH([] { LIBC_NAMESPACE::wcspbrk(nullptr, L"aaaaaaaaaaaaaa"); },
+ WITH_SIGNAL(-1));
+}
+#endif // LIBC_HAS_ADDRESS_SANITIZER
diff --git a/test/src/wchar/wcsrchr_test.cpp b/test/src/wchar/wcsrchr_test.cpp
new file mode 100644
index 0000000..707dfb6
--- /dev/null
+++ b/test/src/wchar/wcsrchr_test.cpp
@@ -0,0 +1,68 @@
+//===-- Unittests for wcsrchr ---------------------------------------------===//
+//
+// 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/types/wchar_t.h"
+#include "src/wchar/wcsrchr.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcWCSRChrTest, FindsFirstCharacter) {
+ // Should return pointer to original string since 'a' is the first character.
+ const wchar_t *src = L"abcde";
+ ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(src, L'a'), src);
+}
+
+TEST(LlvmLibcWCSRChrTest, FindsMiddleCharacter) {
+ // Should return pointer to 'c'.
+ const wchar_t *src = L"abcde";
+ ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(src, L'c'), (src + 2));
+}
+
+TEST(LlvmLibcWCSRChrTest, FindsLastCharacterThatIsNotNullTerminator) {
+ // Should return pointer to 'e'.
+ const wchar_t *src = L"abcde";
+ ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(src, L'e'), (src + 4));
+}
+
+TEST(LlvmLibcWCSRChrTest, FindsNullTerminator) {
+ // Should return pointer to null terminator.
+ const wchar_t *src = L"abcde";
+ ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(src, L'\0'), (src + 5));
+}
+
+TEST(LlvmLibcWCSRChrTest, CharacterNotWithinStringShouldReturnNullptr) {
+ // Since 'z' is not within the string, should return nullptr.
+ const wchar_t *src = L"abcde";
+ ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(src, L'z'), nullptr);
+}
+
+TEST(LlvmLibcWCSRChrTest, ShouldFindLastOfDuplicates) {
+ // Should return pointer to the last '1'.
+ const wchar_t *src = L"abc1def1ghi";
+ ASSERT_EQ((int)(LIBC_NAMESPACE::wcsrchr(src, L'1') - src), 7);
+
+ // Should return pointer to the last 'X'
+ const wchar_t *dups = L"XXXXX";
+ ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(dups, L'X'), dups + 4);
+}
+
+TEST(LlvmLibcWCSRChrTest, EmptyStringShouldOnlyMatchNullTerminator) {
+ // Null terminator should match
+ const wchar_t *src = L"";
+ ASSERT_EQ(src, LIBC_NAMESPACE::wcsrchr(src, L'\0'));
+ // All other characters should not match
+ ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(src, L'Z'), nullptr);
+ ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(src, L'3'), nullptr);
+ ASSERT_EQ(LIBC_NAMESPACE::wcsrchr(src, L'*'), nullptr);
+}
+
+#if defined(LIBC_ADD_NULL_CHECKS) && !defined(LIBC_HAS_SANITIZER)
+TEST(LlvmLibcWCSRChrTest, NullptrCrash) {
+ // Passing in a nullptr should crash the program.
+ EXPECT_DEATH([] { LIBC_NAMESPACE::wcsrchr(nullptr, L'a'); }, WITH_SIGNAL(-1));
+}
+#endif // LIBC_HAS_ADDRESS_SANITIZER
diff --git a/test/src/wchar/wcsstr_test.cpp b/test/src/wchar/wcsstr_test.cpp
new file mode 100644
index 0000000..c1448bb
--- /dev/null
+++ b/test/src/wchar/wcsstr_test.cpp
@@ -0,0 +1,113 @@
+//===-- Unittests for wcsstr ----------------------------------------------===//
+//
+// 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/types/wchar_t.h"
+#include "src/wchar/wcsstr.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcWCSStrTest, NeedleNotInHaystack) {
+ // Should return nullptr if string is not found.
+ const wchar_t *haystack = L"12345";
+ const wchar_t *needle = L"a";
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), nullptr);
+}
+
+TEST(LlvmLibcWCSStrTest, NeedleIsEmptyString) {
+ // Should return pointer to first character if needle is empty.
+ const wchar_t *haystack = L"12345";
+ const wchar_t *needle = L"";
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), haystack);
+}
+
+TEST(LlvmLibcWCSStrTest, HaystackIsEmptyString) {
+ // Should return nullptr since haystack is empty.
+ const wchar_t *needle = L"12345";
+ const wchar_t *haystack = L"";
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), nullptr);
+}
+
+TEST(LlvmLibcWCSStrTest, HaystackAndNeedleAreEmptyStrings) {
+ // Should point to haystack since needle is empty.
+ const wchar_t *needle = L"";
+ const wchar_t *haystack = L"";
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), haystack);
+}
+
+TEST(LlvmLibcWCSStrTest, HaystackAndNeedleAreSingleCharacters) {
+ const wchar_t *haystack = L"a";
+ // Should point to haystack.
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"a"), haystack);
+ // Should return nullptr.
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"b"), nullptr);
+}
+
+TEST(LlvmLibcWCSStrTest, NeedleEqualToHaystack) {
+ const wchar_t *haystack = L"12345";
+ // Should point to haystack.
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"12345"), haystack);
+}
+
+TEST(LlvmLibcWCSStrTest, NeedleLargerThanHaystack) {
+ const wchar_t *haystack = L"123";
+ // Should return nullptr.
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"12345"), nullptr);
+}
+
+TEST(LlvmLibcWCSStrTest, NeedleAtBeginning) {
+ const wchar_t *haystack = L"12345";
+ const wchar_t *needle = L"12";
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), haystack);
+}
+
+TEST(LlvmLibcWCSStrTest, NeedleInMiddle) {
+ const wchar_t *haystack = L"abcdefghi";
+ const wchar_t *needle = L"def";
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), haystack + 3);
+}
+
+TEST(LlvmLibcWCSStrTest, NeedleDirectlyBeforeNullTerminator) {
+ const wchar_t *haystack = L"abcdefghi";
+ const wchar_t *needle = L"ghi";
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), haystack + 6);
+}
+
+TEST(LlvmLibcWCSStrTest, NeedlePastNullTerminator) {
+ const wchar_t haystack[5] = {L'1', L'2', L'\0', L'3', L'4'};
+ // Shouldn't find anything after the null terminator.
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, /*needle=*/L"3"), nullptr);
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, /*needle=*/L"4"), nullptr);
+}
+
+TEST(LlvmLibcWCSStrTest, PartialNeedle) {
+ const wchar_t *haystack = L"la_ap_lap";
+ const wchar_t *needle = L"lap";
+ // Shouldn't find la or ap.
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), haystack + 6);
+}
+
+TEST(LlvmLibcWCSStrTest, MisspelledNeedle) {
+ const wchar_t *haystack = L"atalloftwocities...wait, tale";
+ const wchar_t *needle = L"tale";
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), haystack + 25);
+}
+
+TEST(LlvmLibcWCSStrTest, AnagramNeedle) {
+ const wchar_t *haystack = L"dgo_ogd_god_odg_gdo_dog";
+ const wchar_t *needle = L"dog";
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, needle), haystack + 20);
+}
+
+TEST(LlvmLibcWCSStrTest, MorphedNeedle) {
+ // Changes a single letter in the needle to mismatch with the haystack.
+ const wchar_t *haystack = L"once upon a time";
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"time"), haystack + 12);
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"lime"), nullptr);
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"tome"), nullptr);
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"tire"), nullptr);
+ ASSERT_EQ(LIBC_NAMESPACE::wcsstr(haystack, L"timo"), nullptr);
+}
diff --git a/test/src/wchar/wmempcpy_test.cpp b/test/src/wchar/wmempcpy_test.cpp
new file mode 100644
index 0000000..000e4b3
--- /dev/null
+++ b/test/src/wchar/wmempcpy_test.cpp
@@ -0,0 +1,50 @@
+//===-- Unittests for wmempcpy --------------------------------------------===//
+//
+// 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/wchar/wmempcpy.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcWMempcpyTest, Simple) {
+ const wchar_t *src = L"12345";
+ wchar_t dest[10] = {};
+ void *result = LIBC_NAMESPACE::wmempcpy(dest, src, 6);
+ ASSERT_EQ(static_cast<wchar_t *>(result), dest + 6);
+
+ ASSERT_TRUE(dest[0] == src[0]);
+ ASSERT_TRUE(dest[1] == src[1]);
+ ASSERT_TRUE(dest[2] == src[2]);
+ ASSERT_TRUE(dest[3] == src[3]);
+ ASSERT_TRUE(dest[4] == src[4]);
+ ASSERT_TRUE(dest[5] == src[5]);
+}
+
+TEST(LlvmLibcWmempcpyTest, ZeroCount) {
+ const wchar_t *src = L"12345";
+ wchar_t dest[5] = {};
+ void *result = LIBC_NAMESPACE::wmempcpy(dest, src, 0);
+ ASSERT_EQ(static_cast<wchar_t *>(result), dest);
+
+ ASSERT_TRUE(dest[0] == 0);
+ ASSERT_TRUE(dest[1] == 0);
+ ASSERT_TRUE(dest[2] == 0);
+ ASSERT_TRUE(dest[3] == 0);
+ ASSERT_TRUE(dest[4] == 0);
+}
+
+TEST(LlvmLibcWMempcpyTest, BoundaryCheck) {
+ const wchar_t *src = L"12345";
+ wchar_t dest[4] = {};
+ void *result = LIBC_NAMESPACE::wmempcpy(dest + 1, src + 1, 2);
+
+ ASSERT_TRUE(dest[0] == 0);
+ ASSERT_TRUE(dest[1] == src[1]);
+ ASSERT_TRUE(dest[2] == src[2]);
+ ASSERT_TRUE(dest[3] == 0);
+
+ ASSERT_EQ(static_cast<wchar_t *>(result), dest + 3);
+}