From 83bd24b3384919775cce99b5ce11c6cd2490562a Mon Sep 17 00:00:00 2001 From: google-yfyang Date: Wed, 21 Jan 2026 10:28:11 -0500 Subject: [PATCH 1/2] reinstate emscripten local changes when importing llvm-libc --- system/lib/llvm-libc/src/string/memory_utils/inline_memcpy.h | 2 +- system/lib/llvm-libc/src/string/memory_utils/inline_memmove.h | 2 +- system/lib/llvm-libc/src/string/memory_utils/inline_memset.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/system/lib/llvm-libc/src/string/memory_utils/inline_memcpy.h b/system/lib/llvm-libc/src/string/memory_utils/inline_memcpy.h index f98e55321a9b5..9f1a162416da0 100644 --- a/system/lib/llvm-libc/src/string/memory_utils/inline_memcpy.h +++ b/system/lib/llvm-libc/src/string/memory_utils/inline_memcpy.h @@ -28,7 +28,7 @@ #elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) #include "src/string/memory_utils/riscv/inline_memcpy.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMCPY inline_memcpy_riscv -#elif defined(LIBC_TARGET_ARCH_IS_GPU) +#elif defined(LIBC_TARGET_ARCH_IS_GPU) || defined(LIBC_TARGET_ARCH_IS_WASM) #include "src/string/memory_utils/generic/builtin.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMCPY inline_memcpy_builtin #else diff --git a/system/lib/llvm-libc/src/string/memory_utils/inline_memmove.h b/system/lib/llvm-libc/src/string/memory_utils/inline_memmove.h index 71a28c32e4c56..31627669b06bf 100644 --- a/system/lib/llvm-libc/src/string/memory_utils/inline_memmove.h +++ b/system/lib/llvm-libc/src/string/memory_utils/inline_memmove.h @@ -29,7 +29,7 @@ #define LIBC_SRC_STRING_MEMORY_UTILS_MEMMOVE_SMALL_SIZE \ inline_memmove_no_small_size #define LIBC_SRC_STRING_MEMORY_UTILS_MEMMOVE_FOLLOW_UP inline_memmove_riscv -#elif defined(LIBC_TARGET_ARCH_IS_GPU) +#elif defined(LIBC_TARGET_ARCH_IS_GPU) || defined(LIBC_TARGET_ARCH_IS_WASM) #include "src/string/memory_utils/generic/builtin.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMMOVE_SMALL_SIZE \ inline_memmove_no_small_size diff --git a/system/lib/llvm-libc/src/string/memory_utils/inline_memset.h b/system/lib/llvm-libc/src/string/memory_utils/inline_memset.h index fd9c29ea4410a..1ac071f1473ce 100644 --- a/system/lib/llvm-libc/src/string/memory_utils/inline_memset.h +++ b/system/lib/llvm-libc/src/string/memory_utils/inline_memset.h @@ -24,7 +24,7 @@ #elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) #include "src/string/memory_utils/riscv/inline_memset.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMSET inline_memset_riscv -#elif defined(LIBC_TARGET_ARCH_IS_GPU) +#elif defined(LIBC_TARGET_ARCH_IS_GPU) || defined(LIBC_TARGET_ARCH_IS_WASM) #include "src/string/memory_utils/generic/builtin.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMSET inline_memset_builtin #else From c5208b9bf700af9e2a888da33489e36dab1aeead Mon Sep 17 00:00:00 2001 From: google-yfyang Date: Thu, 22 Jan 2026 16:00:42 -0500 Subject: [PATCH 2/2] update llvmlibc to llvm 21.1.8 --- .../lib/llvm-libc/src/__support/CPP/atomic.h | 3 +- system/lib/llvm-libc/src/__support/CPP/new.h | 8 + .../CPP/type_traits/is_floating_point.h | 3 +- .../llvm-libc/src/__support/FPUtil/FEnvImpl.h | 22 +- .../llvm-libc/src/__support/FPUtil/FPBits.h | 11 + .../__support/FPUtil/ManipulationFunctions.h | 2 +- .../llvm-libc/src/__support/FPUtil/bfloat16.h | 65 ++ .../lib/llvm-libc/src/__support/FPUtil/cast.h | 14 +- .../src/__support/FPUtil/dyadic_float.h | 16 +- .../src/__support/FPUtil/x86_64/FEnvImpl.h | 13 +- .../llvm-libc/src/__support/GPU/allocator.cpp | 59 +- .../llvm-libc/src/__support/GPU/allocator.h | 2 + .../src/__support/HashTable/randomness.h | 16 +- .../src/__support/OSUtil/linux/getrandom.h | 35 ++ .../src/__support/macros/optimization.h | 12 +- .../macros/properties/cpu_features.h | 6 +- .../src/__support/macros/properties/types.h | 13 +- .../lib/llvm-libc/src/__support/math/expf16.h | 141 +++++ .../src/__support/math/expf16_utils.h | 89 +++ .../lib/llvm-libc/src/__support/math/frexpf.h | 28 + .../llvm-libc/src/__support/math/frexpf128.h | 34 ++ .../llvm-libc/src/__support/math/frexpf16.h | 34 ++ .../lib/llvm-libc/src/__support/math/ldexpf.h | 28 + .../llvm-libc/src/__support/math/ldexpf128.h | 34 ++ .../llvm-libc/src/__support/math/ldexpf16.h | 34 ++ .../llvm-libc/src/__support/str_to_float.h | 2 +- .../llvm-libc/src/__support/str_to_integer.h | 9 +- .../src/__support/threads/linux/thread.cpp | 2 +- .../__support/wchar/character_converter.cpp | 86 ++- .../src/__support/wchar/character_converter.h | 8 +- .../llvm-libc/src/__support/wchar/mbrtowc.cpp | 52 ++ .../llvm-libc/src/__support/wchar/mbrtowc.h | 29 + .../llvm-libc/src/__support/wchar/mbstate.h | 10 +- .../src/__support/wchar/string_converter.h | 110 ++++ .../llvm-libc/src/__support/wchar/wcrtomb.cpp | 50 ++ .../llvm-libc/src/__support/wchar/wcrtomb.h | 26 + .../llvm-libc/src/__support/wcs_to_integer.h | 155 +++++ .../llvm-libc/src/__support/wctype_utils.h | 559 ++++++++++++++++++ .../lib/llvm-libc/src/math/generic/frexpf.cpp | 7 +- .../llvm-libc/src/math/generic/frexpf128.cpp | 7 +- .../lib/llvm-libc/src/math/generic/ldexpf.cpp | 6 +- .../llvm-libc/src/math/generic/ldexpf128.cpp | 7 +- .../lib/llvm-libc/src/math/generic/log2f.cpp | 2 +- .../lib/llvm-libc/src/math/generic/tanpif.cpp | 106 ++++ system/lib/llvm-libc/src/math/tanpif.h | 20 + .../src/stdlib/gpu/aligned_alloc.cpp | 18 +- .../lib/llvm-libc/src/stdlib/gpu/realloc.cpp | 20 +- .../string/memory_utils/arm/inline_memcpy.h | 217 +++++++ .../src/string/memory_utils/inline_memcpy.h | 3 + .../llvm-libc/src/string/memory_utils/utils.h | 2 +- system/lib/llvm-libc/src/wchar/mbrtowc.cpp | 38 ++ system/lib/llvm-libc/src/wchar/mbrtowc.h | 24 + system/lib/llvm-libc/src/wchar/mbtowc.cpp | 40 ++ system/lib/llvm-libc/src/wchar/mbtowc.h | 22 + system/lib/llvm-libc/src/wchar/wcpcpy.cpp | 27 + system/lib/llvm-libc/src/wchar/wcpcpy.h | 21 + system/lib/llvm-libc/src/wchar/wcpncpy.cpp | 37 ++ system/lib/llvm-libc/src/wchar/wcpncpy.h | 23 + system/lib/llvm-libc/src/wchar/wcrtomb.cpp | 45 ++ system/lib/llvm-libc/src/wchar/wcrtomb.h | 23 + system/lib/llvm-libc/src/wchar/wcscspn.cpp | 34 ++ system/lib/llvm-libc/src/wchar/wcscspn.h | 22 + system/lib/llvm-libc/src/wchar/wcslcat.cpp | 39 ++ system/lib/llvm-libc/src/wchar/wcslcat.h | 23 + system/lib/llvm-libc/src/wchar/wcslcpy.cpp | 32 + system/lib/llvm-libc/src/wchar/wcslcpy.h | 23 + system/lib/llvm-libc/src/wchar/wcsnlen.cpp | 25 + system/lib/llvm-libc/src/wchar/wcsnlen.h | 22 + system/lib/llvm-libc/src/wchar/wcsspn.h | 2 +- system/lib/llvm-libc/src/wchar/wcstok.cpp | 50 ++ system/lib/llvm-libc/src/wchar/wcstok.h | 22 + system/lib/llvm-libc/src/wchar/wcstol.cpp | 30 + system/lib/llvm-libc/src/wchar/wcstol.h | 22 + system/lib/llvm-libc/src/wchar/wcstoll.cpp | 30 + system/lib/llvm-libc/src/wchar/wcstoll.h | 22 + system/lib/llvm-libc/src/wchar/wcstoul.cpp | 30 + system/lib/llvm-libc/src/wchar/wcstoul.h | 22 + system/lib/llvm-libc/src/wchar/wcstoull.cpp | 30 + system/lib/llvm-libc/src/wchar/wcstoull.h | 22 + system/lib/llvm-libc/src/wchar/wctomb.cpp | 35 ++ system/lib/llvm-libc/src/wchar/wctomb.h | 22 + tools/system_libs.py | 3 +- 82 files changed, 2974 insertions(+), 123 deletions(-) create mode 100644 system/lib/llvm-libc/src/__support/FPUtil/bfloat16.h create mode 100644 system/lib/llvm-libc/src/__support/OSUtil/linux/getrandom.h create mode 100644 system/lib/llvm-libc/src/__support/math/expf16.h create mode 100644 system/lib/llvm-libc/src/__support/math/expf16_utils.h create mode 100644 system/lib/llvm-libc/src/__support/math/frexpf.h create mode 100644 system/lib/llvm-libc/src/__support/math/frexpf128.h create mode 100644 system/lib/llvm-libc/src/__support/math/frexpf16.h create mode 100644 system/lib/llvm-libc/src/__support/math/ldexpf.h create mode 100644 system/lib/llvm-libc/src/__support/math/ldexpf128.h create mode 100644 system/lib/llvm-libc/src/__support/math/ldexpf16.h create mode 100644 system/lib/llvm-libc/src/__support/wchar/mbrtowc.cpp create mode 100644 system/lib/llvm-libc/src/__support/wchar/mbrtowc.h create mode 100644 system/lib/llvm-libc/src/__support/wchar/string_converter.h create mode 100644 system/lib/llvm-libc/src/__support/wchar/wcrtomb.cpp create mode 100644 system/lib/llvm-libc/src/__support/wchar/wcrtomb.h create mode 100644 system/lib/llvm-libc/src/__support/wcs_to_integer.h create mode 100644 system/lib/llvm-libc/src/math/generic/tanpif.cpp create mode 100644 system/lib/llvm-libc/src/math/tanpif.h create mode 100644 system/lib/llvm-libc/src/string/memory_utils/arm/inline_memcpy.h create mode 100644 system/lib/llvm-libc/src/wchar/mbrtowc.cpp create mode 100644 system/lib/llvm-libc/src/wchar/mbrtowc.h create mode 100644 system/lib/llvm-libc/src/wchar/mbtowc.cpp create mode 100644 system/lib/llvm-libc/src/wchar/mbtowc.h create mode 100644 system/lib/llvm-libc/src/wchar/wcpcpy.cpp create mode 100644 system/lib/llvm-libc/src/wchar/wcpcpy.h create mode 100644 system/lib/llvm-libc/src/wchar/wcpncpy.cpp create mode 100644 system/lib/llvm-libc/src/wchar/wcpncpy.h create mode 100644 system/lib/llvm-libc/src/wchar/wcrtomb.cpp create mode 100644 system/lib/llvm-libc/src/wchar/wcrtomb.h create mode 100644 system/lib/llvm-libc/src/wchar/wcscspn.cpp create mode 100644 system/lib/llvm-libc/src/wchar/wcscspn.h create mode 100644 system/lib/llvm-libc/src/wchar/wcslcat.cpp create mode 100644 system/lib/llvm-libc/src/wchar/wcslcat.h create mode 100644 system/lib/llvm-libc/src/wchar/wcslcpy.cpp create mode 100644 system/lib/llvm-libc/src/wchar/wcslcpy.h create mode 100644 system/lib/llvm-libc/src/wchar/wcsnlen.cpp create mode 100644 system/lib/llvm-libc/src/wchar/wcsnlen.h create mode 100644 system/lib/llvm-libc/src/wchar/wcstok.cpp create mode 100644 system/lib/llvm-libc/src/wchar/wcstok.h create mode 100644 system/lib/llvm-libc/src/wchar/wcstol.cpp create mode 100644 system/lib/llvm-libc/src/wchar/wcstol.h create mode 100644 system/lib/llvm-libc/src/wchar/wcstoll.cpp create mode 100644 system/lib/llvm-libc/src/wchar/wcstoll.h create mode 100644 system/lib/llvm-libc/src/wchar/wcstoul.cpp create mode 100644 system/lib/llvm-libc/src/wchar/wcstoul.h create mode 100644 system/lib/llvm-libc/src/wchar/wcstoull.cpp create mode 100644 system/lib/llvm-libc/src/wchar/wcstoull.h create mode 100644 system/lib/llvm-libc/src/wchar/wctomb.cpp create mode 100644 system/lib/llvm-libc/src/wchar/wctomb.h diff --git a/system/lib/llvm-libc/src/__support/CPP/atomic.h b/system/lib/llvm-libc/src/__support/CPP/atomic.h index 2f00b3ed32811..53b583c04ba15 100644 --- a/system/lib/llvm-libc/src/__support/CPP/atomic.h +++ b/system/lib/llvm-libc/src/__support/CPP/atomic.h @@ -28,7 +28,8 @@ enum class MemoryOrder : int { SEQ_CST = __ATOMIC_SEQ_CST }; -// These are a clang extension, see the clang documenation for more information: +// These are a clang extension, see the clang documentation for more +// information: // https://clang.llvm.org/docs/LanguageExtensions.html#scoped-atomic-builtins. enum class MemoryScope : int { #if defined(__MEMORY_SCOPE_SYSTEM) && defined(__MEMORY_SCOPE_DEVICE) diff --git a/system/lib/llvm-libc/src/__support/CPP/new.h b/system/lib/llvm-libc/src/__support/CPP/new.h index 8694d9c475507..fe36de29468a8 100644 --- a/system/lib/llvm-libc/src/__support/CPP/new.h +++ b/system/lib/llvm-libc/src/__support/CPP/new.h @@ -29,6 +29,14 @@ enum class align_val_t : size_t {}; namespace LIBC_NAMESPACE_DECL { +namespace cpp { +template [[nodiscard]] constexpr T *launder(T *p) { + static_assert(__has_builtin(__builtin_launder), + "cpp::launder requires __builtin_launder"); + return __builtin_launder(p); +} +} // namespace cpp + class AllocChecker { bool success = false; diff --git a/system/lib/llvm-libc/src/__support/CPP/type_traits/is_floating_point.h b/system/lib/llvm-libc/src/__support/CPP/type_traits/is_floating_point.h index 11ffbfabe60b6..9dc77ad7ee0ea 100644 --- a/system/lib/llvm-libc/src/__support/CPP/type_traits/is_floating_point.h +++ b/system/lib/llvm-libc/src/__support/CPP/type_traits/is_floating_point.h @@ -36,7 +36,8 @@ template struct is_floating_point { , float128 #endif - >(); + , + bfloat16>(); }; template LIBC_INLINE_VAR constexpr bool is_floating_point_v = diff --git a/system/lib/llvm-libc/src/__support/FPUtil/FEnvImpl.h b/system/lib/llvm-libc/src/__support/FPUtil/FEnvImpl.h index 50a101f833c55..76910880eb810 100644 --- a/system/lib/llvm-libc/src/__support/FPUtil/FEnvImpl.h +++ b/system/lib/llvm-libc/src/__support/FPUtil/FEnvImpl.h @@ -15,6 +15,7 @@ #include "src/__support/libc_errno.h" #include "src/__support/macros/attributes.h" // LIBC_INLINE #include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" #include "src/__support/macros/properties/architectures.h" #if defined(LIBC_TARGET_ARCH_IS_AARCH64) && defined(__ARM_FP) @@ -71,27 +72,40 @@ LIBC_INLINE int set_env(const fenv_t *) { return 0; } namespace LIBC_NAMESPACE_DECL { namespace fputil { -LIBC_INLINE int clear_except_if_required(int excepts) { +LIBC_INLINE static int clear_except_if_required([[maybe_unused]] int excepts) { +#ifndef LIBC_MATH_HAS_NO_EXCEPT if (math_errhandling & MATH_ERREXCEPT) return clear_except(excepts); +#endif // LIBC_MATH_HAS_NO_EXCEPT return 0; } -LIBC_INLINE int set_except_if_required(int excepts) { +LIBC_INLINE static int set_except_if_required([[maybe_unused]] int excepts) { +#ifndef LIBC_MATH_HAS_NO_EXCEPT if (math_errhandling & MATH_ERREXCEPT) return set_except(excepts); +#endif // LIBC_MATH_HAS_NO_EXCEPT return 0; } -LIBC_INLINE int raise_except_if_required(int excepts) { +LIBC_INLINE static int raise_except_if_required([[maybe_unused]] int excepts) { +#ifndef LIBC_MATH_HAS_NO_EXCEPT if (math_errhandling & MATH_ERREXCEPT) +#ifdef LIBC_TARGET_ARCH_IS_X86_64 + return raise_except(excepts); +#else // !LIBC_TARGET_ARCH_IS_X86 return raise_except(excepts); +#endif // LIBC_TARGET_ARCH_IS_X86 + +#endif // LIBC_MATH_HAS_NO_EXCEPT return 0; } -LIBC_INLINE void set_errno_if_required(int err) { +LIBC_INLINE static void set_errno_if_required([[maybe_unused]] int err) { +#ifndef LIBC_MATH_HAS_NO_ERRNO if (math_errhandling & MATH_ERRNO) libc_errno = err; +#endif // LIBC_MATH_HAS_NO_ERRNO } } // namespace fputil diff --git a/system/lib/llvm-libc/src/__support/FPUtil/FPBits.h b/system/lib/llvm-libc/src/__support/FPUtil/FPBits.h index 4fa3bc30ecd12..9e21136558a03 100644 --- a/system/lib/llvm-libc/src/__support/FPUtil/FPBits.h +++ b/system/lib/llvm-libc/src/__support/FPUtil/FPBits.h @@ -38,6 +38,7 @@ enum class FPType { IEEE754_Binary64, IEEE754_Binary128, X86_Binary80, + BFloat16 }; // The classes hierarchy is as follows: @@ -138,6 +139,14 @@ template <> struct FPLayout { LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SIG_LEN - 1; }; +template <> struct FPLayout { + using StorageType = uint16_t; + LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1; + LIBC_INLINE_VAR static constexpr int EXP_LEN = 8; + LIBC_INLINE_VAR static constexpr int SIG_LEN = 7; + LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SIG_LEN; +}; + // FPStorage derives useful constants from the FPLayout above. template struct FPStorage : public FPLayout { using UP = FPLayout; @@ -801,6 +810,8 @@ template LIBC_INLINE static constexpr FPType get_fp_type() { else if constexpr (cpp::is_same_v) return FPType::IEEE754_Binary128; #endif + else if constexpr (cpp::is_same_v) + return FPType::BFloat16; else static_assert(cpp::always_false, "Unsupported type"); } diff --git a/system/lib/llvm-libc/src/__support/FPUtil/ManipulationFunctions.h b/system/lib/llvm-libc/src/__support/FPUtil/ManipulationFunctions.h index 9c10011ccd203..ea9ee5a57c36d 100644 --- a/system/lib/llvm-libc/src/__support/FPUtil/ManipulationFunctions.h +++ b/system/lib/llvm-libc/src/__support/FPUtil/ManipulationFunctions.h @@ -29,7 +29,7 @@ namespace LIBC_NAMESPACE_DECL { namespace fputil { template , int> = 0> -LIBC_INLINE T frexp(T x, int &exp) { +LIBC_INLINE constexpr T frexp(T x, int &exp) { FPBits bits(x); if (bits.is_inf_or_nan()) { #ifdef LIBC_FREXP_INF_NAN_EXPONENT diff --git a/system/lib/llvm-libc/src/__support/FPUtil/bfloat16.h b/system/lib/llvm-libc/src/__support/FPUtil/bfloat16.h new file mode 100644 index 0000000000000..bc0b8b23896fc --- /dev/null +++ b/system/lib/llvm-libc/src/__support/FPUtil/bfloat16.h @@ -0,0 +1,65 @@ +//===-- Definition of bfloat16 data type. -----------------------*- 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_FPUTIL_BFLOAT16_H +#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_BFLOAT16_H + +#include "src/__support/CPP/bit.h" +#include "src/__support/CPP/type_traits.h" +#include "src/__support/FPUtil/cast.h" +#include "src/__support/FPUtil/dyadic_float.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" + +#include + +namespace LIBC_NAMESPACE_DECL { +namespace fputil { + +struct BFloat16 { + uint16_t bits; + + LIBC_INLINE BFloat16() = default; + + LIBC_INLINE constexpr explicit BFloat16(uint16_t bits) : bits(bits) {} + + template LIBC_INLINE constexpr explicit BFloat16(T value) { + if constexpr (cpp::is_floating_point_v) { + bits = fputil::cast(value).bits; + } else if constexpr (cpp::is_integral_v) { + Sign sign = Sign::POS; + + if constexpr (cpp::is_signed_v) { + if (value < 0) { + sign = Sign::NEG; + value = -value; + } + } + + fputil::DyadicFloat>::digits> + xd(sign, 0, value); + bits = xd.template as().bits; + + } else { + bits = fputil::cast(static_cast(value)).bits; + } + } + + template () == + fputil::FPType::IEEE754_Binary32, + int> = 0> + LIBC_INLINE constexpr operator float() const { + uint32_t x_bits = static_cast(bits) << 16U; + return cpp::bit_cast(x_bits); + } +}; // struct BFloat16 + +} // namespace fputil +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_BFLOAT16_H diff --git a/system/lib/llvm-libc/src/__support/FPUtil/cast.h b/system/lib/llvm-libc/src/__support/FPUtil/cast.h index 7578bb42b18f1..e6fad1be7d053 100644 --- a/system/lib/llvm-libc/src/__support/FPUtil/cast.h +++ b/system/lib/llvm-libc/src/__support/FPUtil/cast.h @@ -26,9 +26,18 @@ LIBC_INLINE constexpr cpp::enable_if_t && cpp::is_floating_point_v, OutType> cast(InType x) { + // Casting to the same type is a no-op. + if constexpr (cpp::is_same_v) + return x; + + // bfloat16 is always defined (for now) + if constexpr (cpp::is_same_v || + cpp::is_same_v #if defined(LIBC_TYPES_HAS_FLOAT16) && !defined(__LIBC_USE_FLOAT16_CONVERSION) - if constexpr (cpp::is_same_v || - cpp::is_same_v) { + || cpp::is_same_v || + cpp::is_same_v +#endif + ) { using InFPBits = FPBits; using InStorageType = typename InFPBits::StorageType; using OutFPBits = FPBits; @@ -58,7 +67,6 @@ cast(InType x) { DyadicFloat xd(x); return xd.template as(); } -#endif return static_cast(x); } diff --git a/system/lib/llvm-libc/src/__support/FPUtil/dyadic_float.h b/system/lib/llvm-libc/src/__support/FPUtil/dyadic_float.h index 6c3e1520e5aff..3464e4aa9423f 100644 --- a/system/lib/llvm-libc/src/__support/FPUtil/dyadic_float.h +++ b/system/lib/llvm-libc/src/__support/FPUtil/dyadic_float.h @@ -170,7 +170,6 @@ template struct DyadicFloat { return DyadicFloat(result_sign, result_exponent, result_mantissa); } -#ifdef LIBC_TYPES_HAS_FLOAT16 template LIBC_INLINE constexpr cpp::enable_if_t< cpp::is_floating_point_v && (FPBits::FRACTION_LEN < Bits), T> @@ -277,7 +276,6 @@ template struct DyadicFloat { return FPBits(result).get_val(); } -#endif // LIBC_TYPES_HAS_FLOAT16 template && @@ -411,11 +409,14 @@ template struct DyadicFloat { (FPBits::FRACTION_LEN < Bits), void>> LIBC_INLINE constexpr T as() const { + if constexpr (cpp::is_same_v #if defined(LIBC_TYPES_HAS_FLOAT16) && !defined(__LIBC_USE_FLOAT16_CONVERSION) - if constexpr (cpp::is_same_v) - return generic_as(); + || cpp::is_same_v #endif - return fast_as(); + ) + return generic_as(); + else + return fast_as(); } template struct DyadicFloat { // exponents coming in to this function _shouldn't_ be that large). The // result should always end up as a positive size_t. size_t shift = -static_cast(exponent); - new_mant >>= shift; + if (shift >= Bits) + new_mant = 0; + else + new_mant >>= shift; round_dir = rounding_direction(mantissa, shift, sign); if (round_dir > 0) ++new_mant; diff --git a/system/lib/llvm-libc/src/__support/FPUtil/x86_64/FEnvImpl.h b/system/lib/llvm-libc/src/__support/FPUtil/x86_64/FEnvImpl.h index b77178ea69ea0..560727c22978e 100644 --- a/system/lib/llvm-libc/src/__support/FPUtil/x86_64/FEnvImpl.h +++ b/system/lib/llvm-libc/src/__support/FPUtil/x86_64/FEnvImpl.h @@ -239,7 +239,7 @@ LIBC_INLINE int set_except(int excepts) { return 0; } -LIBC_INLINE int raise_except(int excepts) { +template LIBC_INLINE int raise_except(int excepts) { uint16_t status_value = internal::get_status_value_for_except(excepts); // We set the status flag for exception one at a time and call the @@ -256,13 +256,16 @@ LIBC_INLINE int raise_except(int excepts) { // when raising the next exception. auto raise_helper = [](uint16_t singleExceptFlag) { - internal::X87StateDescriptor state; + if constexpr (!SKIP_X87_FPU) { + internal::X87StateDescriptor state; + internal::get_x87_state_descriptor(state); + state.status_word |= singleExceptFlag; + internal::write_x87_state_descriptor(state); + } + uint32_t mxcsr = 0; - internal::get_x87_state_descriptor(state); mxcsr = internal::get_mxcsr(); - state.status_word |= singleExceptFlag; mxcsr |= singleExceptFlag; - internal::write_x87_state_descriptor(state); internal::write_mxcsr(mxcsr); internal::fwait(); }; diff --git a/system/lib/llvm-libc/src/__support/GPU/allocator.cpp b/system/lib/llvm-libc/src/__support/GPU/allocator.cpp index 66ab155e5c299..7923fbb2c1c24 100644 --- a/system/lib/llvm-libc/src/__support/GPU/allocator.cpp +++ b/system/lib/llvm-libc/src/__support/GPU/allocator.cpp @@ -22,6 +22,7 @@ #include "src/__support/GPU/utils.h" #include "src/__support/RPC/rpc_client.h" #include "src/__support/threads/sleep.h" +#include "src/string/memory_utils/inline_memcpy.h" namespace LIBC_NAMESPACE_DECL { @@ -137,6 +138,11 @@ void uniform_memset(uint32_t *s, uint32_t c, uint32_t n, uint64_t uniform) { s[i] = c; } +// Indicates that the provided value is a power of two. +static inline constexpr bool is_pow2(uint64_t x) { + return x && (x & (x - 1)) == 0; +} + } // namespace impl /// A slab allocator used to hand out identically sized slabs of memory. @@ -183,7 +189,9 @@ struct Slab { // Get the number of bytes needed to contain the bitfield bits. constexpr static uint32_t bitfield_bytes(uint32_t chunk_size) { - return ((num_chunks(chunk_size) + BITS_IN_WORD - 1) / BITS_IN_WORD) * 8; + return __builtin_align_up( + ((num_chunks(chunk_size) + BITS_IN_WORD - 1) / BITS_IN_WORD) * 8, + MIN_ALIGNMENT + 1); } // The actual amount of memory available excluding the bitfield and metadata. @@ -540,15 +548,58 @@ void deallocate(void *ptr) { return; // All non-slab allocations will be aligned on a 2MiB boundary. - if ((reinterpret_cast(ptr) & SLAB_ALIGNMENT) == 0) + if (__builtin_is_aligned(ptr, SLAB_ALIGNMENT + 1)) return impl::rpc_free(ptr); // The original slab pointer is the 2MiB boundary using the given pointer. - Slab *slab = reinterpret_cast( - (reinterpret_cast(ptr) & ~SLAB_ALIGNMENT)); + Slab *slab = cpp::launder(reinterpret_cast( + (reinterpret_cast(ptr) & ~SLAB_ALIGNMENT))); slab->deallocate(ptr); release_slab(slab); } +void *reallocate(void *ptr, uint64_t size) { + if (ptr == nullptr) + return gpu::allocate(size); + + // Non-slab allocations are considered foreign pointers so we fail. + if (__builtin_is_aligned(ptr, SLAB_ALIGNMENT + 1)) + return nullptr; + + // The original slab pointer is the 2MiB boundary using the given pointer. + Slab *slab = cpp::launder(reinterpret_cast( + (reinterpret_cast(ptr) & ~SLAB_ALIGNMENT))); + if (slab->get_chunk_size() >= size) + return ptr; + + // If we need a new chunk we reallocate and copy it over. + void *new_ptr = gpu::allocate(size); + inline_memcpy(new_ptr, ptr, slab->get_chunk_size()); + gpu::deallocate(ptr); + return new_ptr; +} + +void *aligned_allocate(uint32_t alignment, uint64_t size) { + // All alignment values must be a non-zero power of two. + if (!impl::is_pow2(alignment)) + return nullptr; + + // If the requested alignment is less than what we already provide this is + // just a normal allocation. + if (alignment <= MIN_ALIGNMENT + 1) + return gpu::allocate(size); + + // We can't handle alignments greater than 2MiB so we simply fail. + if (alignment > SLAB_ALIGNMENT + 1) + return nullptr; + + // Trying to handle allocation internally would break the assumption that each + // chunk is identical to eachother. Allocate enough memory with worst-case + // alignment and then round up. The index logic will round down properly. + uint64_t rounded = size + alignment - MIN_ALIGNMENT; + void *ptr = gpu::allocate(rounded); + return __builtin_align_up(ptr, alignment); +} + } // namespace gpu } // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/__support/GPU/allocator.h b/system/lib/llvm-libc/src/__support/GPU/allocator.h index 466009aa71981..a7cf8bceef272 100644 --- a/system/lib/llvm-libc/src/__support/GPU/allocator.h +++ b/system/lib/llvm-libc/src/__support/GPU/allocator.h @@ -17,6 +17,8 @@ namespace gpu { void *allocate(uint64_t size); void deallocate(void *ptr); +void *reallocate(void *ptr, uint64_t size); +void *aligned_allocate(uint32_t alignment, uint64_t size); } // namespace gpu } // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/__support/HashTable/randomness.h b/system/lib/llvm-libc/src/__support/HashTable/randomness.h index 6b58a4125f785..7e54c9aa6ad1f 100644 --- a/system/lib/llvm-libc/src/__support/HashTable/randomness.h +++ b/system/lib/llvm-libc/src/__support/HashTable/randomness.h @@ -14,8 +14,8 @@ #include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" #if defined(LIBC_HASHTABLE_USE_GETRANDOM) -#include "src/__support/libc_errno.h" -#include "src/sys/random/getrandom.h" +#include "hdr/errno_macros.h" +#include "src/__support/OSUtil/linux/getrandom.h" #endif namespace LIBC_NAMESPACE_DECL { @@ -35,20 +35,18 @@ LIBC_INLINE uint64_t next_random_seed() { entropy[0] = reinterpret_cast(&entropy); entropy[1] = reinterpret_cast(&state); #if defined(LIBC_HASHTABLE_USE_GETRANDOM) - int errno_backup = libc_errno; size_t count = sizeof(entropy); uint8_t *buffer = reinterpret_cast(entropy); while (count > 0) { - ssize_t len = getrandom(buffer, count, 0); - if (len == -1) { - if (libc_errno == ENOSYS) + auto len = internal::getrandom(buffer, count, 0); + if (!len.has_value()) { + if (len.error() == ENOSYS) break; continue; } - count -= len; - buffer += len; + count -= len.value(); + buffer += len.value(); } - libc_errno = errno_backup; #endif state.update(&entropy, sizeof(entropy)); } diff --git a/system/lib/llvm-libc/src/__support/OSUtil/linux/getrandom.h b/system/lib/llvm-libc/src/__support/OSUtil/linux/getrandom.h new file mode 100644 index 0000000000000..793639472fee7 --- /dev/null +++ b/system/lib/llvm-libc/src/__support/OSUtil/linux/getrandom.h @@ -0,0 +1,35 @@ +//===------------ Implementation of getrandom 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_SRC___SUPPORT_OSUTIL_GETRANDOM_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_GETRANDOM_H + +#include "hdr/types/ssize_t.h" +#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +LIBC_INLINE static ErrorOr getrandom(void *buf, size_t buflen, + unsigned int flags) { + ssize_t ret = + LIBC_NAMESPACE::syscall_impl(SYS_getrandom, buf, buflen, flags); + if (ret < 0) { + return Error(-static_cast(ret)); + } + return ret; +} + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_GETRANDOM_H diff --git a/system/lib/llvm-libc/src/__support/macros/optimization.h b/system/lib/llvm-libc/src/__support/macros/optimization.h index 253843e5e37aa..250a9e060728a 100644 --- a/system/lib/llvm-libc/src/__support/macros/optimization.h +++ b/system/lib/llvm-libc/src/__support/macros/optimization.h @@ -10,7 +10,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_OPTIMIZATION_H #define LLVM_LIBC_SRC___SUPPORT_MACROS_OPTIMIZATION_H -#include "src/__support/macros/attributes.h" // LIBC_INLINE +#include "src/__support/macros/attributes.h" // LIBC_INLINE #include "src/__support/macros/config.h" #include "src/__support/macros/properties/compiler.h" // LIBC_COMPILER_IS_CLANG @@ -30,8 +30,10 @@ LIBC_INLINE constexpr bool expects_bool_condition(T value, T expected) { #if defined(LIBC_COMPILER_IS_CLANG) #define LIBC_LOOP_NOUNROLL _Pragma("nounroll") +#define LIBC_LOOP_UNROLL _Pragma("unroll") #elif defined(LIBC_COMPILER_IS_GCC) #define LIBC_LOOP_NOUNROLL _Pragma("GCC unroll 0") +#define LIBC_LOOP_UNROLL _Pragma("GCC unroll 2048") #else #error "Unhandled compiler" #endif @@ -63,4 +65,12 @@ LIBC_INLINE constexpr bool expects_bool_condition(T value, T expected) { #define LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT #endif +#if (LIBC_MATH & LIBC_MATH_NO_ERRNO) +#define LIBC_MATH_HAS_NO_ERRNO +#endif + +#if (LIBC_MATH & LIBC_MATH_NO_EXCEPT) +#define LIBC_MATH_HAS_NO_EXCEPT +#endif + #endif // LLVM_LIBC_SRC___SUPPORT_MACROS_OPTIMIZATION_H diff --git a/system/lib/llvm-libc/src/__support/macros/properties/cpu_features.h b/system/lib/llvm-libc/src/__support/macros/properties/cpu_features.h index 3677e1fc3275c..cdb2df97b2b9a 100644 --- a/system/lib/llvm-libc/src/__support/macros/properties/cpu_features.h +++ b/system/lib/llvm-libc/src/__support/macros/properties/cpu_features.h @@ -61,15 +61,15 @@ #if defined(__riscv_flen) // https://github.com/riscv-non-isa/riscv-c-api-doc/blob/main/src/c-api.adoc -#if (__riscv_flen & 0x10) +#if defined(__riscv_zfhmin) #define LIBC_TARGET_CPU_HAS_RISCV_FPU_HALF #define LIBC_TARGET_CPU_HAS_FPU_HALF #endif // LIBC_TARGET_CPU_HAS_RISCV_FPU_HALF -#if (__riscv_flen & 0x20) +#if (__riscv_flen >= 32) #define LIBC_TARGET_CPU_HAS_RISCV_FPU_FLOAT #define LIBC_TARGET_CPU_HAS_FPU_FLOAT #endif // LIBC_TARGET_CPU_HAS_RISCV_FPU_FLOAT -#if (__riscv_flen & 0x40) +#if (__riscv_flen >= 64) #define LIBC_TARGET_CPU_HAS_RISCV_FPU_DOUBLE #define LIBC_TARGET_CPU_HAS_FPU_DOUBLE #endif // LIBC_TARGET_CPU_HAS_RISCV_FPU_DOUBLE diff --git a/system/lib/llvm-libc/src/__support/macros/properties/types.h b/system/lib/llvm-libc/src/__support/macros/properties/types.h index 6293b9d4d292a..aec4a488c3cba 100644 --- a/system/lib/llvm-libc/src/__support/macros/properties/types.h +++ b/system/lib/llvm-libc/src/__support/macros/properties/types.h @@ -10,9 +10,10 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_TYPES_H #define LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_TYPES_H -#include "hdr/float_macros.h" // LDBL_MANT_DIG +#include "hdr/float_macros.h" // LDBL_MANT_DIG #include "include/llvm-libc-macros/float16-macros.h" // LIBC_TYPES_HAS_FLOAT16 #include "include/llvm-libc-types/float128.h" // float128 +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL #include "src/__support/macros/properties/architectures.h" #include "src/__support/macros/properties/compiler.h" #include "src/__support/macros/properties/cpu_features.h" @@ -58,4 +59,14 @@ using float16 = _Float16; // LIBC_TYPES_HAS_FLOAT128 and 'float128' type are provided by // "include/llvm-libc-types/float128.h" +// -- bfloat16 support --------------------------------------------------------- + +namespace LIBC_NAMESPACE_DECL { +namespace fputil { +struct BFloat16; +} +} // namespace LIBC_NAMESPACE_DECL + +using bfloat16 = LIBC_NAMESPACE::fputil::BFloat16; + #endif // LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_TYPES_H diff --git a/system/lib/llvm-libc/src/__support/math/expf16.h b/system/lib/llvm-libc/src/__support/math/expf16.h new file mode 100644 index 0000000000000..ded28c7dba500 --- /dev/null +++ b/system/lib/llvm-libc/src/__support/math/expf16.h @@ -0,0 +1,141 @@ +//===-- Implementation header for expf16 ------------------------*- 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_EXPF16_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_EXPF16_H + +#include "include/llvm-libc-macros/float16-macros.h" + +#ifdef LIBC_TYPES_HAS_FLOAT16 + +#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/rounding_mode.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" + +#include "expf16_utils.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +static constexpr float16 expf16(float16 x) { +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + constexpr fputil::ExceptValues EXPF16_EXCEPTS_LO = {{ + // (input, RZ output, RU offset, RD offset, RN offset) + // x = 0x1.de4p-8, expf16(x) = 0x1.01cp+0 (RZ) + {0x1f79U, 0x3c07U, 1U, 0U, 0U}, + // x = 0x1.73cp-6, expf16(x) = 0x1.05cp+0 (RZ) + {0x25cfU, 0x3c17U, 1U, 0U, 0U}, + }}; + + constexpr fputil::ExceptValues EXPF16_EXCEPTS_HI = {{ + // (input, RZ output, RU offset, RD offset, RN offset) + // x = 0x1.c34p+0, expf16(x) = 0x1.74cp+2 (RZ) + {0x3f0dU, 0x45d3U, 1U, 0U, 1U}, + // x = -0x1.488p-5, expf16(x) = 0x1.ebcp-1 (RZ) + {0xa922U, 0x3bafU, 1U, 0U, 0U}, + // x = -0x1.55p-5, expf16(x) = 0x1.ebp-1 (RZ) + {0xa954U, 0x3bacU, 1U, 0U, 0U}, + }}; +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + using FPBits = fputil::FPBits; + FPBits x_bits(x); + + uint16_t x_u = x_bits.uintval(); + uint16_t x_abs = x_u & 0x7fffU; + + // When 0 < |x| <= 2^(-5), or |x| >= 12, or x is NaN. + if (LIBC_UNLIKELY(x_abs <= 0x2800U || x_abs >= 0x4a00U)) { + // exp(NaN) = NaN + if (x_bits.is_nan()) { + if (x_bits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + return x; + } + + // When x >= 12. + if (x_bits.is_pos() && x_abs >= 0x4a00U) { + // exp(+inf) = +inf + if (x_bits.is_inf()) + return FPBits::inf().get_val(); + + switch (fputil::quick_get_round()) { + case FE_TONEAREST: + case FE_UPWARD: + fputil::set_errno_if_required(ERANGE); + fputil::raise_except_if_required(FE_OVERFLOW); + return FPBits::inf().get_val(); + default: + return FPBits::max_normal().get_val(); + } + } + + // When x <= -18. + if (x_u >= 0xcc80U) { + // exp(-inf) = +0 + if (x_bits.is_inf()) + return FPBits::zero().get_val(); + + fputil::set_errno_if_required(ERANGE); + fputil::raise_except_if_required(FE_UNDERFLOW | FE_INEXACT); + + switch (fputil::quick_get_round()) { + case FE_UPWARD: + return FPBits::min_subnormal().get_val(); + default: + return FPBits::zero().get_val(); + } + } + + // When 0 < |x| <= 2^(-5). + if (x_abs <= 0x2800U && !x_bits.is_zero()) { +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + if (auto r = EXPF16_EXCEPTS_LO.lookup(x_u); LIBC_UNLIKELY(r.has_value())) + return r.value(); +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + float xf = x; + // Degree-3 minimax polynomial generated by Sollya with the following + // commands: + // > display = hexadecimal; + // > P = fpminimax(expm1(x)/x, 2, [|SG...|], [-2^-5, 2^-5]); + // > 1 + x * P; + return fputil::cast( + fputil::polyeval(xf, 0x1p+0f, 0x1p+0f, 0x1.0004p-1f, 0x1.555778p-3f)); + } + } + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + if (auto r = EXPF16_EXCEPTS_HI.lookup(x_u); LIBC_UNLIKELY(r.has_value())) + return r.value(); +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + // exp(x) = exp(hi + mid) * exp(lo) + auto [exp_hi_mid, exp_lo] = exp_range_reduction(x); + return fputil::cast(exp_hi_mid * exp_lo); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT16 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXPF16_H diff --git a/system/lib/llvm-libc/src/__support/math/expf16_utils.h b/system/lib/llvm-libc/src/__support/math/expf16_utils.h new file mode 100644 index 0000000000000..bebb72b09b886 --- /dev/null +++ b/system/lib/llvm-libc/src/__support/math/expf16_utils.h @@ -0,0 +1,89 @@ +//===-- Common utils for expf16 functions -----------------------*- 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_EXPF16_UTILS_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_EXPF16_UTILS_H + +#include "include/llvm-libc-macros/float16-macros.h" + +#ifdef LIBC_TYPES_HAS_FLOAT16 + +#include "src/__support/CPP/array.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE_DECL { + +// Generated by Sollya with the following commands: +// > display = hexadecimal; +// > for i from -18 to 12 do print(round(exp(i), SG, RN)); +static constexpr cpp::array EXP_HI = { + 0x1.05a628p-26f, 0x1.639e32p-25f, 0x1.e355bcp-24f, 0x1.4875cap-22f, + 0x1.be6c7p-21f, 0x1.2f6054p-19f, 0x1.9c54c4p-18f, 0x1.183542p-16f, + 0x1.7cd79cp-15f, 0x1.02cf22p-13f, 0x1.5fc21p-12f, 0x1.de16bap-11f, + 0x1.44e52p-9f, 0x1.b993fep-8f, 0x1.2c155cp-6f, 0x1.97db0cp-5f, + 0x1.152aaap-3f, 0x1.78b564p-2f, 0x1p+0f, 0x1.5bf0a8p+1f, + 0x1.d8e64cp+2f, 0x1.415e5cp+4f, 0x1.b4c902p+5f, 0x1.28d38ap+7f, + 0x1.936dc6p+8f, 0x1.122886p+10f, 0x1.749ea8p+11f, 0x1.fa7158p+12f, + 0x1.5829dcp+14f, 0x1.d3c448p+15f, 0x1.3de166p+17f, +}; + +// Generated by Sollya with the following commands: +// > display = hexadecimal; +// > for i from 0 to 7 do print(round(exp(i * 2^-3), SG, RN)); +static constexpr cpp::array EXP_MID = { + 0x1p+0f, 0x1.221604p+0f, 0x1.48b5e4p+0f, 0x1.747a52p+0f, + 0x1.a61298p+0f, 0x1.de455ep+0f, 0x1.0ef9dcp+1f, 0x1.330e58p+1f, +}; + +struct ExpRangeReduction { + float exp_hi_mid; + float exp_lo; +}; + +static constexpr ExpRangeReduction exp_range_reduction(float16 x) { + // For -18 < x < 12, to compute exp(x), we perform the following range + // reduction: find hi, mid, lo, such that: + // x = hi + mid + lo, in which + // hi is an integer, + // mid * 2^3 is an integer, + // -2^(-4) <= lo < 2^(-4). + // In particular, + // hi + mid = round(x * 2^3) * 2^(-3). + // Then, + // exp(x) = exp(hi + mid + lo) = exp(hi) * exp(mid) * exp(lo). + // We store exp(hi) and exp(mid) in the lookup tables EXP_HI and EXP_MID + // respectively. exp(lo) is computed using a degree-3 minimax polynomial + // generated by Sollya. + + float xf = x; + float kf = fputil::nearest_integer(xf * 0x1.0p+3f); + int x_hi_mid = static_cast(kf); + int x_hi = x_hi_mid >> 3; + int x_mid = x_hi_mid & 0x7; + // lo = x - (hi + mid) = round(x * 2^3) * (-2^(-3)) + x + float lo = fputil::multiply_add(kf, -0x1.0p-3f, xf); + + float exp_hi = EXP_HI[x_hi + 18]; + float exp_mid = EXP_MID[x_mid]; + // Degree-3 minimax polynomial generated by Sollya with the following + // commands: + // > display = hexadecimal; + // > P = fpminimax(expm1(x)/x, 2, [|SG...|], [-2^-4, 2^-4]); + // > 1 + x * P; + float exp_lo = + fputil::polyeval(lo, 0x1p+0f, 0x1p+0f, 0x1.001p-1f, 0x1.555ddep-3f); + return {exp_hi * exp_mid, exp_lo}; +} + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT16 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXPF16_UTILS_H diff --git a/system/lib/llvm-libc/src/__support/math/frexpf.h b/system/lib/llvm-libc/src/__support/math/frexpf.h new file mode 100644 index 0000000000000..4d2f4948f2af6 --- /dev/null +++ b/system/lib/llvm-libc/src/__support/math/frexpf.h @@ -0,0 +1,28 @@ +//===-- Implementation header for frexpf ------------------------*- 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_FREXPF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_FREXPF_H + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +static constexpr float frexpf(float x, int *exp) { + return fputil::frexp(x, *exp); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_FREXPF_H diff --git a/system/lib/llvm-libc/src/__support/math/frexpf128.h b/system/lib/llvm-libc/src/__support/math/frexpf128.h new file mode 100644 index 0000000000000..2fd5bc4318e28 --- /dev/null +++ b/system/lib/llvm-libc/src/__support/math/frexpf128.h @@ -0,0 +1,34 @@ +//===-- Implementation header for expf --------------------------*- 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_FREXPF128_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_FREXPF128_H + +#include "include/llvm-libc-types/float128.h" + +#ifdef LIBC_TYPES_HAS_FLOAT128 + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +static constexpr float128 frexpf128(float128 x, int *exp) { + return fputil::frexp(x, *exp); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT128 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_FREXPF128_H diff --git a/system/lib/llvm-libc/src/__support/math/frexpf16.h b/system/lib/llvm-libc/src/__support/math/frexpf16.h new file mode 100644 index 0000000000000..8deeba0f43e3a --- /dev/null +++ b/system/lib/llvm-libc/src/__support/math/frexpf16.h @@ -0,0 +1,34 @@ +//===-- Implementation header for frexpf16 ----------------------*- 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_FREXPF16_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_FREXPF16_H + +#include "include/llvm-libc-macros/float16-macros.h" + +#ifdef LIBC_TYPES_HAS_FLOAT16 + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +static constexpr float16 frexpf16(float16 x, int *exp) { + return fputil::frexp(x, *exp); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT16 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_FREXPF16_H diff --git a/system/lib/llvm-libc/src/__support/math/ldexpf.h b/system/lib/llvm-libc/src/__support/math/ldexpf.h new file mode 100644 index 0000000000000..3a5ec1d471337 --- /dev/null +++ b/system/lib/llvm-libc/src/__support/math/ldexpf.h @@ -0,0 +1,28 @@ +//===-- Implementation header for ldexpf ------------------------*- 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_LDEXPF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_LDEXPF_H + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +static constexpr float ldexpf(float x, int exp) { + return fputil::ldexp(x, exp); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LDEXPF_H diff --git a/system/lib/llvm-libc/src/__support/math/ldexpf128.h b/system/lib/llvm-libc/src/__support/math/ldexpf128.h new file mode 100644 index 0000000000000..362583093b2f3 --- /dev/null +++ b/system/lib/llvm-libc/src/__support/math/ldexpf128.h @@ -0,0 +1,34 @@ +//===-- Implementation header for ldexpf ------------------------*- 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_LDEXPF128_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_LDEXPF128_H + +#include "include/llvm-libc-types/float128.h" + +#ifdef LIBC_TYPES_HAS_FLOAT128 + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +static constexpr float128 ldexpf128(float128 x, int exp) { + return fputil::ldexp(x, exp); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT128 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LDEXPF128_H diff --git a/system/lib/llvm-libc/src/__support/math/ldexpf16.h b/system/lib/llvm-libc/src/__support/math/ldexpf16.h new file mode 100644 index 0000000000000..fbead87d909a8 --- /dev/null +++ b/system/lib/llvm-libc/src/__support/math/ldexpf16.h @@ -0,0 +1,34 @@ +//===-- Implementation header for ldexpf16 ----------------------*- 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_LDEXPF16_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_LDEXPF16_H + +#include "include/llvm-libc-macros/float16-macros.h" + +#ifdef LIBC_TYPES_HAS_FLOAT16 + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +static constexpr float16 ldexpf16(float16 x, int exp) { + return fputil::ldexp(x, exp); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT16 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LDEXPF16_H diff --git a/system/lib/llvm-libc/src/__support/str_to_float.h b/system/lib/llvm-libc/src/__support/str_to_float.h index 0748e1cb8a8b4..a7dd7ce0ae25a 100644 --- a/system/lib/llvm-libc/src/__support/str_to_float.h +++ b/system/lib/llvm-libc/src/__support/str_to_float.h @@ -1135,7 +1135,7 @@ LIBC_INLINE StrToNumResult strtofloatingpoint(const char *__restrict src) { int error = 0; - size_t index = static_cast(first_non_whitespace(src) - src); + size_t index = first_non_whitespace(src); if (src[index] == '+' || src[index] == '-') { sign = src[index]; diff --git a/system/lib/llvm-libc/src/__support/str_to_integer.h b/system/lib/llvm-libc/src/__support/str_to_integer.h index 76a99a8948941..d332c929f2c31 100644 --- a/system/lib/llvm-libc/src/__support/str_to_integer.h +++ b/system/lib/llvm-libc/src/__support/str_to_integer.h @@ -29,17 +29,16 @@ namespace LIBC_NAMESPACE_DECL { namespace internal { -// Returns a pointer to the first character in src that is not a whitespace +// Returns the idx to the first character in src that is not a whitespace // character (as determined by isspace()) -// TODO: Change from returning a pointer to returning a length. -LIBC_INLINE const char * +LIBC_INLINE size_t first_non_whitespace(const char *__restrict src, size_t src_len = cpp::numeric_limits::max()) { size_t src_cur = 0; while (src_cur < src_len && internal::isspace(src[src_cur])) { ++src_cur; } - return src + src_cur; + return src_cur; } // checks if the next 3 characters of the string pointer are the start of a @@ -96,7 +95,7 @@ strtointeger(const char *__restrict src, int base, if (base < 0 || base == 1 || base > 36) return {0, 0, EINVAL}; - src_cur = static_cast(first_non_whitespace(src, src_len) - src); + src_cur = first_non_whitespace(src, src_len); char result_sign = '+'; if (src[src_cur] == '+' || src[src_cur] == '-') { diff --git a/system/lib/llvm-libc/src/__support/threads/linux/thread.cpp b/system/lib/llvm-libc/src/__support/threads/linux/thread.cpp index 33fc7d14fd38f..baad26aed6851 100644 --- a/system/lib/llvm-libc/src/__support/threads/linux/thread.cpp +++ b/system/lib/llvm-libc/src/__support/threads/linux/thread.cpp @@ -295,7 +295,7 @@ int Thread::run(ThreadStyle style, ThreadRunner runner, void *arg, void *stack, // The clone syscall takes arguments in an architecture specific order. // Also, we want the result of the syscall to be in a register as the child // thread gets a completely different stack after it is created. The stack - // variables from this function will not be availalbe the child thread. + // variables from this function will not be availalbe to the child thread. #if defined(LIBC_TARGET_ARCH_IS_X86_64) long register clone_result asm(CLONE_RESULT_REGISTER); clone_result = LIBC_NAMESPACE::syscall_impl( diff --git a/system/lib/llvm-libc/src/__support/wchar/character_converter.cpp b/system/lib/llvm-libc/src/__support/wchar/character_converter.cpp index 3b9046dfb9a76..15d0f478a18a9 100644 --- a/system/lib/llvm-libc/src/__support/wchar/character_converter.cpp +++ b/system/lib/llvm-libc/src/__support/wchar/character_converter.cpp @@ -6,8 +6,10 @@ // //===----------------------------------------------------------------------===// +#include "hdr/errno_macros.h" #include "hdr/types/char32_t.h" #include "hdr/types/char8_t.h" +#include "hdr/types/size_t.h" #include "src/__support/CPP/bit.h" #include "src/__support/common.h" #include "src/__support/error_or.h" @@ -19,22 +21,45 @@ namespace LIBC_NAMESPACE_DECL { namespace internal { +// This is for utf-8 bytes other than the first byte +constexpr size_t ENCODED_BITS_PER_UTF8 = 6; +// The number of bits per utf-8 byte that actually encode character +// Information not metadata (# of bits excluding the byte headers) +constexpr uint32_t MASK_ENCODED_BITS = + mask_trailing_ones(); +// Maximum value for utf-32 for a utf-8 sequence of a given length +constexpr char32_t MAX_VALUE_PER_UTF8_LEN[] = {0x7f, 0x7ff, 0xffff, 0x10ffff}; +constexpr int MAX_UTF8_LENGTH = 4; + CharacterConverter::CharacterConverter(mbstate *mbstate) { state = mbstate; } void CharacterConverter::clear() { state->partial = 0; - state->bytes_processed = 0; + state->bytes_stored = 0; state->total_bytes = 0; } -bool CharacterConverter::isComplete() { - return state->bytes_processed == state->total_bytes; +bool CharacterConverter::isFull() { + return state->bytes_stored == state->total_bytes && state->total_bytes != 0; +} + +bool CharacterConverter::isEmpty() { return state->bytes_stored == 0; } + +bool CharacterConverter::isValidState() { + if (state->total_bytes > MAX_UTF8_LENGTH) + return false; + + const char32_t max_utf32_value = + state->total_bytes == 0 ? 0 + : MAX_VALUE_PER_UTF8_LEN[state->total_bytes - 1]; + return state->bytes_stored <= state->total_bytes && + state->partial <= max_utf32_value; } int CharacterConverter::push(char8_t utf8_byte) { uint8_t num_ones = static_cast(cpp::countl_one(utf8_byte)); // Checking the first byte if first push - if (state->bytes_processed == 0) { + if (isEmpty()) { // UTF-8 char has 1 byte total if (num_ones == 0) { state->total_bytes = 1; @@ -51,44 +76,41 @@ int CharacterConverter::push(char8_t utf8_byte) { } // Invalid first byte else { - // bytes_processed and total_bytes will always be 0 here + // bytes_stored and total_bytes will always be 0 here state->partial = static_cast(0); - return -1; + return EILSEQ; } state->partial = static_cast(utf8_byte); - state->bytes_processed++; + state->bytes_stored++; return 0; } // Any subsequent push // Adding 6 more bits so need to left shift - constexpr size_t ENCODED_BITS_PER_UTF8 = 6; - if (num_ones == 1 && !isComplete()) { - char32_t byte = - utf8_byte & mask_trailing_ones(); + if (num_ones == 1 && !isFull()) { + char32_t byte = utf8_byte & MASK_ENCODED_BITS; state->partial = state->partial << ENCODED_BITS_PER_UTF8; state->partial |= byte; - state->bytes_processed++; + state->bytes_stored++; return 0; } + // Invalid byte -> reset the state clear(); - return -1; + return EILSEQ; } int CharacterConverter::push(char32_t utf32) { // we can't be partially through a conversion when pushing a utf32 value - if (!isComplete()) + if (!isEmpty()) return -1; state->partial = utf32; - state->bytes_processed = 0; // determine number of utf-8 bytes needed to represent this utf32 value - constexpr char32_t MAX_VALUE_PER_UTF8_LEN[] = {0x7f, 0x7ff, 0xffff, 0x10ffff}; - constexpr int NUM_RANGES = 4; - for (uint8_t i = 0; i < NUM_RANGES; i++) { + for (uint8_t i = 0; i < MAX_UTF8_LENGTH; i++) { if (state->partial <= MAX_VALUE_PER_UTF8_LEN[i]) { state->total_bytes = i + 1; + state->bytes_stored = i + 1; return 0; } } @@ -96,13 +118,13 @@ int CharacterConverter::push(char32_t utf32) { // `utf32` contains a value that is too large to actually represent a valid // unicode character clear(); - return -1; + return EILSEQ; } ErrorOr CharacterConverter::pop_utf32() { // If pop is called too early, do not reset the state, use error to determine // whether enough bytes have been pushed - if (!isComplete() || state->bytes_processed == 0) + if (!isFull()) return Error(-1); char32_t utf32 = state->partial; // reset if successful pop @@ -110,25 +132,24 @@ ErrorOr CharacterConverter::pop_utf32() { return utf32; } +size_t CharacterConverter::sizeAsUTF32() { + return 1; // a single utf-32 value can fit an entire character +} + +size_t CharacterConverter::sizeAsUTF8() { return state->total_bytes; } + ErrorOr CharacterConverter::pop_utf8() { - if (isComplete()) + if (isEmpty()) return Error(-1); constexpr char8_t FIRST_BYTE_HEADERS[] = {0, 0xC0, 0xE0, 0xF0}; constexpr char8_t CONTINUING_BYTE_HEADER = 0x80; - // the number of bits per utf-8 byte that actually encode character - // information not metadata (# of bits excluding the byte headers) - constexpr size_t ENCODED_BITS_PER_UTF8 = 6; - constexpr int MASK_ENCODED_BITS = - mask_trailing_ones(); - char32_t output; // Shift to get the next 6 bits from the utf32 encoding - const size_t shift_amount = - (state->total_bytes - state->bytes_processed - 1) * ENCODED_BITS_PER_UTF8; - if (state->bytes_processed == 0) { + const size_t shift_amount = (state->bytes_stored - 1) * ENCODED_BITS_PER_UTF8; + if (isFull()) { /* Choose the correct set of most significant bits to encode the length of the utf8 sequence. The remaining bits contain the most significant @@ -142,7 +163,10 @@ ErrorOr CharacterConverter::pop_utf8() { ((state->partial >> shift_amount) & MASK_ENCODED_BITS); } - state->bytes_processed++; + state->bytes_stored--; + if (state->bytes_stored == 0) + clear(); + return static_cast(output); } diff --git a/system/lib/llvm-libc/src/__support/wchar/character_converter.h b/system/lib/llvm-libc/src/__support/wchar/character_converter.h index c4ba7cf6b689f..b6d918f2d2edc 100644 --- a/system/lib/llvm-libc/src/__support/wchar/character_converter.h +++ b/system/lib/llvm-libc/src/__support/wchar/character_converter.h @@ -11,6 +11,7 @@ #include "hdr/types/char32_t.h" #include "hdr/types/char8_t.h" +#include "hdr/types/size_t.h" #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/wchar/mbstate.h" @@ -26,7 +27,12 @@ class CharacterConverter { CharacterConverter(mbstate *mbstate); void clear(); - bool isComplete(); + bool isFull(); + bool isEmpty(); + bool isValidState(); + + size_t sizeAsUTF32(); + size_t sizeAsUTF8(); int push(char8_t utf8_byte); int push(char32_t utf32); diff --git a/system/lib/llvm-libc/src/__support/wchar/mbrtowc.cpp b/system/lib/llvm-libc/src/__support/wchar/mbrtowc.cpp new file mode 100644 index 0000000000000..90ba934c42b69 --- /dev/null +++ b/system/lib/llvm-libc/src/__support/wchar/mbrtowc.cpp @@ -0,0 +1,52 @@ +//===-- Implementation for mbrtowc 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 +// +//===----------------------------------------------------------------------===// + +#include "src/__support/wchar/mbrtowc.h" +#include "hdr/errno_macros.h" +#include "hdr/types/mbstate_t.h" +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include "src/__support/wchar/character_converter.h" +#include "src/__support/wchar/mbstate.h" + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +ErrorOr mbrtowc(wchar_t *__restrict pwc, const char *__restrict s, + size_t n, mbstate *__restrict ps) { + CharacterConverter char_conv(ps); + if (!char_conv.isValidState()) + return Error(EINVAL); + if (s == nullptr) + return 0; + size_t i = 0; + // Reading in bytes until we have a complete wc or error + for (; i < n && !char_conv.isFull(); ++i) { + int err = char_conv.push(static_cast(s[i])); + // Encoding error + if (err == EILSEQ) + return Error(err); + } + auto wc = char_conv.pop_utf32(); + if (wc.has_value()) { + *pwc = wc.value(); + // null terminator -> return 0 + if (wc.value() == L'\0') + return 0; + return i; + } + // Incomplete but potentially valid + return -2; +} + +} // namespace internal + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/__support/wchar/mbrtowc.h b/system/lib/llvm-libc/src/__support/wchar/mbrtowc.h new file mode 100644 index 0000000000000..37329ee61beac --- /dev/null +++ b/system/lib/llvm-libc/src/__support/wchar/mbrtowc.h @@ -0,0 +1,29 @@ +//===-- Implementation header for mbrtowc 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_SRC___SUPPORT_WCHAR_MBRTOWC +#define LLVM_LIBC_SRC___SUPPORT_WCHAR_MBRTOWC + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include "src/__support/wchar/mbstate.h" + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +ErrorOr mbrtowc(wchar_t *__restrict pwc, const char *__restrict s, + size_t n, mbstate *__restrict ps); + +} // namespace internal + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_WCHAR_MBRTOWC diff --git a/system/lib/llvm-libc/src/__support/wchar/mbstate.h b/system/lib/llvm-libc/src/__support/wchar/mbstate.h index fb08fb4eaa188..32304a5215241 100644 --- a/system/lib/llvm-libc/src/__support/wchar/mbstate.h +++ b/system/lib/llvm-libc/src/__support/wchar/mbstate.h @@ -18,17 +18,17 @@ namespace internal { struct mbstate { // store a partial codepoint (in UTF-32) - char32_t partial; + char32_t partial = 0; /* Progress towards a conversion - For utf8 -> utf32, increases with each CharacterConverter::push(utf8_byte) - For utf32 -> utf8, increases with each CharacterConverter::pop_utf8() + Increases with each push(...) until it reaches total_bytes + Decreases with each pop(...) until it reaches 0 */ - uint8_t bytes_processed; + uint8_t bytes_stored = 0; // Total number of bytes that will be needed to represent this character - uint8_t total_bytes; + uint8_t total_bytes = 0; }; } // namespace internal diff --git a/system/lib/llvm-libc/src/__support/wchar/string_converter.h b/system/lib/llvm-libc/src/__support/wchar/string_converter.h new file mode 100644 index 0000000000000..0635bc57bf3e2 --- /dev/null +++ b/system/lib/llvm-libc/src/__support/wchar/string_converter.h @@ -0,0 +1,110 @@ +//===-- Definition of a class for mbstate_t and conversion -----*-- 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_STRING_CONVERTER_H +#define LLVM_LIBC_SRC___SUPPORT_STRING_CONVERTER_H + +#include "hdr/types/char32_t.h" +#include "hdr/types/char8_t.h" +#include "hdr/types/size_t.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/wchar/character_converter.h" +#include "src/__support/wchar/mbstate.h" + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +template class StringConverter { +private: + CharacterConverter cr; + const T *src; + size_t src_len; + size_t src_idx; + + // # of pops we are allowed to perform (essentially size of the dest buffer) + size_t num_to_write; + + ErrorOr pushFullCharacter() { + size_t num_pushed; + for (num_pushed = 0; !cr.isFull() && src_idx + num_pushed < src_len; + ++num_pushed) { + int err = cr.push(src[src_idx + num_pushed]); + if (err != 0) + return Error(err); + } + + // if we aren't able to read a full character from the source string + if (src_idx + num_pushed == src_len && !cr.isFull()) { + src_idx += num_pushed; + return Error(-1); + } + + return num_pushed; + } + +public: + StringConverter(const T *s, mbstate *ps, size_t dstlen, + size_t srclen = SIZE_MAX) + : cr(ps), src(s), src_len(srclen), src_idx(0), num_to_write(dstlen) {} + + // TODO: following functions are almost identical + // look into templating CharacterConverter pop functions + ErrorOr popUTF32() { + if (cr.isEmpty() || src_idx == 0) { + auto src_elements_read = pushFullCharacter(); + if (!src_elements_read.has_value()) + return Error(src_elements_read.error()); + + if (cr.sizeAsUTF32() > num_to_write) { + cr.clear(); + return Error(-1); + } + + src_idx += src_elements_read.value(); + } + + auto out = cr.pop_utf32(); + if (out.has_value() && out.value() == L'\0') + src_len = src_idx; + + num_to_write--; + + return out; + } + + ErrorOr popUTF8() { + if (cr.isEmpty() || src_idx == 0) { + auto src_elements_read = pushFullCharacter(); + if (!src_elements_read.has_value()) + return Error(src_elements_read.error()); + + if (cr.sizeAsUTF8() > num_to_write) { + cr.clear(); + return Error(-1); + } + + src_idx += src_elements_read.value(); + } + + auto out = cr.pop_utf8(); + if (out.has_value() && out.value() == '\0') + src_len = src_idx; + + num_to_write--; + + return out; + } + + size_t getSourceIndex() { return src_idx; } +}; + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_STRING_CONVERTER_H diff --git a/system/lib/llvm-libc/src/__support/wchar/wcrtomb.cpp b/system/lib/llvm-libc/src/__support/wchar/wcrtomb.cpp new file mode 100644 index 0000000000000..fc54bbfc93e0c --- /dev/null +++ b/system/lib/llvm-libc/src/__support/wchar/wcrtomb.cpp @@ -0,0 +1,50 @@ +//===-- Implementation of wcrtomb -----------------------------------------===// +// +// 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/wchar/wcrtomb.h" +#include "src/__support/error_or.h" +#include "src/__support/wchar/character_converter.h" +#include "src/__support/wchar/mbstate.h" + +#include "hdr/errno_macros.h" +#include "hdr/types/char32_t.h" +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/libc_assert.h" + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +ErrorOr wcrtomb(char *__restrict s, wchar_t wc, + mbstate *__restrict ps) { + static_assert(sizeof(wchar_t) == 4); + + CharacterConverter cr(ps); + + if (!cr.isValidState()) + return Error(EINVAL); + + int status = cr.push(static_cast(wc)); + if (status != 0) + return Error(status); + + size_t count = 0; + while (!cr.isEmpty()) { + auto utf8 = cr.pop_utf8(); // can never fail as long as the push succeeded + LIBC_ASSERT(utf8.has_value()); + + *s = utf8.value(); + s++; + count++; + } + return count; +} + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/__support/wchar/wcrtomb.h b/system/lib/llvm-libc/src/__support/wchar/wcrtomb.h new file mode 100644 index 0000000000000..bcd39a92a3b76 --- /dev/null +++ b/system/lib/llvm-libc/src/__support/wchar/wcrtomb.h @@ -0,0 +1,26 @@ +//===-- Implementation header for wcrtomb ---------------------------------===// +// +// 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_WCHAR_WCRTOMB_H +#define LLVM_LIBC_SRC__SUPPORT_WCHAR_WCRTOMB_H + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include "src/__support/wchar/mbstate.h" + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +ErrorOr wcrtomb(char *__restrict s, wchar_t wc, mbstate *__restrict ps); + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC__SUPPORT_WCHAR_WCRTOMB_H diff --git a/system/lib/llvm-libc/src/__support/wcs_to_integer.h b/system/lib/llvm-libc/src/__support/wcs_to_integer.h new file mode 100644 index 0000000000000..4254bd860f77a --- /dev/null +++ b/system/lib/llvm-libc/src/__support/wcs_to_integer.h @@ -0,0 +1,155 @@ +//===-- Widechar string to integer conversion utils -------------*- 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_WCS_TO_INTEGER_H +#define LLVM_LIBC_SRC___SUPPORT_WCS_TO_INTEGER_H + +#include "hdr/errno_macros.h" // For ERANGE +#include "src/__support/CPP/limits.h" +#include "src/__support/CPP/type_traits.h" +#include "src/__support/CPP/type_traits/make_unsigned.h" +#include "src/__support/big_int.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/__support/str_to_num_result.h" +#include "src/__support/uint128.h" +#include "src/__support/wctype_utils.h" + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +// Returns the idx of the first character in src that is not a whitespace +// character (as determined by iswspace()) +LIBC_INLINE size_t +first_non_whitespace(const wchar_t *__restrict src, + size_t src_len = cpp::numeric_limits::max()) { + size_t src_cur = 0; + while (src_cur < src_len && internal::iswspace(src[src_cur])) { + ++src_cur; + } + return src_cur; +} + +// checks if the next 3 characters of the string pointer are the start of a +// hexadecimal number. Does not advance the string pointer. +LIBC_INLINE bool +is_hex_start(const wchar_t *__restrict src, + size_t src_len = cpp::numeric_limits::max()) { + if (src_len < 3) + return false; + return *src == L'0' && towlower(*(src + 1)) == L'x' && iswalnum(*(src + 2)) && + b36_wchar_to_int(*(src + 2)) < 16; +} + +// Takes the address of the string pointer and parses the base from the start of +// it. +LIBC_INLINE int infer_base(const wchar_t *__restrict src, size_t src_len) { + // A hexadecimal number is defined as "the prefix 0x or 0X followed by a + // sequence of the decimal digits and the letters a (or A) through f (or F) + // with values 10 through 15 respectively." (C standard 6.4.4.1) + if (is_hex_start(src, src_len)) + return 16; + // An octal number is defined as "the prefix 0 optionally followed by a + // sequence of the digits 0 through 7 only" (C standard 6.4.4.1) and so any + // number that starts with 0, including just 0, is an octal number. + if (src_len > 0 && src[0] == L'0') + return 8; + // A decimal number is defined as beginning "with a nonzero digit and + // consist[ing] of a sequence of decimal digits." (C standard 6.4.4.1) + return 10; +} + +template +LIBC_INLINE StrToNumResult +wcstointeger(const wchar_t *__restrict src, int base, + const size_t src_len = cpp::numeric_limits::max()) { + using ResultType = make_integral_or_big_int_unsigned_t; + + ResultType result = 0; + + bool is_number = false; + size_t src_cur = 0; + int error_val = 0; + + if (src_len == 0) + return {0, 0, 0}; + + if (base < 0 || base == 1 || base > 36) + return {0, 0, EINVAL}; + + src_cur = first_non_whitespace(src, src_len); + + wchar_t result_sign = L'+'; + if (src[src_cur] == L'+' || src[src_cur] == L'-') { + result_sign = src[src_cur]; + ++src_cur; + } + + if (base == 0) + base = infer_base(src + src_cur, src_len - src_cur); + + if (base == 16 && is_hex_start(src + src_cur, src_len - src_cur)) + src_cur = src_cur + 2; + + constexpr bool IS_UNSIGNED = cpp::is_unsigned_v; + const bool is_positive = (result_sign == L'+'); + + ResultType constexpr NEGATIVE_MAX = + !IS_UNSIGNED ? static_cast(cpp::numeric_limits::max()) + 1 + : cpp::numeric_limits::max(); + ResultType const abs_max = + (is_positive ? cpp::numeric_limits::max() : NEGATIVE_MAX); + ResultType const abs_max_div_by_base = + abs_max / static_cast(base); + + while (src_cur < src_len && iswalnum(src[src_cur])) { + int cur_digit = b36_wchar_to_int(src[src_cur]); + if (cur_digit >= base) + break; + + is_number = true; + ++src_cur; + + // If the number has already hit the maximum value for the current type then + // the result cannot change, but we still need to advance src to the end of + // the number. + if (result == abs_max) { + error_val = ERANGE; + continue; + } + + if (result > abs_max_div_by_base) { + result = abs_max; + error_val = ERANGE; + } else { + result = result * static_cast(base); + } + if (result > abs_max - static_cast(cur_digit)) { + result = abs_max; + error_val = ERANGE; + } else { + result = result + static_cast(cur_digit); + } + } + + ptrdiff_t str_len = is_number ? static_cast(src_cur) : 0; + + if (error_val == ERANGE) { + if (is_positive || IS_UNSIGNED) + return {cpp::numeric_limits::max(), str_len, error_val}; + else // T is signed and there is a negative overflow + return {cpp::numeric_limits::min(), str_len, error_val}; + } + + return {static_cast(is_positive ? result : -result), str_len, error_val}; +} + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_WCS_TO_INTEGER_H diff --git a/system/lib/llvm-libc/src/__support/wctype_utils.h b/system/lib/llvm-libc/src/__support/wctype_utils.h index aa137c278323e..2ae5ec93b2a63 100644 --- a/system/lib/llvm-libc/src/__support/wctype_utils.h +++ b/system/lib/llvm-libc/src/__support/wctype_utils.h @@ -17,6 +17,565 @@ namespace LIBC_NAMESPACE_DECL { namespace internal { +// ----------------------------------------------------------------------------- +// ****************** WARNING ****************** +// ****************** DO NOT TRY TO OPTIMIZE THESE FUNCTIONS! ****************** +// ----------------------------------------------------------------------------- +// This switch/case form is easier for the compiler to understand, and is +// optimized into a form that is almost always the same as or better than +// versions written by hand (see https://godbolt.org/z/qvrebqvvr). Also this +// form makes these functions encoding independent. If you want to rewrite these +// functions, make sure you have benchmarks to show your new solution is faster, +// as well as a way to support non-ASCII character encodings. + +// Similarly, do not change these fumarks to show your new solution is faster, +// as well as a way to support non-Anctions to use case ranges. e.g. +// bool iswlower(wint_t ch) { +// switch(ch) { +// case L'a'...L'z': +// return true; +// } +// } +// This assumes the character ranges are contiguous, which they aren't in +// EBCDIC. Technically we could use some smaller ranges, but that's even harder +// to read. + +LIBC_INLINE static constexpr bool iswlower(wint_t wch) { + switch (wch) { + case L'a': + case L'b': + case L'c': + case L'd': + case L'e': + case L'f': + case L'g': + case L'h': + case L'i': + case L'j': + case L'k': + case L'l': + case L'm': + case L'n': + case L'o': + case L'p': + case L'q': + case L'r': + case L's': + case L't': + case L'u': + case L'v': + case L'w': + case L'x': + case L'y': + case L'z': + return true; + default: + return false; + } +} + +LIBC_INLINE static constexpr bool iswupper(wint_t wch) { + switch (wch) { + case L'A': + case L'B': + case L'C': + case L'D': + case L'E': + case L'F': + case L'G': + case L'H': + case L'I': + case L'J': + case L'K': + case L'L': + case L'M': + case L'N': + case L'O': + case L'P': + case L'Q': + case L'R': + case L'S': + case L'T': + case L'U': + case L'V': + case L'W': + case L'X': + case L'Y': + case L'Z': + return true; + default: + return false; + } +} + +LIBC_INLINE static constexpr bool iswdigit(wint_t wch) { + switch (wch) { + case L'0': + case L'1': + case L'2': + case L'3': + case L'4': + case L'5': + case L'6': + case L'7': + case L'8': + case L'9': + return true; + default: + return false; + } +} + +LIBC_INLINE static constexpr wint_t towlower(wint_t wch) { + switch (wch) { + case L'A': + return L'a'; + case L'B': + return L'b'; + case L'C': + return L'c'; + case L'D': + return L'd'; + case L'E': + return L'e'; + case L'F': + return L'f'; + case L'G': + return L'g'; + case L'H': + return L'h'; + case L'I': + return L'i'; + case L'J': + return L'j'; + case L'K': + return L'k'; + case L'L': + return L'l'; + case L'M': + return L'm'; + case L'N': + return L'n'; + case L'O': + return L'o'; + case L'P': + return L'p'; + case L'Q': + return L'q'; + case L'R': + return L'r'; + case L'S': + return L's'; + case L'T': + return L't'; + case L'U': + return L'u'; + case L'V': + return L'v'; + case L'W': + return L'w'; + case L'X': + return L'x'; + case L'Y': + return L'y'; + case L'Z': + return L'z'; + default: + return wch; + } +} + +LIBC_INLINE static constexpr wint_t towupper(wint_t wch) { + switch (wch) { + case L'a': + return L'A'; + case L'b': + return L'B'; + case L'c': + return L'C'; + case L'd': + return L'D'; + case L'e': + return L'E'; + case L'f': + return L'F'; + case L'g': + return L'G'; + case L'h': + return L'H'; + case L'i': + return L'I'; + case L'j': + return L'J'; + case L'k': + return L'K'; + case L'l': + return L'L'; + case L'm': + return L'M'; + case L'n': + return L'N'; + case L'o': + return L'O'; + case L'p': + return L'P'; + case L'q': + return L'Q'; + case L'r': + return L'R'; + case L's': + return L'S'; + case L't': + return L'T'; + case L'u': + return L'U'; + case L'v': + return L'V'; + case L'w': + return L'W'; + case L'x': + return L'X'; + case L'y': + return L'Y'; + case L'z': + return L'Z'; + default: + return wch; + } +} + +LIBC_INLINE static constexpr bool iswalpha(wint_t wch) { + switch (wch) { + case L'a': + case L'b': + case L'c': + case L'd': + case L'e': + case L'f': + case L'g': + case L'h': + case L'i': + case L'j': + case L'k': + case L'l': + case L'm': + case L'n': + case L'o': + case L'p': + case L'q': + case L'r': + case L's': + case L't': + case L'u': + case L'v': + case L'w': + case L'x': + case L'y': + case L'z': + case L'A': + case L'B': + case L'C': + case L'D': + case L'E': + case L'F': + case L'G': + case L'H': + case L'I': + case L'J': + case L'K': + case L'L': + case L'M': + case L'N': + case L'O': + case L'P': + case L'Q': + case L'R': + case L'S': + case L'T': + case L'U': + case L'V': + case L'W': + case L'X': + case L'Y': + case L'Z': + return true; + default: + return false; + } +} + +LIBC_INLINE static constexpr bool iswalnum(wint_t wch) { + switch (wch) { + case L'a': + case L'b': + case L'c': + case L'd': + case L'e': + case L'f': + case L'g': + case L'h': + case L'i': + case L'j': + case L'k': + case L'l': + case L'm': + case L'n': + case L'o': + case L'p': + case L'q': + case L'r': + case L's': + case L't': + case L'u': + case L'v': + case L'w': + case L'x': + case L'y': + case L'z': + case L'A': + case L'B': + case L'C': + case L'D': + case L'E': + case L'F': + case L'G': + case L'H': + case L'I': + case L'J': + case L'K': + case L'L': + case L'M': + case L'N': + case L'O': + case L'P': + case L'Q': + case L'R': + case L'S': + case L'T': + case L'U': + case L'V': + case L'W': + case L'X': + case L'Y': + case L'Z': + case L'0': + case L'1': + case L'2': + case L'3': + case L'4': + case L'5': + case L'6': + case L'7': + case L'8': + case L'9': + return true; + default: + return false; + } +} + +LIBC_INLINE static constexpr int b36_wchar_to_int(wint_t wch) { + switch (wch) { + case L'0': + return 0; + case L'1': + return 1; + case L'2': + return 2; + case L'3': + return 3; + case L'4': + return 4; + case L'5': + return 5; + case L'6': + return 6; + case L'7': + return 7; + case L'8': + return 8; + case L'9': + return 9; + case L'a': + case L'A': + return 10; + case L'b': + case L'B': + return 11; + case L'c': + case L'C': + return 12; + case L'd': + case L'D': + return 13; + case L'e': + case L'E': + return 14; + case L'f': + case L'F': + return 15; + case L'g': + case L'G': + return 16; + case L'h': + case L'H': + return 17; + case L'i': + case L'I': + return 18; + case L'j': + case L'J': + return 19; + case L'k': + case L'K': + return 20; + case L'l': + case L'L': + return 21; + case L'm': + case L'M': + return 22; + case L'n': + case L'N': + return 23; + case L'o': + case L'O': + return 24; + case L'p': + case L'P': + return 25; + case L'q': + case L'Q': + return 26; + case L'r': + case L'R': + return 27; + case L's': + case L'S': + return 28; + case L't': + case L'T': + return 29; + case L'u': + case L'U': + return 30; + case L'v': + case L'V': + return 31; + case L'w': + case L'W': + return 32; + case L'x': + case L'X': + return 33; + case L'y': + case L'Y': + return 34; + case L'z': + case L'Z': + return 35; + default: + return 0; + } +} + +LIBC_INLINE static constexpr wint_t int_to_b36_wchar(int num) { + // Can't actually use LIBC_ASSERT here because it depends on integer_to_string + // which depends on this. + + // LIBC_ASSERT(num < 36); + switch (num) { + case 0: + return L'0'; + case 1: + return L'1'; + case 2: + return L'2'; + case 3: + return L'3'; + case 4: + return L'4'; + case 5: + return L'5'; + case 6: + return L'6'; + case 7: + return L'7'; + case 8: + return L'8'; + case 9: + return L'9'; + case 10: + return L'a'; + case 11: + return L'b'; + case 12: + return L'c'; + case 13: + return L'd'; + case 14: + return L'e'; + case 15: + return L'f'; + case 16: + return L'g'; + case 17: + return L'h'; + case 18: + return L'i'; + case 19: + return L'j'; + case 20: + return L'k'; + case 21: + return L'l'; + case 22: + return L'm'; + case 23: + return L'n'; + case 24: + return L'o'; + case 25: + return L'p'; + case 26: + return L'q'; + case 27: + return L'r'; + case 28: + return L's'; + case 29: + return L't'; + case 30: + return L'u'; + case 31: + return L'v'; + case 32: + return L'w'; + case 33: + return L'x'; + case 34: + return L'y'; + case 35: + return L'z'; + default: + return L'!'; + } +} + +LIBC_INLINE static constexpr bool iswspace(wint_t wch) { + switch (wch) { + case L' ': + case L'\t': + case L'\n': + case L'\v': + case L'\f': + case L'\r': + return true; + default: + return false; + } +} + // ------------------------------------------------------ // Rationale: Since these classification functions are // called in other functions, we will avoid the overhead diff --git a/system/lib/llvm-libc/src/math/generic/frexpf.cpp b/system/lib/llvm-libc/src/math/generic/frexpf.cpp index 09227badc3417..783880d44ce61 100644 --- a/system/lib/llvm-libc/src/math/generic/frexpf.cpp +++ b/system/lib/llvm-libc/src/math/generic/frexpf.cpp @@ -7,14 +7,13 @@ //===----------------------------------------------------------------------===// #include "src/math/frexpf.h" -#include "src/__support/FPUtil/ManipulationFunctions.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" + +#include "src/__support/math/frexpf.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(float, frexpf, (float x, int *exp)) { - return fputil::frexp(x, *exp); + return math::frexpf(x, exp); } } // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/math/generic/frexpf128.cpp b/system/lib/llvm-libc/src/math/generic/frexpf128.cpp index eb816c4769707..55f7afcf4aea5 100644 --- a/system/lib/llvm-libc/src/math/generic/frexpf128.cpp +++ b/system/lib/llvm-libc/src/math/generic/frexpf128.cpp @@ -7,14 +7,13 @@ //===----------------------------------------------------------------------===// #include "src/math/frexpf128.h" -#include "src/__support/FPUtil/ManipulationFunctions.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" + +#include "src/__support/math/frexpf128.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(float128, frexpf128, (float128 x, int *exp)) { - return fputil::frexp(x, *exp); + return math::frexpf128(x, exp); } } // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/math/generic/ldexpf.cpp b/system/lib/llvm-libc/src/math/generic/ldexpf.cpp index 63c5d219f7a79..c5f30bb725e6b 100644 --- a/system/lib/llvm-libc/src/math/generic/ldexpf.cpp +++ b/system/lib/llvm-libc/src/math/generic/ldexpf.cpp @@ -7,14 +7,12 @@ //===----------------------------------------------------------------------===// #include "src/math/ldexpf.h" -#include "src/__support/FPUtil/ManipulationFunctions.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/ldexpf.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(float, ldexpf, (float x, int exp)) { - return fputil::ldexp(x, exp); + return math::ldexpf(x, exp); } } // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/math/generic/ldexpf128.cpp b/system/lib/llvm-libc/src/math/generic/ldexpf128.cpp index 03b1a2d2032e2..40afa5b285bcd 100644 --- a/system/lib/llvm-libc/src/math/generic/ldexpf128.cpp +++ b/system/lib/llvm-libc/src/math/generic/ldexpf128.cpp @@ -7,14 +7,13 @@ //===----------------------------------------------------------------------===// #include "src/math/ldexpf128.h" -#include "src/__support/FPUtil/ManipulationFunctions.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" + +#include "src/__support/math/ldexpf128.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(float128, ldexpf128, (float128 x, int exp)) { - return fputil::ldexp(x, exp); + return math::ldexpf128(x, exp); } } // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/math/generic/log2f.cpp b/system/lib/llvm-libc/src/math/generic/log2f.cpp index b25ec41f277b6..cff718eec2169 100644 --- a/system/lib/llvm-libc/src/math/generic/log2f.cpp +++ b/system/lib/llvm-libc/src/math/generic/log2f.cpp @@ -79,7 +79,7 @@ LLVM_LIBC_FUNCTION(float, log2f, (float x)) { } if (xbits.is_neg() && !xbits.is_nan()) { fputil::set_errno_if_required(EDOM); - fputil::raise_except(FE_INVALID); + fputil::raise_except_if_required(FE_INVALID); return FPBits::quiet_nan().get_val(); } if (xbits.is_inf_or_nan()) { diff --git a/system/lib/llvm-libc/src/math/generic/tanpif.cpp b/system/lib/llvm-libc/src/math/generic/tanpif.cpp new file mode 100644 index 0000000000000..58d46c9481aa5 --- /dev/null +++ b/system/lib/llvm-libc/src/math/generic/tanpif.cpp @@ -0,0 +1,106 @@ +//===-- Single-precision tanpi 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/tanpif.h" +#include "sincosf_utils.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/cast.h" +#include "src/__support/FPUtil/except_value_utils.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY + +namespace LIBC_NAMESPACE_DECL { + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS +constexpr size_t N_EXCEPTS = 3; + +constexpr fputil::ExceptValues TANPIF_EXCEPTS{{ + // (input, RZ output, RU offset, RD offset, RN offset) + {0x38F26685, 0x39BE6182, 1, 0, 0}, + {0x3E933802, 0x3FA267DD, 1, 0, 0}, + {0x3F3663FF, 0xBFA267DD, 0, 1, 0}, +}}; +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +LLVM_LIBC_FUNCTION(float, tanpif, (float x)) { + using FPBits = typename fputil::FPBits; + FPBits xbits(x); + + uint32_t x_u = xbits.uintval(); + uint32_t x_abs = x_u & 0x7fff'ffffU; + double xd = static_cast(xbits.get_val()); + + // Handle exceptional values + if (LIBC_UNLIKELY(x_abs <= 0x3F3663FF)) { + if (LIBC_UNLIKELY(x_abs == 0U)) + return x; + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + bool x_sign = x_u >> 31; + + if (auto r = TANPIF_EXCEPTS.lookup_odd(x_abs, x_sign); + LIBC_UNLIKELY(r.has_value())) + return r.value(); +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + } + + // Numbers greater or equal to 2^23 are always integers, or infinity, or NaN + if (LIBC_UNLIKELY(x_abs >= 0x4B00'0000)) { + // x is inf or NaN. + if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + if (x_abs == 0x7f80'0000U) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + } + + return x + FPBits::quiet_nan().get_val(); + } + + return FPBits::zero(xbits.sign()).get_val(); + } + + // Range reduction: + // For |x| > 1/32, we perform range reduction as follows: + // Find k and y such that: + // x = (k + y) * 1/32 + // k is an integer + // |y| < 0.5 + // + // This is done by performing: + // k = round(x * 32) + // y = x * 32 - k + // + // Once k and y are computed, we then deduce the answer by the formula: + // tan(x) = sin(x) / cos(x) + // = (sin_y * cos_k + cos_y * sin_k) / (cos_y * cos_k - sin_y * sin_k) + double sin_k, cos_k, sin_y, cosm1_y; + sincospif_eval(xd, sin_k, cos_k, sin_y, cosm1_y); + + if (LIBC_UNLIKELY(sin_y == 0 && cos_k == 0)) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_DIVBYZERO); + + int32_t x_mp5_i = static_cast(xd - 0.5); + return FPBits::inf((x_mp5_i & 0x1) ? Sign::NEG : Sign::POS).get_val(); + } + + using fputil::multiply_add; + return fputil::cast( + multiply_add(sin_y, cos_k, multiply_add(cosm1_y, sin_k, sin_k)) / + multiply_add(sin_y, -sin_k, multiply_add(cosm1_y, cos_k, cos_k))); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/math/tanpif.h b/system/lib/llvm-libc/src/math/tanpif.h new file mode 100644 index 0000000000000..59e6dcfa9ff73 --- /dev/null +++ b/system/lib/llvm-libc/src/math/tanpif.h @@ -0,0 +1,20 @@ +//===-- Implementation header for tanpif ------------------------*- 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_TANPIF_H +#define LLVM_LIBC_SRC_MATH_TANPIF_H + +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +float tanpif(float x); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_TANPIF_H diff --git a/system/lib/llvm-libc/src/stdlib/gpu/aligned_alloc.cpp b/system/lib/llvm-libc/src/stdlib/gpu/aligned_alloc.cpp index cd2c7e55128fe..34a7eae618fec 100644 --- a/system/lib/llvm-libc/src/stdlib/gpu/aligned_alloc.cpp +++ b/system/lib/llvm-libc/src/stdlib/gpu/aligned_alloc.cpp @@ -15,15 +15,15 @@ namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(void *, aligned_alloc, (size_t alignment, size_t size)) { - if ((alignment & -alignment) != alignment) - return nullptr; - - void *ptr = gpu::allocate(size); - if ((reinterpret_cast(ptr) & (alignment - 1)) != 0) { - gpu::deallocate(ptr); - return nullptr; - } - return ptr; + // FIXME: NVIDIA targets currently use the built-in 'malloc' which we cannot + // reason with. But we still need to provide this function for compatibility. +#ifndef LIBC_TARGET_ARCH_IS_NVPTX + return gpu::aligned_allocate(static_cast(alignment), size); +#else + (void)alignment; + (void)size; + return nullptr; +#endif } } // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/stdlib/gpu/realloc.cpp b/system/lib/llvm-libc/src/stdlib/gpu/realloc.cpp index 4fd4d6b278179..97ad1b3bbeff2 100644 --- a/system/lib/llvm-libc/src/stdlib/gpu/realloc.cpp +++ b/system/lib/llvm-libc/src/stdlib/gpu/realloc.cpp @@ -16,17 +16,15 @@ namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(void *, realloc, (void *ptr, size_t size)) { - if (ptr == nullptr) - return gpu::allocate(size); - - void *newmem = gpu::allocate(size); - if (newmem == nullptr) - return nullptr; - - // This will copy garbage if it goes beyond the old allocation size. - inline_memcpy(newmem, ptr, size); - gpu::deallocate(ptr); - return newmem; + // FIXME: NVIDIA targets currently use the built-in 'malloc' which we cannot + // reason with. But we still need to provide this function for compatibility. +#ifndef LIBC_TARGET_ARCH_IS_NVPTX + return gpu::reallocate(ptr, size); +#else + (void)ptr; + (void)size; + return nullptr; +#endif } } // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/string/memory_utils/arm/inline_memcpy.h b/system/lib/llvm-libc/src/string/memory_utils/arm/inline_memcpy.h new file mode 100644 index 0000000000000..61efebe29b485 --- /dev/null +++ b/system/lib/llvm-libc/src/string/memory_utils/arm/inline_memcpy.h @@ -0,0 +1,217 @@ +//===-- Memcpy implementation for arm ---------------------------*- 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_STRING_MEMORY_UTILS_ARM_INLINE_MEMCPY_H +#define LLVM_LIBC_SRC_STRING_MEMORY_UTILS_ARM_INLINE_MEMCPY_H + +#include "src/__support/macros/attributes.h" // LIBC_INLINE +#include "src/__support/macros/optimization.h" // LIBC_LOOP_NOUNROLL +#include "src/string/memory_utils/utils.h" // memcpy_inline, distance_to_align + +#include // size_t + +// https://libc.llvm.org/compiler_support.html +// Support for [[likely]] / [[unlikely]] +// [X] GCC 12.2 +// [X] Clang 12 +// [ ] Clang 11 +#define LIBC_ATTR_LIKELY [[likely]] +#define LIBC_ATTR_UNLIKELY [[unlikely]] + +#if defined(LIBC_COMPILER_IS_CLANG) +#if LIBC_COMPILER_CLANG_VER < 1200 +#undef LIBC_ATTR_LIKELY +#undef LIBC_ATTR_UNLIKELY +#define LIBC_ATTR_LIKELY +#define LIBC_ATTR_UNLIKELY +#endif +#endif + +namespace LIBC_NAMESPACE_DECL { + +namespace { + +LIBC_INLINE_VAR constexpr size_t kWordSize = sizeof(uint32_t); + +enum Strategy { + ForceWordLdStChain, + AssumeWordAligned, + AssumeUnaligned, +}; + +template +LIBC_INLINE void copy_and_bump_pointers(Ptr &dst, CPtr &src) { + if constexpr (strategy == AssumeUnaligned) { + memcpy_inline(assume_aligned<1>(dst), assume_aligned<1>(src)); + } else if constexpr (strategy == AssumeWordAligned) { + static_assert(bytes >= kWordSize); + memcpy_inline(assume_aligned(dst), + assume_aligned(src)); + } else if constexpr (strategy == ForceWordLdStChain) { + // We restrict loads/stores to 4 byte to prevent the use of load/store + // multiple (LDM, STM) and load/store double (LDRD, STRD). First, they may + // fault (see notes below) and second, they use more registers which in turn + // adds push/pop instructions in the hot path. + static_assert((bytes % kWordSize == 0) && (bytes >= kWordSize)); + LIBC_LOOP_UNROLL + for (size_t i = 0; i < bytes / kWordSize; ++i) { + const size_t offset = i * kWordSize; + memcpy_inline(dst + offset, src + offset); + } + } + // In the 1, 2, 4 byte copy case, the compiler can fold pointer offsetting + // into the load/store instructions. + // e.g., + // ldrb r3, [r1], #1 + // strb r3, [r0], #1 + dst += bytes; + src += bytes; +} + +LIBC_INLINE void copy_bytes_and_bump_pointers(Ptr &dst, CPtr &src, + const size_t size) { + LIBC_LOOP_NOUNROLL + for (size_t i = 0; i < size; ++i) + *dst++ = *src++; +} + +template +LIBC_INLINE void copy_blocks_and_update_args(Ptr &dst, CPtr &src, + size_t &size) { + LIBC_LOOP_NOUNROLL + for (size_t i = 0; i < size / block_size; ++i) + copy_and_bump_pointers(dst, src); + // Update `size` once at the end instead of once per iteration. + size %= block_size; +} + +LIBC_INLINE CPtr bitwise_or(CPtr a, CPtr b) { + return cpp::bit_cast(cpp::bit_cast(a) | + cpp::bit_cast(b)); +} + +LIBC_INLINE auto misaligned(CPtr a) { + return distance_to_align_down(a); +} + +} // namespace + +// Implementation for Cortex-M0, M0+, M1. +// Notes: +// - It compiles down to 196 bytes, but 220 bytes when used through `memcpy` +// that also needs to return the `dst` ptr. +// - These cores do not allow for unaligned loads/stores. +// - When `src` and `dst` are coaligned, we start by aligning them and perform +// bulk copies. We let the compiler know the pointers are aligned so it can +// use load/store multiple (LDM, STM). This significantly increase throughput +// but it also requires more registers and push/pop instructions. This impacts +// latency for small size copies. +// - When `src` and `dst` are misaligned, we align `dst` and recompose words +// using multiple aligned loads. `load_aligned` takes care of endianness +// issues. +[[maybe_unused]] LIBC_INLINE void inline_memcpy_arm_low_end(Ptr dst, CPtr src, + size_t size) { + if (size >= 8) { + if (const size_t offset = distance_to_align_up(dst)) + LIBC_ATTR_UNLIKELY { + copy_bytes_and_bump_pointers(dst, src, offset); + size -= offset; + } + const auto src_alignment = distance_to_align_down(src); + if (src_alignment == 0) + LIBC_ATTR_LIKELY { + // Both `src` and `dst` are now word-aligned. + copy_blocks_and_update_args<64, AssumeWordAligned>(dst, src, size); + copy_blocks_and_update_args<16, AssumeWordAligned>(dst, src, size); + copy_blocks_and_update_args<4, AssumeWordAligned>(dst, src, size); + } + else { + // `dst` is aligned but `src` is not. + LIBC_LOOP_NOUNROLL + while (size >= kWordSize) { + // Recompose word from multiple loads depending on the alignment. + const uint32_t value = + src_alignment == 2 + ? load_aligned(src) + : load_aligned(src); + memcpy_inline(assume_aligned(dst), &value); + dst += kWordSize; + src += kWordSize; + size -= kWordSize; + } + } + // Up to 3 bytes may still need to be copied. + // Handling them with the slow loop below. + } + copy_bytes_and_bump_pointers(dst, src, size); +} + +// Implementation for Cortex-M3, M4, M7, M23, M33, M35P, M52 with hardware +// support for unaligned loads and stores. +// Notes: +// - It compiles down to 266 bytes. +// - `dst` and `src` are not `__restrict` to prevent the compiler from +// reordering loads/stores. +// - We keep state variables to a strict minimum to keep everything in the free +// registers and prevent costly push / pop. +// - If unaligned single loads/stores to normal memory are supported, unaligned +// accesses for load/store multiple (LDM, STM) and load/store double (LDRD, +// STRD) instructions are generally not supported and will still fault so we +// make sure to restrict unrolling to word loads/stores. +[[maybe_unused]] LIBC_INLINE void inline_memcpy_arm_mid_end(Ptr dst, CPtr src, + size_t size) { + if (misaligned(bitwise_or(src, dst))) + LIBC_ATTR_UNLIKELY { + if (size < 8) + LIBC_ATTR_UNLIKELY { + if (size & 1) + copy_and_bump_pointers<1>(dst, src); + if (size & 2) + copy_and_bump_pointers<2>(dst, src); + if (size & 4) + copy_and_bump_pointers<4>(dst, src); + return; + } + if (misaligned(src)) + LIBC_ATTR_UNLIKELY { + const size_t offset = distance_to_align_up(dst); + if (offset & 1) + copy_and_bump_pointers<1>(dst, src); + if (offset & 2) + copy_and_bump_pointers<2>(dst, src); + size -= offset; + } + } + copy_blocks_and_update_args<64, ForceWordLdStChain>(dst, src, size); + copy_blocks_and_update_args<16, ForceWordLdStChain>(dst, src, size); + copy_blocks_and_update_args<4, AssumeUnaligned>(dst, src, size); + if (size & 1) + copy_and_bump_pointers<1>(dst, src); + if (size & 2) + LIBC_ATTR_UNLIKELY + copy_and_bump_pointers<2>(dst, src); +} + +[[maybe_unused]] LIBC_INLINE void inline_memcpy_arm(void *__restrict dst_, + const void *__restrict src_, + size_t size) { + Ptr dst = cpp::bit_cast(dst_); + CPtr src = cpp::bit_cast(src_); +#ifdef __ARM_FEATURE_UNALIGNED + return inline_memcpy_arm_mid_end(dst, src, size); +#else + return inline_memcpy_arm_low_end(dst, src, size); +#endif +} + +} // namespace LIBC_NAMESPACE_DECL + +// Cleanup local macros +#undef LIBC_ATTR_LIKELY +#undef LIBC_ATTR_UNLIKELY + +#endif // LLVM_LIBC_SRC_STRING_MEMORY_UTILS_ARM_INLINE_MEMCPY_H diff --git a/system/lib/llvm-libc/src/string/memory_utils/inline_memcpy.h b/system/lib/llvm-libc/src/string/memory_utils/inline_memcpy.h index 9f1a162416da0..931d2821be3a9 100644 --- a/system/lib/llvm-libc/src/string/memory_utils/inline_memcpy.h +++ b/system/lib/llvm-libc/src/string/memory_utils/inline_memcpy.h @@ -22,6 +22,9 @@ #include "src/string/memory_utils/x86_64/inline_memcpy.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMCPY \ inline_memcpy_x86_maybe_interpose_repmovsb +#elif defined(LIBC_TARGET_ARCH_IS_ARM) +#include "src/string/memory_utils/arm/inline_memcpy.h" +#define LIBC_SRC_STRING_MEMORY_UTILS_MEMCPY inline_memcpy_arm #elif defined(LIBC_TARGET_ARCH_IS_AARCH64) #include "src/string/memory_utils/aarch64/inline_memcpy.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMCPY inline_memcpy_aarch64 diff --git a/system/lib/llvm-libc/src/string/memory_utils/utils.h b/system/lib/llvm-libc/src/string/memory_utils/utils.h index bdf0b8652188b..c08608c87bb25 100644 --- a/system/lib/llvm-libc/src/string/memory_utils/utils.h +++ b/system/lib/llvm-libc/src/string/memory_utils/utils.h @@ -101,7 +101,7 @@ LIBC_INLINE void memcpy_inline(void *__restrict dst, } using Ptr = cpp::byte *; // Pointer to raw data. -using CPtr = const cpp::byte *; // Const pointer to raw data. +using CPtr = const cpp::byte *; // Pointer to const raw data. // This type makes sure that we don't accidentally promote an integral type to // another one. It is only constructible from the exact T type. diff --git a/system/lib/llvm-libc/src/wchar/mbrtowc.cpp b/system/lib/llvm-libc/src/wchar/mbrtowc.cpp new file mode 100644 index 0000000000000..6ecf4828da9bf --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/mbrtowc.cpp @@ -0,0 +1,38 @@ +//===-- Implementation of mbrtowc -----------------------------------------===// +// +// 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/mbrtowc.h" + +#include "hdr/types/mbstate_t.h" +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/__support/wchar/mbrtowc.h" +#include "src/__support/wchar/mbstate.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(size_t, mbrtowc, + (wchar_t *__restrict pwc, const char *__restrict s, size_t n, + mbstate_t *__restrict ps)) { + static internal::mbstate internal_mbstate; + auto ret = internal::mbrtowc(pwc, s, n, + ps == nullptr + ? &internal_mbstate + : reinterpret_cast(ps)); + if (!ret.has_value()) { + // Encoding failure + libc_errno = ret.error(); + return -1; + } + return ret.value(); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/wchar/mbrtowc.h b/system/lib/llvm-libc/src/wchar/mbrtowc.h new file mode 100644 index 0000000000000..e2e3d3ebd2853 --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/mbrtowc.h @@ -0,0 +1,24 @@ +//===-- Implementation header for mbrtowc ---------------------------------===// +// +// 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_MBRTOWC_H +#define LLVM_LIBC_SRC_WCHAR_MBRTOWC_H + +#include "hdr/types/mbstate_t.h" +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +size_t mbrtowc(wchar_t *__restrict pwc, const char *__restrict s, size_t n, + mbstate_t *__restrict ps); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_MBRTOWC_H diff --git a/system/lib/llvm-libc/src/wchar/mbtowc.cpp b/system/lib/llvm-libc/src/wchar/mbtowc.cpp new file mode 100644 index 0000000000000..eae39ba6081f3 --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/mbtowc.cpp @@ -0,0 +1,40 @@ +//===-- Implementation of mbtowc -----------------------------------------===// +// +// 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/mbtowc.h" + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/__support/wchar/mbrtowc.h" +#include "src/__support/wchar/mbstate.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, mbtowc, + (wchar_t *__restrict pwc, const char *__restrict s, + size_t n)) { + // returns 0 since UTF-8 encoding is not state-dependent + if (s == nullptr) + return 0; + internal::mbstate internal_mbstate; + // temp ptr to use if pwc is nullptr + wchar_t buf[1]; + auto ret = + internal::mbrtowc(pwc == nullptr ? buf : pwc, s, n, &internal_mbstate); + if (!ret.has_value() || static_cast(ret.value()) == -2) { + // Encoding failure + libc_errno = EILSEQ; + return -1; + } + return static_cast(ret.value()); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/wchar/mbtowc.h b/system/lib/llvm-libc/src/wchar/mbtowc.h new file mode 100644 index 0000000000000..f974197f81b58 --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/mbtowc.h @@ -0,0 +1,22 @@ +//===-- Implementation header for mbtowc ---------------------------------===// +// +// 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_MBTOWC_H +#define LLVM_LIBC_SRC_WCHAR_MBTOWC_H + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +int mbtowc(wchar_t *__restrict pwc, const char *__restrict s, size_t n); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_MBTOWC_H diff --git a/system/lib/llvm-libc/src/wchar/wcpcpy.cpp b/system/lib/llvm-libc/src/wchar/wcpcpy.cpp new file mode 100644 index 0000000000000..9e2b12f09eb05 --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcpcpy.cpp @@ -0,0 +1,27 @@ +//===-- Implementation of wcpcpy ------------------------------------------===// +// +// 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/wcpcpy.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 *, wcpcpy, + (wchar_t *__restrict s1, const wchar_t *__restrict s2)) { + size_t size = internal::string_length(s2); + __builtin_memcpy(s1, s2, (size + 1) * sizeof(wchar_t)); + wchar_t *result = s1 + size; + return result; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/wchar/wcpcpy.h b/system/lib/llvm-libc/src/wchar/wcpcpy.h new file mode 100644 index 0000000000000..333491fc13abb --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcpcpy.h @@ -0,0 +1,21 @@ +//===-- Implementation header for wcpcpy ----------------------------------===// +// +// 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_WCPCPY_H +#define LLVM_LIBC_SRC_WCHAR_WCPCPY_H + +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +wchar_t *wcpcpy(wchar_t *__restrict ws1, const wchar_t *__restrict ws2); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCPCPY_H diff --git a/system/lib/llvm-libc/src/wchar/wcpncpy.cpp b/system/lib/llvm-libc/src/wchar/wcpncpy.cpp new file mode 100644 index 0000000000000..0e729db7abf60 --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcpncpy.cpp @@ -0,0 +1,37 @@ +//===-- Implementation of wcpncpy -----------------------------------------===// +// +// 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/wcpncpy.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/__support/macros/null_check.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(wchar_t *, wcpncpy, + (wchar_t *__restrict s1, const wchar_t *__restrict s2, + size_t n)) { + if (n) { + LIBC_CRASH_ON_NULLPTR(s1); + LIBC_CRASH_ON_NULLPTR(s2); + } + size_t i; + // Copy up until \0 is found. + for (i = 0; i < n && s2[i] != '\0'; ++i) + s1[i] = s2[i]; + // When n>strlen(src), n-strlen(src) \0 are appended. + for (size_t j = i; j < n; ++j) + s1[j] = L'\0'; + // ...but our result points to the first \0 (if any). + return s1 + i; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/wchar/wcpncpy.h b/system/lib/llvm-libc/src/wchar/wcpncpy.h new file mode 100644 index 0000000000000..1f67cd46f7753 --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcpncpy.h @@ -0,0 +1,23 @@ +//===-- Implementation header for wcpncpy ---------------------------------===// +// +// 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_WCPNCPY_H +#define LLVM_LIBC_SRC_WCHAR_WCPNCPY_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 *wcpncpy(wchar_t *__restrict ws1, const wchar_t *__restrict ws2, + size_t n); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCPNCPY_H diff --git a/system/lib/llvm-libc/src/wchar/wcrtomb.cpp b/system/lib/llvm-libc/src/wchar/wcrtomb.cpp new file mode 100644 index 0000000000000..3e9df0599431e --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcrtomb.cpp @@ -0,0 +1,45 @@ +//===-- Implementation of wcrtomb -----------------------------------------===// +// +// 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/wcrtomb.h" + +#include "hdr/types/mbstate_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/__support/wchar/mbstate.h" +#include "src/__support/wchar/wcrtomb.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(size_t, wcrtomb, + (char *__restrict s, wchar_t wc, mbstate_t *__restrict ps)) { + static internal::mbstate internal_mbstate; + + // when s is nullptr, this is equivalent to wcrtomb(buf, L'\0', ps) + char buf[sizeof(wchar_t) / sizeof(char)]; + if (s == nullptr) { + s = buf; + wc = L'\0'; + } + + auto result = internal::wcrtomb( + s, wc, + ps == nullptr ? &internal_mbstate + : reinterpret_cast(ps)); + + if (!result.has_value()) { + libc_errno = result.error(); + return -1; + } + + return result.value(); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/wchar/wcrtomb.h b/system/lib/llvm-libc/src/wchar/wcrtomb.h new file mode 100644 index 0000000000000..06c42f158122c --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcrtomb.h @@ -0,0 +1,23 @@ +//===-- Implementation header for wcrtomb -----------------------*- 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_WCHAR_WCRTOMB_H +#define LLVM_LIBC_SRC_WCHAR_WCRTOMB_H + +#include "hdr/types/mbstate_t.h" +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +size_t wcrtomb(char *__restrict s, wchar_t wc, mbstate_t *__restrict ps); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCRTOMB_H diff --git a/system/lib/llvm-libc/src/wchar/wcscspn.cpp b/system/lib/llvm-libc/src/wchar/wcscspn.cpp new file mode 100644 index 0000000000000..8869d84cdfdee --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcscspn.cpp @@ -0,0 +1,34 @@ +//===-- Implementation of wcscspn -----------------------------------------===// +// +// 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/wcscspn.h" + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +bool check(wchar_t c, const wchar_t *s2) { + for (int n = 0; s2[n]; ++n) { + if (s2[n] == c) + return false; + } + return true; +} +LLVM_LIBC_FUNCTION(size_t, wcscspn, (const wchar_t *s1, const wchar_t *s2)) { + size_t i = 0; + for (; s1[i]; ++i) { + if (!check(s1[i], s2)) + return i; + } + return i; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/wchar/wcscspn.h b/system/lib/llvm-libc/src/wchar/wcscspn.h new file mode 100644 index 0000000000000..cffc2b98c3467 --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcscspn.h @@ -0,0 +1,22 @@ +//===-- Implementation header for wcscspn ---------------------------------===// +// +// 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_WCSCSPN_H +#define LLVM_LIBC_SRC_WCHAR_WCSCSPN_H + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +size_t wcscspn(const wchar_t *s1, const wchar_t *s2); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCSCSPN_H diff --git a/system/lib/llvm-libc/src/wchar/wcslcat.cpp b/system/lib/llvm-libc/src/wchar/wcslcat.cpp new file mode 100644 index 0000000000000..eb318e066f7a0 --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcslcat.cpp @@ -0,0 +1,39 @@ +//===-- Implementation of wcslcat -----------------------------------------===// +// +// 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/wcslcat.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(size_t, wcslcat, + (wchar_t *__restrict dst, const wchar_t *__restrict src, + size_t dstsize)) { + const size_t dstlen = internal::string_length(dst); + const size_t srclen = internal::string_length(src); + int limit = static_cast(dstsize - dstlen - 1); + size_t returnval = (dstsize < dstlen ? dstsize : dstlen) + srclen; + if (limit < 0) + return returnval; + int i = 0; + for (; i < limit && src[i] != L'\0'; ++i) { + dst[dstlen + i] = src[i]; + } + + // appending null terminator if there is room + if (dstlen + i < dstlen + dstsize) + dst[dstlen + i] = L'\0'; + return returnval; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/wchar/wcslcat.h b/system/lib/llvm-libc/src/wchar/wcslcat.h new file mode 100644 index 0000000000000..fd964e1af49d5 --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcslcat.h @@ -0,0 +1,23 @@ +//===-- Implementation header for wcslcat ---------------------------------===// +// +// 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_WCSLCAT_H +#define LLVM_LIBC_SRC_WCHAR_WCSLCAT_H + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +size_t wcslcat(wchar_t *__restrict dst, const wchar_t *__restrict src, + size_t dstsize); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCSLCAT_H diff --git a/system/lib/llvm-libc/src/wchar/wcslcpy.cpp b/system/lib/llvm-libc/src/wchar/wcslcpy.cpp new file mode 100644 index 0000000000000..7239334a07f77 --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcslcpy.cpp @@ -0,0 +1,32 @@ +//===-- Implementation of wcslcpy -----------------------------------------===// +// +// 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/wcslcpy.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(size_t, wcslcpy, + (wchar_t *__restrict dst, const wchar_t *__restrict src, + size_t dstsize)) { + size_t len = internal::string_length(src); + if (dstsize == 0) + return len; + size_t i = 0; + for (; i < dstsize - 1 && src[i] != L'\0'; ++i) + dst[i] = src[i]; + dst[i] = L'\0'; + return len; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/wchar/wcslcpy.h b/system/lib/llvm-libc/src/wchar/wcslcpy.h new file mode 100644 index 0000000000000..97b02f616605d --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcslcpy.h @@ -0,0 +1,23 @@ +//===-- Implementation header for wcslcpy ---------------------------------===// +// +// 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_WCSLCPY_H +#define LLVM_LIBC_SRC_WCHAR_WCSLCPY_H + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +size_t wcslcpy(wchar_t *__restrict dst, const wchar_t *__restrict src, + size_t dstsize); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCSLCPY_H diff --git a/system/lib/llvm-libc/src/wchar/wcsnlen.cpp b/system/lib/llvm-libc/src/wchar/wcsnlen.cpp new file mode 100644 index 0000000000000..4613006ff203e --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcsnlen.cpp @@ -0,0 +1,25 @@ +//===-- Implementation of wcsnlen -----------------------------------------===// +// +// 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/wcsnlen.h" + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(size_t, wcsnlen, (const wchar_t *src, size_t maxlen)) { + size_t i = 0; + for (; i < maxlen && src[i]; ++i) + ; + return i; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/wchar/wcsnlen.h b/system/lib/llvm-libc/src/wchar/wcsnlen.h new file mode 100644 index 0000000000000..5a4c92d368a54 --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcsnlen.h @@ -0,0 +1,22 @@ +//===-- Implementation header for wcsnlen ---------------------------------===// +// +// 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_WCSNLEN_H +#define LLVM_LIBC_SRC_WCHAR_WCSNLEN_H + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +size_t wcsnlen(const wchar_t *src, size_t maxlen); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCSNLEN_H diff --git a/system/lib/llvm-libc/src/wchar/wcsspn.h b/system/lib/llvm-libc/src/wchar/wcsspn.h index 6dbe65d9a4a98..6e21cbe594574 100644 --- a/system/lib/llvm-libc/src/wchar/wcsspn.h +++ b/system/lib/llvm-libc/src/wchar/wcsspn.h @@ -19,4 +19,4 @@ size_t wcsspn(const wchar_t *s1, const wchar_t *s2); } // namespace LIBC_NAMESPACE_DECL -#endif // LLVM_LIBC_SRC_WCHAR_WCSCHR_H +#endif // LLVM_LIBC_SRC_WCHAR_WCSSPN_H diff --git a/system/lib/llvm-libc/src/wchar/wcstok.cpp b/system/lib/llvm-libc/src/wchar/wcstok.cpp new file mode 100644 index 0000000000000..291efc15e158a --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcstok.cpp @@ -0,0 +1,50 @@ +//===-- Implementation of wcstok ------------------------------------------===// +// +// 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/wcstok.h" + +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE_DECL { + +bool isADelimeter(wchar_t wc, const wchar_t *delimiters) { + for (const wchar_t *delim_ptr = delimiters; *delim_ptr != L'\0'; ++delim_ptr) + if (wc == *delim_ptr) + return true; + return false; +} + +LLVM_LIBC_FUNCTION(wchar_t *, wcstok, + (wchar_t *__restrict str, const wchar_t *__restrict delim, + wchar_t **__restrict context)) { + if (str == nullptr) { + if (*context == nullptr) + return nullptr; + + str = *context; + } + + wchar_t *tok_start, *tok_end; + for (tok_start = str; *tok_start != L'\0' && isADelimeter(*tok_start, delim); + ++tok_start) + ; + + for (tok_end = tok_start; *tok_end != L'\0' && !isADelimeter(*tok_end, delim); + ++tok_end) + ; + + if (*tok_end != L'\0') { + *tok_end = L'\0'; + ++tok_end; + } + *context = tok_end; + return *tok_start == L'\0' ? nullptr : tok_start; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/wchar/wcstok.h b/system/lib/llvm-libc/src/wchar/wcstok.h new file mode 100644 index 0000000000000..5e673ff4e89b9 --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcstok.h @@ -0,0 +1,22 @@ +//===-- Implementation header for wcstok ----------------------------------===// +// +// 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_WCSTOK_H +#define LLVM_LIBC_SRC_WCHAR_WCSTOK_H + +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +wchar_t *wcstok(wchar_t *__restrict str, const wchar_t *__restrict delim, + wchar_t **__restrict context); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCSTOK_H diff --git a/system/lib/llvm-libc/src/wchar/wcstol.cpp b/system/lib/llvm-libc/src/wchar/wcstol.cpp new file mode 100644 index 0000000000000..a05718f706dfd --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcstol.cpp @@ -0,0 +1,30 @@ +//===-- Implementation of wcstol ------------------------------------------===// +// +// 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/wcstol.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/__support/wcs_to_integer.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(long, wcstol, + (const wchar_t *__restrict str, wchar_t **__restrict str_end, + int base)) { + auto result = internal::wcstointeger(str, base); + if (result.has_error()) + libc_errno = result.error; + + if (str_end != nullptr) + *str_end = const_cast(str + result.parsed_len); + + return result; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/wchar/wcstol.h b/system/lib/llvm-libc/src/wchar/wcstol.h new file mode 100644 index 0000000000000..08acd9717a237 --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcstol.h @@ -0,0 +1,22 @@ +//===-- Implementation header for wcstol ------------------------*- 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_WCHAR_WCSTOL_H +#define LLVM_LIBC_SRC_WCHAR_WCSTOL_H + +#include "hdr/types/wint_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +long wcstol(const wchar_t *__restrict str, wchar_t **__restrict str_end, + int base); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCSTOL_H diff --git a/system/lib/llvm-libc/src/wchar/wcstoll.cpp b/system/lib/llvm-libc/src/wchar/wcstoll.cpp new file mode 100644 index 0000000000000..de1299d681cdb --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcstoll.cpp @@ -0,0 +1,30 @@ +//===-- Implementation of wcstoll -----------------------------------------===// +// +// 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/wcstoll.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/__support/wcs_to_integer.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(long long, wcstoll, + (const wchar_t *__restrict str, wchar_t **__restrict str_end, + int base)) { + auto result = internal::wcstointeger(str, base); + if (result.has_error()) + libc_errno = result.error; + + if (str_end != nullptr) + *str_end = const_cast(str + result.parsed_len); + + return result; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/wchar/wcstoll.h b/system/lib/llvm-libc/src/wchar/wcstoll.h new file mode 100644 index 0000000000000..6278043569490 --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcstoll.h @@ -0,0 +1,22 @@ +//===-- Implementation header for wcstoll -----------------------*- 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_WCHAR_WCSTOLL_H +#define LLVM_LIBC_SRC_WCHAR_WCSTOLL_H + +#include "hdr/types/wint_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +long long wcstoll(const wchar_t *__restrict str, wchar_t **__restrict str_end, + int base); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCSTOLL_H diff --git a/system/lib/llvm-libc/src/wchar/wcstoul.cpp b/system/lib/llvm-libc/src/wchar/wcstoul.cpp new file mode 100644 index 0000000000000..79b8c9b5c9fa3 --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcstoul.cpp @@ -0,0 +1,30 @@ +//===-- Implementation of wcstoul -----------------------------------------===// +// +// 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/wcstoul.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/__support/wcs_to_integer.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(unsigned long, wcstoul, + (const wchar_t *__restrict str, wchar_t **__restrict str_end, + int base)) { + auto result = internal::wcstointeger(str, base); + if (result.has_error()) + libc_errno = result.error; + + if (str_end != nullptr) + *str_end = const_cast(str + result.parsed_len); + + return result; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/wchar/wcstoul.h b/system/lib/llvm-libc/src/wchar/wcstoul.h new file mode 100644 index 0000000000000..81f530534e81a --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcstoul.h @@ -0,0 +1,22 @@ +//===-- Implementation header for wcstoul -----------------------*- 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_WCHAR_WCSTOUL_H +#define LLVM_LIBC_SRC_WCHAR_WCSTOUL_H + +#include "hdr/types/wint_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +unsigned long wcstoul(const wchar_t *__restrict str, + wchar_t **__restrict str_end, int base); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCSTOUL_H diff --git a/system/lib/llvm-libc/src/wchar/wcstoull.cpp b/system/lib/llvm-libc/src/wchar/wcstoull.cpp new file mode 100644 index 0000000000000..768e03c4bd189 --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcstoull.cpp @@ -0,0 +1,30 @@ +//===-- Implementation of wcstoull ----------------------------------------===// +// +// 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/wcstoull.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/__support/wcs_to_integer.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(unsigned long long, wcstoull, + (const wchar_t *__restrict str, wchar_t **__restrict str_end, + int base)) { + auto result = internal::wcstointeger(str, base); + if (result.has_error()) + libc_errno = result.error; + + if (str_end != nullptr) + *str_end = const_cast(str + result.parsed_len); + + return result; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/wchar/wcstoull.h b/system/lib/llvm-libc/src/wchar/wcstoull.h new file mode 100644 index 0000000000000..e970a5792338b --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wcstoull.h @@ -0,0 +1,22 @@ +//===-- Implementation header for wcstoull -----------------------*- 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_WCHAR_WCSTOULL_H +#define LLVM_LIBC_SRC_WCHAR_WCSTOULL_H + +#include "hdr/types/wint_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +unsigned long long wcstoull(const wchar_t *__restrict str, + wchar_t **__restrict str_end, int base); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCSTOULL_H diff --git a/system/lib/llvm-libc/src/wchar/wctomb.cpp b/system/lib/llvm-libc/src/wchar/wctomb.cpp new file mode 100644 index 0000000000000..142302e6ae09b --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wctomb.cpp @@ -0,0 +1,35 @@ +//===-- Implementation of wctomb ------------------------------------------===// +// +// 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/wctomb.h" + +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/__support/wchar/mbstate.h" +#include "src/__support/wchar/wcrtomb.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, wctomb, (char *s, wchar_t wc)) { + static internal::mbstate internal_mbstate; + if (s == nullptr) + return 0; + + auto result = internal::wcrtomb(s, wc, &internal_mbstate); + + if (!result.has_value()) { // invalid wide character + libc_errno = EILSEQ; + return -1; + } + + return static_cast(result.value()); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/system/lib/llvm-libc/src/wchar/wctomb.h b/system/lib/llvm-libc/src/wchar/wctomb.h new file mode 100644 index 0000000000000..02a34e5ad229f --- /dev/null +++ b/system/lib/llvm-libc/src/wchar/wctomb.h @@ -0,0 +1,22 @@ +//===-- Implementation header for wctomb ------------------------*- 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_WCHAR_WCTOMB_H +#define LLVM_LIBC_SRC_WCHAR_WCTOMB_H + +#include "hdr/types/mbstate_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +int wctomb(char *s, wchar_t wc); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCTOMB_H diff --git a/tools/system_libs.py b/tools/system_libs.py index 79e4e614344f2..0328aae72c25d 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1033,7 +1033,8 @@ def get_files(self): files += glob_in_path('system/lib/llvm-libc/src/strings', '**/*.cpp') files += glob_in_path('system/lib/llvm-libc/src/errno', '**/*.cpp') files += glob_in_path('system/lib/llvm-libc/src/math', '*.cpp') - files += glob_in_path('system/lib/llvm-libc/src/wchar', '*.cpp') + # Overlay mode doesn't support mbstate_t which is used by these wchar sources. + files += glob_in_path('system/lib/llvm-libc/src/wchar', '*.cpp', excludes=['wcrtomb.cpp', 'mbrtowc.cpp', 'wctomb.cpp', 'mbtowc.cpp']) files += glob_in_path('system/lib/llvm-libc/src/setjmp', '*.cpp') files += glob_in_path('system/lib/llvm-libc/src/setjmp', '**/*.cpp') files += glob_in_path('system/lib/llvm-libc/src/stdlib', '*.cpp', excludes=['at_quick_exit.cpp',