diff --git a/lib/libcxx/libc/hdr/errno_macros.h b/lib/libcxx/libc/hdr/errno_macros.h index e2913f45a8ad97bf068c247a4ae7135c9e7bcda7..e101239f4396efec604a87f8b4a99466e3c58f2d 100644 --- a/lib/libcxx/libc/hdr/errno_macros.h +++ b/lib/libcxx/libc/hdr/errno_macros.h @@ -25,6 +25,6 @@ #include -#endif // LLVM_LIBC_FULL_BUILD +#endif // LIBC_FULL_BUILD #endif // LLVM_LIBC_HDR_ERRNO_MACROS_H diff --git a/lib/libcxx/libc/hdr/fenv_macros.h b/lib/libcxx/libc/hdr/fenv_macros.h index 3f0bd89a6ea35451f85ec55bd746081e89bb3735..d8778e1393df4aee1a27f3dfa06d95259c3d1a8b 100644 --- a/lib/libcxx/libc/hdr/fenv_macros.h +++ b/lib/libcxx/libc/hdr/fenv_macros.h @@ -56,6 +56,6 @@ #define FE_UPWARD 0x800 #endif // FE_UPWARD -#endif // LLVM_LIBC_FULL_BUILD +#endif // LIBC_FULL_BUILD #endif // LLVM_LIBC_HDR_FENV_MACROS_H diff --git a/lib/libcxx/libc/hdr/float_macros.h b/lib/libcxx/libc/hdr/float_macros.h index a0ef5e29b98687f0b0baac2f301a15d29452d376..e590f413ad56385f6b752fc41bf2dc96a56f078e 100644 --- a/lib/libcxx/libc/hdr/float_macros.h +++ b/lib/libcxx/libc/hdr/float_macros.h @@ -17,6 +17,6 @@ #include -#endif // LLVM_LIBC_FULL_BUILD +#endif // LIBC_FULL_BUILD #endif // LLVM_LIBC_HDR_FLOAT_MACROS_H diff --git a/lib/libcxx/libc/hdr/limits_macros.h b/lib/libcxx/libc/hdr/limits_macros.h index 2dc13b0cca60df3937113fa0502b6cf5842295ba..7ed79685f7c3ff7f397281cde35478a3f9e8b8df 100644 --- a/lib/libcxx/libc/hdr/limits_macros.h +++ b/lib/libcxx/libc/hdr/limits_macros.h @@ -17,6 +17,6 @@ #include -#endif // LLVM_LIBC_FULL_BUILD +#endif // LIBC_FULL_BUILD #endif // LLVM_LIBC_HDR_LIMITS_MACROS_H diff --git a/lib/libcxx/libc/hdr/types/size_t.h b/lib/libcxx/libc/hdr/types/size_t.h new file mode 100644 index 0000000000000000000000000000000000000000..1d9f26db3bbb3aff6952186fccaeaae1123a1a2e --- /dev/null +++ b/lib/libcxx/libc/hdr/types/size_t.h @@ -0,0 +1,23 @@ +//===-- Proxy for size_t --------------------------------------------------===// +// +// 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_HDR_TYPES_SIZE_T_H +#define LLVM_LIBC_HDR_TYPES_SIZE_T_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/size_t.h" + +#else + +#define __need_size_t +#include +#undef __need_size_t + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_SIZE_T_H diff --git a/lib/libcxx/libc/hdr/types/wchar_t.h b/lib/libcxx/libc/hdr/types/wchar_t.h index 75e945239119c61c5182e168277a30820b443833..c5b6b0d9cacca414f188346605f2fd0ef30697d4 100644 --- a/lib/libcxx/libc/hdr/types/wchar_t.h +++ b/lib/libcxx/libc/hdr/types/wchar_t.h @@ -18,6 +18,6 @@ #include "hdr/wchar_overlay.h" -#endif // LLVM_LIBC_FULL_BUILD +#endif // LIBC_FULL_BUILD #endif // LLVM_LIBC_HDR_TYPES_WCHAR_T_H diff --git a/lib/libcxx/libc/hdr/types/wint_t.h b/lib/libcxx/libc/hdr/types/wint_t.h new file mode 100644 index 0000000000000000000000000000000000000000..aa06c35d03ab81bcb6288a5acc6c59ac44001ae6 --- /dev/null +++ b/lib/libcxx/libc/hdr/types/wint_t.h @@ -0,0 +1,23 @@ +//===-- Definition of wint_t.h --------------------------------------------===// +// +// 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_HDR_TYPES_WINT_T_H +#define LLVM_LIBC_HDR_TYPES_WINT_T_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/wint_t.h" + +#else // overlay mode + +#include "hdr/wchar_overlay.h" + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_WINT_T_H diff --git a/lib/libcxx/libc/include/llvm-libc-macros/cfloat128-macros.h b/lib/libcxx/libc/include/llvm-libc-macros/cfloat128-macros.h index 5f28cfa21aaee80aa0d112c6b05d60183eee6ea4..ff4aa530685de0b9ce57bb62e42f866a4d137882 100644 --- a/lib/libcxx/libc/include/llvm-libc-macros/cfloat128-macros.h +++ b/lib/libcxx/libc/include/llvm-libc-macros/cfloat128-macros.h @@ -27,7 +27,7 @@ #define LIBC_TYPES_HAS_CFLOAT128 #endif #elif defined(__GNUC__) -#if (defined(__STDC_IEC_60559_COMPLEX__) || defined(__SIZEOF_FLOAT128__)) && \ +#if (defined(__STDC_IEC_60559_COMPLEX__) && defined(__SIZEOF_FLOAT128__)) && \ (__GNUC__ >= 13 || (!defined(__cplusplus))) #define LIBC_TYPES_HAS_CFLOAT128 #endif diff --git a/lib/libcxx/libc/include/llvm-libc-macros/float-macros.h b/lib/libcxx/libc/include/llvm-libc-macros/float-macros.h index a25ef60a293d3678d1fce0a18f04c98c1c8f51f1..38a3a771cca54a3722a2351a0e3b4b0b42543cd3 100644 --- a/lib/libcxx/libc/include/llvm-libc-macros/float-macros.h +++ b/lib/libcxx/libc/include/llvm-libc-macros/float-macros.h @@ -9,6 +9,12 @@ #ifndef LLVM_LIBC_MACROS_FLOAT_MACROS_H #define LLVM_LIBC_MACROS_FLOAT_MACROS_H +// __has_builtin is a Clang extension; GCC < 10 doesn't define it, which +// turns a bare `#if __has_builtin(...)` into a preprocessor syntax error. +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + #ifndef FLT_RADIX #define FLT_RADIX __FLT_RADIX__ #endif // FLT_RADIX diff --git a/lib/libcxx/libc/include/llvm-libc-macros/float16-macros.h b/lib/libcxx/libc/include/llvm-libc-macros/float16-macros.h index 229e3e62f2aedf5a850af81f682669c655377e35..528c7f016f873f5887a285e1f00d014b915c6113 100644 --- a/lib/libcxx/libc/include/llvm-libc-macros/float16-macros.h +++ b/lib/libcxx/libc/include/llvm-libc-macros/float16-macros.h @@ -12,7 +12,8 @@ #include "../llvm-libc-types/float128.h" #if defined(__FLT16_MANT_DIG__) && \ - (!defined(__GNUC__) || __GNUC__ >= 13 || defined(__clang__)) && \ + (!defined(__GNUC__) || __GNUC__ >= 13 || \ + (defined(__clang__) && __clang_major__ >= 12)) && \ !defined(__arm__) && !defined(_M_ARM) && !defined(__riscv) && \ !defined(_WIN32) #define LIBC_TYPES_HAS_FLOAT16 diff --git a/lib/libcxx/libc/include/llvm-libc-macros/stdfix-macros.h b/lib/libcxx/libc/include/llvm-libc-macros/stdfix-macros.h index 04097e14e9747b4f18674ea71fb957e31c476683..20fa41e509e5826caacd70d7ee5be4bbca0f4bca 100644 --- a/lib/libcxx/libc/include/llvm-libc-macros/stdfix-macros.h +++ b/lib/libcxx/libc/include/llvm-libc-macros/stdfix-macros.h @@ -9,7 +9,7 @@ #ifndef LLVM_LIBC_MACROS_STDFIX_MACROS_H #define LLVM_LIBC_MACROS_STDFIX_MACROS_H -#ifdef __FRACT_FBIT__ +#if defined(__FRACT_FBIT__) && defined(__clang__) // _Fract and _Accum types are available #define LIBC_COMPILER_HAS_FIXED_POINT #endif // __FRACT_FBIT__ diff --git a/lib/libcxx/libc/include/llvm-libc-types/size_t.h b/lib/libcxx/libc/include/llvm-libc-types/size_t.h new file mode 100644 index 0000000000000000000000000000000000000000..26ae68abe0ee7a6a390e27eec6317898e49ddcf2 --- /dev/null +++ b/lib/libcxx/libc/include/llvm-libc-types/size_t.h @@ -0,0 +1,14 @@ +//===-- Definition of size_t types ----------------------------------------===// +// +// 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_TYPES_SIZE_T_H +#define LLVM_LIBC_TYPES_SIZE_T_H + +typedef __SIZE_TYPE__ size_t; + +#endif // LLVM_LIBC_TYPES_SIZE_T_H diff --git a/lib/libcxx/libc/src/__support/CPP/bit.h b/lib/libcxx/libc/src/__support/CPP/bit.h index 88d4362e6758ccbdcbdebe0a7272b93b0b92c43e..0f71b475bf560f160faf87fa6aa3aee0e8d6130d 100644 --- a/lib/libcxx/libc/src/__support/CPP/bit.h +++ b/lib/libcxx/libc/src/__support/CPP/bit.h @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// // This is inspired by LLVM ADT/bit.h header. -// Some functions are missing, we can add them as needed (popcount, byteswap). +// Some functions are missing, we can add them as needed. #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H #define LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H @@ -27,9 +27,14 @@ namespace cpp { #endif template -LIBC_INLINE static void inline_copy(const char *from, char *to) { -#if __has_builtin(__builtin_memcpy_inline) - __builtin_memcpy_inline(to, from, N); +LIBC_INLINE constexpr void inline_copy(const char *from, char *to) { +#if __has_builtin(__builtin_memcpy_inline) && \ + defined(LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED) + if (cpp::is_constant_evaluated()) + for (unsigned i = 0; i < N; ++i) + to[i] = from[i]; + else + __builtin_memcpy_inline(to, from, N); #else for (unsigned i = 0; i < N; ++i) to[i] = from[i]; @@ -39,15 +44,14 @@ LIBC_INLINE static void inline_copy(const char *from, char *to) { // This implementation of bit_cast requires trivially-constructible To, to avoid // UB in the implementation. template -LIBC_INLINE constexpr cpp::enable_if_t< +LIBC_INLINE static constexpr cpp::enable_if_t< (sizeof(To) == sizeof(From)) && cpp::is_trivially_constructible::value && cpp::is_trivially_copyable::value && cpp::is_trivially_copyable::value, To> bit_cast(const From &from) { - MSAN_UNPOISON(&from, sizeof(From)); -#if __has_builtin(__builtin_bit_cast) || defined(LIBC_COMPILER_IS_MSVC) +#if LIBC_HAS_BUILTIN_BIT_CAST return __builtin_bit_cast(To, from); #else To to{}; @@ -60,14 +64,12 @@ bit_cast(const From &from) { // The following simple bit copy from a smaller type to maybe-larger type. template -LIBC_INLINE constexpr cpp::enable_if_t< - (sizeof(To) >= sizeof(From)) && - cpp::is_trivially_constructible::value && - cpp::is_trivially_copyable::value && - cpp::is_trivially_copyable::value, - void> +LIBC_INLINE cpp::enable_if_t<(sizeof(To) >= sizeof(From)) && + cpp::is_trivially_constructible::value && + cpp::is_trivially_copyable::value && + cpp::is_trivially_copyable::value, + void> bit_copy(const From &from, To &to) { - MSAN_UNPOISON(&from, sizeof(From)); char *dst = reinterpret_cast(&to); const char *src = reinterpret_cast(&from); inline_copy(src, dst); @@ -330,6 +332,36 @@ ADD_SPECIALIZATION(unsigned long long, __builtin_popcountll) #endif // __builtin_popcountg #undef ADD_SPECIALIZATION +/// Reverses the bytes in the given integer value. +/// +/// All integral types are allowed, matching C++23 std::byteswap semantics. +/// Signed types delegate to the unsigned path via static_cast. +/// +/// The recursive decomposition generates optimal 'bswap' or 'rolw' +/// instructions on Clang at -O2 without requiring compiler intrinsics. +template +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t, T> +byteswap(T value) { + static_assert(sizeof(T) <= 16, "byteswap: unsupported type size"); + if constexpr (!cpp::is_unsigned_v) { + using U = cpp::make_unsigned_t; + return static_cast(byteswap(static_cast(value))); + } else if constexpr (sizeof(T) == 1) { + return value; + } else { + constexpr unsigned half_bits = sizeof(T) * 8 / 2; + using Half = cpp::conditional_t< + sizeof(T) == 2, uint8_t, + cpp::conditional_t< + sizeof(T) == 4, uint16_t, + cpp::conditional_t>>; + Half lo = static_cast(value); + Half hi = static_cast(value >> half_bits); + return static_cast((static_cast(byteswap(lo)) << half_bits) | + static_cast(byteswap(hi))); + } +} + } // namespace cpp } // namespace LIBC_NAMESPACE_DECL diff --git a/lib/libcxx/libc/src/__support/CPP/iterator.h b/lib/libcxx/libc/src/__support/CPP/iterator.h index 168a2697318220be9062a20807e026ea414b8697..9ea66d388238499b74178b8c94c38c9d4f2243ff 100644 --- a/lib/libcxx/libc/src/__support/CPP/iterator.h +++ b/lib/libcxx/libc/src/__support/CPP/iterator.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_ITERATOR_H #define LLVM_LIBC_SRC___SUPPORT_CPP_ITERATOR_H +#include "hdr/types/size_t.h" #include "src/__support/CPP/type_traits/enable_if.h" #include "src/__support/CPP/type_traits/is_convertible.h" #include "src/__support/CPP/type_traits/is_same.h" @@ -18,9 +19,13 @@ namespace LIBC_NAMESPACE_DECL { namespace cpp { +struct input_iterator_tag {}; +struct random_access_iterator_tag : input_iterator_tag {}; + template struct iterator_traits; template struct iterator_traits { using reference = T &; + using iterator_category = random_access_iterator_tag; using value_type = T; }; @@ -93,6 +98,30 @@ public: } }; +namespace cpp_internal { + +template +LIBC_INLINE constexpr size_t distance(It first, It last, + random_access_iterator_tag) { + return last - first; +} + +template +LIBC_INLINE constexpr auto distance(It first, It last, input_iterator_tag) { + size_t n = 0; + for (; first != last; ++first) { + ++n; + } + return n; +} + +} // namespace cpp_internal + +template LIBC_INLINE constexpr auto distance(It first, It last) { + return cpp_internal::distance( + first, last, typename iterator_traits::iterator_category{}); +} + } // namespace cpp } // namespace LIBC_NAMESPACE_DECL diff --git a/lib/libcxx/libc/src/__support/CPP/limits.h b/lib/libcxx/libc/src/__support/CPP/limits.h index cf4beb9cc859f0012c148261e2b3caebfab35252..76158b2926b5e5882087284035716b614c6b5247 100644 --- a/lib/libcxx/libc/src/__support/CPP/limits.h +++ b/lib/libcxx/libc/src/__support/CPP/limits.h @@ -1,4 +1,4 @@ -//===-- A self contained equivalent of std::limits --------------*- C++ -*-===// +//===-- A self contained equivalent of ----------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,78 +13,42 @@ #include "src/__support/CPP/type_traits/is_integral.h" #include "src/__support/CPP/type_traits/is_signed.h" #include "src/__support/macros/attributes.h" // LIBC_INLINE -#include "src/__support/macros/config.h" -#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128 namespace LIBC_NAMESPACE_DECL { namespace cpp { namespace internal { -template struct integer_impl { - static_assert(cpp::is_integral_v); - LIBC_INLINE static constexpr T max() { return max_value; } - LIBC_INLINE static constexpr T min() { return min_value; } +template struct numeric_limits_impl {}; + +template struct numeric_limits_impl { + LIBC_INLINE_VAR static constexpr bool is_signed = T(-1) < T(0); + LIBC_INLINE_VAR static constexpr int digits = - CHAR_BIT * sizeof(T) - cpp::is_signed_v; + (CHAR_BIT * sizeof(T)) - is_signed; + + LIBC_INLINE static constexpr T min() { + if constexpr (is_signed) { + return T(T(1) << digits); + } else { + return 0; + } + } + + LIBC_INLINE static constexpr T max() { + if constexpr (is_signed) { + return T(T(~0) ^ min()); + } else { + return T(~0); + } + } }; } // namespace internal -template struct numeric_limits {}; - -// TODO: Add numeric_limits specializations as needed for new types. -template <> -struct numeric_limits - : public internal::integer_impl {}; - -template <> -struct numeric_limits - : public internal::integer_impl {}; - -template <> -struct numeric_limits - : public internal::integer_impl {}; - -template <> -struct numeric_limits - : public internal::integer_impl {}; - -template <> -struct numeric_limits - : public internal::integer_impl {}; - -template <> -struct numeric_limits - : public internal::integer_impl {}; - -template <> -struct numeric_limits - : public internal::integer_impl {}; - -template <> -struct numeric_limits - : public internal::integer_impl {}; - -template <> -struct numeric_limits - : public internal::integer_impl {}; - -template <> -struct numeric_limits - : public internal::integer_impl {}; - -template <> -struct numeric_limits - : public internal::integer_impl {}; - -#ifdef LIBC_TYPES_HAS_INT128 -// On platform where UInt128 resolves to __uint128_t, this specialization -// provides the limits of UInt128. -template <> -struct numeric_limits<__uint128_t> - : public internal::integer_impl<__uint128_t, 0, ~__uint128_t(0)> {}; -#endif +template +struct numeric_limits + : public internal::numeric_limits_impl> {}; } // namespace cpp } // namespace LIBC_NAMESPACE_DECL diff --git a/lib/libcxx/libc/src/__support/CPP/string_view.h b/lib/libcxx/libc/src/__support/CPP/string_view.h index aa15814b2e149cbd0b2746720a6f4f3c4fe8f1ae..68056f753c3148cc40749fc6923d2bf9200f53bf 100644 --- a/lib/libcxx/libc/src/__support/CPP/string_view.h +++ b/lib/libcxx/libc/src/__support/CPP/string_view.h @@ -18,46 +18,52 @@ namespace LIBC_NAMESPACE_DECL { namespace cpp { -// This is very simple alternate of the std::string_view class. There is no -// bounds check performed in any of the methods. The callers are expected to -// do the checks before invoking the methods. +template class basic_string_view; + +using string_view = basic_string_view; +using wstring_view = basic_string_view; + +// This is a very simple alternate of the std::basic_string_view class template. +// There is no bounds check performed in any of the methods. The callers are +// expected to do the checks before invoking the methods. // // This class will be extended as needed in future. -class string_view { +template class basic_string_view { private: - const char *Data; + const CharT *Data; size_t Len; - LIBC_INLINE static size_t min(size_t A, size_t B) { return A <= B ? A : B; } + LIBC_INLINE static constexpr size_t min(size_t A, size_t B) { + return A <= B ? A : B; + } - LIBC_INLINE static int compareMemory(const char *Lhs, const char *Rhs, - size_t Length) { + LIBC_INLINE static constexpr int compareN(const CharT *Lhs, const CharT *Rhs, + size_t Length) { for (size_t i = 0; i < Length; ++i) - if (int Diff = (int)Lhs[i] - (int)Rhs[i]) - return Diff; + if (Lhs[i] != Rhs[i]) + return Lhs[i] < Rhs[i] ? -1 : 1; return 0; } - LIBC_INLINE static constexpr size_t length(const char *Str) { - for (const char *End = Str;; ++End) - if (*End == '\0') + LIBC_INLINE static constexpr size_t length(const CharT *Str) { + for (const CharT *End = Str;; ++End) + if (*End == CharT{0}) return static_cast(End - Str); } - LIBC_INLINE bool equals(string_view Other) const { - return (Len == Other.Len && - compareMemory(Data, Other.Data, Other.Len) == 0); + LIBC_INLINE constexpr bool equals(basic_string_view Other) const { + return (Len == Other.Len && compareN(Data, Other.Data, Other.Len) == 0); } public: - using value_type = char; + using value_type = CharT; using size_type = size_t; using difference_type = ptrdiff_t; - using pointer = char *; - using const_pointer = const char *; - using reference = char &; - using const_reference = const char &; - using const_iterator = char *; + using pointer = CharT *; + using const_pointer = const CharT *; + using reference = CharT &; + using const_reference = const CharT &; + using const_iterator = CharT *; using iterator = const_iterator; // special value equal to the maximum value representable by the type @@ -65,124 +71,126 @@ public: LIBC_INLINE_VAR static constexpr size_t npos = cpp::numeric_limits::max(); - LIBC_INLINE constexpr string_view() : Data(nullptr), Len(0) {} + LIBC_INLINE constexpr basic_string_view() : Data(nullptr), Len(0) {} // Assumes Str is a null-terminated string. The length of the string does // not include the terminating null character. // Preconditions: [Str, Str + ​length(Str)) is a valid range. - LIBC_INLINE constexpr string_view(const char *Str) + LIBC_INLINE constexpr basic_string_view(const CharT *Str) : Data(Str), Len(length(Str)) {} // Preconditions: [Str, Str + N) is a valid range. - LIBC_INLINE constexpr string_view(const char *Str, size_t N) + LIBC_INLINE constexpr basic_string_view(const CharT *Str, size_t N) : Data(Str), Len(N) {} - LIBC_INLINE constexpr const char *data() const { return Data; } + LIBC_INLINE constexpr const CharT *data() const { return Data; } - // Returns the size of the string_view. + // Returns the size of the basic_string_view. LIBC_INLINE constexpr size_t size() const { return Len; } - // Returns whether the string_view is empty. + // Returns whether the basic_string_view is empty. LIBC_INLINE constexpr bool empty() const { return Len == 0; } // Returns an iterator to the first character of the view. - LIBC_INLINE const char *begin() const { return Data; } + LIBC_INLINE constexpr const CharT *begin() const { return Data; } // Returns an iterator to the character following the last character of the // view. - LIBC_INLINE const char *end() const { return Data + Len; } + LIBC_INLINE constexpr const CharT *end() const { return Data + Len; } // Returns a const reference to the character at specified location pos. // No bounds checking is performed: the behavior is undefined if pos >= // size(). - LIBC_INLINE constexpr const char &operator[](size_t Index) const { + LIBC_INLINE constexpr const CharT &operator[](size_t Index) const { return Data[Index]; } /// compare - Compare two strings; the result is -1, 0, or 1 if this string /// is lexicographically less than, equal to, or greater than the \p Other. - LIBC_INLINE int compare(string_view Other) const { + LIBC_INLINE constexpr int compare(basic_string_view Other) const { // Check the prefix for a mismatch. - if (int Res = compareMemory(Data, Other.Data, min(Len, Other.Len))) - return Res < 0 ? -1 : 1; + if (int Res = compareN(Data, Other.Data, min(Len, Other.Len))) + return Res; // Otherwise the prefixes match, so we only need to check the lengths. if (Len == Other.Len) return 0; return Len < Other.Len ? -1 : 1; } - LIBC_INLINE bool operator==(string_view Other) const { return equals(Other); } - LIBC_INLINE bool operator!=(string_view Other) const { + LIBC_INLINE constexpr bool operator==(basic_string_view Other) const { + return equals(Other); + } + LIBC_INLINE constexpr bool operator!=(basic_string_view Other) const { return !(*this == Other); } - LIBC_INLINE bool operator<(string_view Other) const { + LIBC_INLINE constexpr bool operator<(basic_string_view Other) const { return compare(Other) == -1; } - LIBC_INLINE bool operator<=(string_view Other) const { + LIBC_INLINE constexpr bool operator<=(basic_string_view Other) const { return compare(Other) != 1; } - LIBC_INLINE bool operator>(string_view Other) const { + LIBC_INLINE constexpr bool operator>(basic_string_view Other) const { return compare(Other) == 1; } - LIBC_INLINE bool operator>=(string_view Other) const { + LIBC_INLINE constexpr bool operator>=(basic_string_view Other) const { return compare(Other) != -1; } // Moves the start of the view forward by n characters. // The behavior is undefined if n > size(). - LIBC_INLINE void remove_prefix(size_t N) { + LIBC_INLINE constexpr void remove_prefix(size_t N) { Len -= N; Data += N; } // Moves the end of the view back by n characters. // The behavior is undefined if n > size(). - LIBC_INLINE void remove_suffix(size_t N) { Len -= N; } + LIBC_INLINE constexpr void remove_suffix(size_t N) { Len -= N; } // Check if this string starts with the given Prefix. - LIBC_INLINE bool starts_with(string_view Prefix) const { - return Len >= Prefix.Len && - compareMemory(Data, Prefix.Data, Prefix.Len) == 0; + LIBC_INLINE constexpr bool starts_with(basic_string_view Prefix) const { + return Len >= Prefix.Len && compareN(Data, Prefix.Data, Prefix.Len) == 0; } // Check if this string starts with the given Prefix. - LIBC_INLINE bool starts_with(const char Prefix) const { + LIBC_INLINE constexpr bool starts_with(const CharT Prefix) const { return !empty() && front() == Prefix; } // Check if this string ends with the given Prefix. - LIBC_INLINE bool ends_with(const char Suffix) const { + LIBC_INLINE constexpr bool ends_with(const CharT Suffix) const { return !empty() && back() == Suffix; } // Check if this string ends with the given Suffix. - LIBC_INLINE bool ends_with(string_view Suffix) const { + LIBC_INLINE constexpr bool ends_with(basic_string_view Suffix) const { return Len >= Suffix.Len && - compareMemory(end() - Suffix.Len, Suffix.Data, Suffix.Len) == 0; + compareN(end() - Suffix.Len, Suffix.Data, Suffix.Len) == 0; } // Return a reference to the substring from [Start, Start + N). // - // Start The index of the starting character in the substring; if the index is - // npos or greater than the length of the string then the empty substring will - // be returned. + // Start The index of the starting character in the substring; if the index + // is npos or greater than the length of the string then the empty substring + // will be returned. // // N The number of characters to included in the substring. If N exceeds the // number of characters remaining in the string, the string suffix (starting // with Start) will be returned. - LIBC_INLINE string_view substr(size_t Start, size_t N = npos) const { + LIBC_INLINE constexpr basic_string_view substr(size_t Start, + size_t N = npos) const { Start = min(Start, Len); - return string_view(Data + Start, min(N, Len - Start)); + return basic_string_view(Data + Start, min(N, Len - Start)); } // front - Get the first character in the string. - LIBC_INLINE char front() const { return Data[0]; } + LIBC_INLINE constexpr CharT front() const { return Data[0]; } // back - Get the last character in the string. - LIBC_INLINE char back() const { return Data[Len - 1]; } + LIBC_INLINE constexpr CharT back() const { return Data[Len - 1]; } // Finds the first occurence of c in this view, starting at position From. - LIBC_INLINE constexpr size_t find_first_of(const char c, + LIBC_INLINE constexpr size_t find_first_of(const CharT c, size_t From = 0) const { for (size_t Pos = From; Pos < size(); ++Pos) if ((*this)[Pos] == c) @@ -191,7 +199,7 @@ public: } // Finds the last occurence of c in this view, ending at position End. - LIBC_INLINE constexpr size_t find_last_of(const char c, + LIBC_INLINE constexpr size_t find_last_of(const CharT c, size_t End = npos) const { End = End >= size() ? size() : End + 1; for (; End > 0; --End) @@ -200,9 +208,18 @@ public: return npos; } - // Finds the first character not equal to c in this view, starting at position - // From. - LIBC_INLINE constexpr size_t find_first_not_of(const char c, + LIBC_INLINE constexpr size_t find_last_not_of(const char c, + size_t end = npos) const { + end = end >= size() ? size() : end + 1; + for (; end > 0; --end) + if ((*this)[end - 1] != c) + return end - 1; + return npos; + } + + // Finds the first character not equal to c in this view, starting at + // position From. + LIBC_INLINE constexpr size_t find_first_not_of(const CharT c, size_t From = 0) const { for (size_t Pos = From; Pos < size(); ++Pos) if ((*this)[Pos] != c) @@ -211,7 +228,7 @@ public: } // Check if this view contains the given character. - LIBC_INLINE constexpr bool contains(char c) const { + LIBC_INLINE constexpr bool contains(CharT c) const { return find_first_of(c) != npos; } }; diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_assignable.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_assignable.h new file mode 100644 index 0000000000000000000000000000000000000000..5978d358798c3fb6cb66a300c15620da3b317fde --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_assignable.h @@ -0,0 +1,63 @@ +//===------------------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// \file +// This file contains a free-standing implementation of is_assignable +// type trait. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_ASSIGNABLE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_ASSIGNABLE_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/CPP/utility/declval.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +namespace is_assignable_detail { + +#if LIBC_HAS_BUILTIN_IS_ASSIGNABLE + +template +struct is_assignable_impl : public bool_constant<__is_assignable(T, U)> {}; + +#else +// Fallback SFINAE implementation for GCC 7 and older toolchains + +template struct is_assignable_impl { +private: + template + LIBC_INLINE static auto test(int) + -> decltype(declval() = declval(), bool_constant()); + + template + LIBC_INLINE static auto test(...) -> bool_constant; + +public: + using type = decltype(test(0)); +}; + +#endif // LIBC_HAS_BUILTIN_IS_ASSIGNABLE + +} // namespace is_assignable_detail + +// is_assignable +template +struct is_assignable : public is_assignable_detail::is_assignable_impl {}; + +template +LIBC_INLINE_VAR constexpr bool is_assignable_v = is_assignable::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_ASSIGNABLE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_constant_evaluated.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_constant_evaluated.h index 0bb2d0806cb0dfe9360733129d38b2491e2cf8c1..dee3f39b7bc970ac69ee2aa5c9e33925bc061838 100644 --- a/lib/libcxx/libc/src/__support/CPP/type_traits/is_constant_evaluated.h +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_constant_evaluated.h @@ -15,7 +15,11 @@ namespace LIBC_NAMESPACE_DECL { namespace cpp { LIBC_INLINE constexpr bool is_constant_evaluated() { +#if LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED return __builtin_is_constant_evaluated(); +#else + return false; +#endif } } // namespace cpp diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_constructible.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_constructible.h new file mode 100644 index 0000000000000000000000000000000000000000..c3ab8afb5ca30a2e96ebf48dda242693d51d51ca --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_constructible.h @@ -0,0 +1,65 @@ +//===------------------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// \file +// This file contains a free-standing implementation of is_constructible +// type trait. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_CONSTRUCTIBLE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_CONSTRUCTIBLE_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/CPP/utility/declval.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +namespace is_contructible_detail { + +#if LIBC_HAS_BUILTIN_IS_CONSTRUCTIBLE + +template +struct is_constructible_impl + : public bool_constant<__is_constructible(T, Args...)> {}; + +#else +// Fallback SFINAE implementation for GCC 7 and older toolchains + +template struct is_constructible_impl { +private: + template + LIBC_INLINE static auto test(int) + -> decltype(T1(declval()...), bool_constant()); + + template + LIBC_INLINE static auto test(...) -> bool_constant; + +public: + using type = decltype(test(0)); +}; + +#endif // LIBC_HAS_BUILTIN_IS_CONSTRUCTIBLE + +} // namespace is_contructible_detail + +template +struct is_constructible + : public is_contructible_detail::is_constructible_impl {}; + +template +LIBC_INLINE_VAR constexpr bool is_constructible_v = + is_constructible::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_CONSTRUCTIBLE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_copy_assignable.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_copy_assignable.h index 9beb93d14668d903c829013db010cbfec98408ad..97c30c668a4e3083399753a69f527a3c9378c50d 100644 --- a/lib/libcxx/libc/src/__support/CPP/type_traits/is_copy_assignable.h +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_copy_assignable.h @@ -9,7 +9,7 @@ #define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_COPY_ASSIGNABLE_H #include "src/__support/CPP/type_traits/add_lvalue_reference.h" -#include "src/__support/CPP/type_traits/integral_constant.h" +#include "src/__support/CPP/type_traits/is_assignable.h" #include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { @@ -18,9 +18,8 @@ namespace cpp { // is copy assignable template struct is_copy_assignable - : public integral_constant< - bool, __is_assignable(cpp::add_lvalue_reference_t, - cpp::add_lvalue_reference_t)> {}; + : public cpp::is_assignable, + cpp::add_lvalue_reference_t> {}; template LIBC_INLINE_VAR constexpr bool is_copy_assignable_v = diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_copy_constructible.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_copy_constructible.h index d8eb9ad3507eec12052ab04348a06261f6ff3bb5..c62db8f69b680093488f0f88c2682cf4342d759e 100644 --- a/lib/libcxx/libc/src/__support/CPP/type_traits/is_copy_constructible.h +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_copy_constructible.h @@ -9,7 +9,7 @@ #define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_COPY_CONSTRUCTIBLE_H #include "src/__support/CPP/type_traits/add_lvalue_reference.h" -#include "src/__support/CPP/type_traits/integral_constant.h" +#include "src/__support/CPP/type_traits/is_constructible.h" #include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { @@ -18,8 +18,7 @@ namespace cpp { // is copy constructible template struct is_copy_constructible - : public integral_constant< - bool, __is_constructible(T, cpp::add_lvalue_reference_t)> {}; + : public cpp::is_constructible> {}; template LIBC_INLINE_VAR constexpr bool is_copy_constructible_v = diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_integral.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_integral.h index 96ba09a07ddc668d37671b5ae503f150d0813eb6..c02bfcd50fea6aa59e662f83da571b2a0da401fa 100644 --- a/lib/libcxx/libc/src/__support/CPP/type_traits/is_integral.h +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_integral.h @@ -26,13 +26,18 @@ private: } public: - LIBC_INLINE_VAR static constexpr bool value = __is_unqualified_any_of< - T, + LIBC_INLINE_VAR static constexpr bool value = + __is_unqualified_any_of(); +#ifdef __cpp_char8_t + char8_t, +#endif + char16_t, char32_t, wchar_t, char, signed char, + unsigned char, short, unsigned short, int, + unsigned int, long, unsigned long, long long, + unsigned long long, bool>(); }; template LIBC_INLINE_VAR constexpr bool is_integral_v = is_integral::value; diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_move_assignable.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_move_assignable.h index a788bd9074e32a14eef830ac3c25673aa7a70728..edffe094c58a37678c92251c2235c2fdf34721bf 100644 --- a/lib/libcxx/libc/src/__support/CPP/type_traits/is_move_assignable.h +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_move_assignable.h @@ -10,7 +10,7 @@ #include "src/__support/CPP/type_traits/add_lvalue_reference.h" #include "src/__support/CPP/type_traits/add_rvalue_reference.h" -#include "src/__support/CPP/type_traits/integral_constant.h" +#include "src/__support/CPP/type_traits/is_assignable.h" #include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { @@ -19,9 +19,8 @@ namespace cpp { // is move assignable template struct is_move_assignable - : public integral_constant, - cpp::add_rvalue_reference_t)> {}; + : public cpp::is_assignable, + cpp::add_rvalue_reference_t> {}; template LIBC_INLINE_VAR constexpr bool is_move_assignable_v = diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_move_constructible.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_move_constructible.h index c89896054625844bad3e15b71301cb64008c0076..37d540c27a5f6aa16da739fcf11f962e68f1766c 100644 --- a/lib/libcxx/libc/src/__support/CPP/type_traits/is_move_constructible.h +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_move_constructible.h @@ -9,7 +9,7 @@ #define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_MOVE_CONSTRUCTIBLE_H #include "src/__support/CPP/type_traits/add_rvalue_reference.h" -#include "src/__support/CPP/type_traits/integral_constant.h" +#include "src/__support/CPP/type_traits/is_constructible.h" #include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { @@ -18,8 +18,7 @@ namespace cpp { // is move constructible template struct is_move_constructible - : public integral_constant)> {}; + : public cpp::is_constructible> {}; template LIBC_INLINE_VAR constexpr bool is_move_constructible_v = diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_unsigned.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_unsigned.h index b4267eedd19fc2418a5f38d2d256f1b7bd24dee1..87c352b2c9564a4283e739ee00ed1a2dd115befc 100644 --- a/lib/libcxx/libc/src/__support/CPP/type_traits/is_unsigned.h +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_unsigned.h @@ -10,7 +10,7 @@ #include "include/llvm-libc-macros/stdfix-macros.h" #include "src/__support/CPP/type_traits/bool_constant.h" -#include "src/__support/CPP/type_traits/is_arithmetic.h" +#include "src/__support/CPP/type_traits/is_integral.h" #include "src/__support/CPP/type_traits/is_same.h" #include "src/__support/CPP/type_traits/remove_cv.h" #include "src/__support/macros/attributes.h" @@ -23,7 +23,7 @@ namespace cpp { #ifndef LIBC_COMPILER_HAS_FIXED_POINT template -struct is_unsigned : bool_constant<(is_arithmetic_v && (T(-1) > T(0)))> { +struct is_unsigned : bool_constant<(is_integral_v && (T(-1) > T(0)))> { LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; } LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; } }; @@ -37,7 +37,7 @@ private: public: LIBC_INLINE_VAR static constexpr bool value = - (is_arithmetic_v && (T(-1) > T(0))) || + (is_integral_v && (T(-1) > T(0))) || __is_unqualified_any_of LIBC_INLINE static constexpr FPType get_fp_type() { return FPType::IEEE754_Binary64; else if constexpr (LDBL_MANT_DIG == 64) return FPType::X86_Binary80; - else if constexpr (LDBL_MANT_DIG == 113) + // TODO: properly treat double-double type. + // else if constexpr (LDBL_MANT_DIG == 113) + else return FPType::IEEE754_Binary128; } #if defined(LIBC_TYPES_HAS_FLOAT16) @@ -833,21 +835,22 @@ struct FPBits final : public internal::FPRepImpl(), FPBits> { // Constructors. LIBC_INLINE constexpr FPBits() = default; - template LIBC_INLINE constexpr explicit FPBits(XType x) { - using Unqual = typename cpp::remove_cv_t; - if constexpr (cpp::is_same_v) { - UP::bits = cpp::bit_cast(x); - } else if constexpr (cpp::is_same_v) { - UP::bits = x; - } else { - // We don't want accidental type promotions/conversions, so we require - // exact type match. - static_assert(cpp::always_false); - } + template < + typename XType, + cpp::enable_if_t, T>, int> = 0> + LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR explicit FPBits(XType x) { + UP::bits = cpp::bit_cast(x); } + template , StorageType>, int> = 0> + LIBC_INLINE constexpr explicit FPBits(XType x) : UP(x) {} + // Floating-point conversions. - LIBC_INLINE constexpr T get_val() const { return cpp::bit_cast(UP::bits); } + LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR T get_val() const { + return cpp::bit_cast(UP::bits); + } }; } // namespace fputil diff --git a/lib/libcxx/libc/src/__support/FPUtil/rounding_mode.h b/lib/libcxx/libc/src/__support/FPUtil/rounding_mode.h index fdc84986a47811b871c9ea8167a43f79ee896df2..3159c1c82ad7f533ef827ffe995ca973d6a85c80 100644 --- a/lib/libcxx/libc/src/__support/FPUtil/rounding_mode.h +++ b/lib/libcxx/libc/src/__support/FPUtil/rounding_mode.h @@ -24,8 +24,12 @@ namespace generic { // 1.0f + 2^-25 = 1.0f for FE_TONEAREST, FE_DOWNWARD, FE_TOWARDZERO // = 0x1.000002f for FE_UPWARD. LIBC_INLINE bool fenv_is_round_up() { +#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + return false; +#else static volatile float x = 0x1.0p-25f; return (1.0f + x != 1.0f); +#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY } // Quick free-standing test whether fegetround() == FE_DOWNWARD. @@ -33,8 +37,12 @@ LIBC_INLINE bool fenv_is_round_up() { // -1.0f - 2^-25 = -1.0f for FE_TONEAREST, FE_UPWARD, FE_TOWARDZERO // = -0x1.000002f for FE_DOWNWARD. LIBC_INLINE bool fenv_is_round_down() { +#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + return false; +#else static volatile float x = 0x1.0p-25f; return (-1.0f - x != -1.0f); +#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY } // Quick free-standing test whether fegetround() == FE_TONEAREST. @@ -44,9 +52,13 @@ LIBC_INLINE bool fenv_is_round_down() { // 1.5f - 2^-24 = 1.5f for FE_TONEAREST, FE_UPWARD // = 0x1.0ffffep-1f for FE_DOWNWARD, FE_TOWARDZERO LIBC_INLINE bool fenv_is_round_to_nearest() { +#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + return true; +#else static volatile float x = 0x1.0p-24f; float y = 1.5f + x; return (y == 1.5f - x); +#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY } // Quick free-standing test whether fegetround() == FE_TOWARDZERO. @@ -60,13 +72,20 @@ LIBC_INLINE bool fenv_is_round_to_nearest() { // = 2^-22 for FE_TONEAREST, FE_UPWARD // = 0 for FE_DOWNWARD LIBC_INLINE bool fenv_is_round_to_zero() { +#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + return false; +#else static volatile float x = 0x1.0p-24f; float y = x; return ((0x1.000002p0f + y) + (-1.0f - y) == 0x1.0p-23f); +#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY } // Quick free standing get rounding mode based on the above observations. LIBC_INLINE int quick_get_round() { +#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + return FE_TONEAREST; +#else static volatile float x = 0x1.0p-24f; float y = x; float z = (0x1.000002p0f + y) + (-1.0f - y); @@ -76,11 +95,12 @@ LIBC_INLINE int quick_get_round() { if (z == 0x1.0p-23f) return FE_TOWARDZERO; return (2.0f + y == 2.0f) ? FE_TONEAREST : FE_UPWARD; +#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY } } // namespace generic -LIBC_INLINE static constexpr bool fenv_is_round_up() { +LIBC_INLINE LIBC_CONSTEXPR_DEFAULT bool fenv_is_round_up() { if (cpp::is_constant_evaluated()) { return false; } else { @@ -88,7 +108,7 @@ LIBC_INLINE static constexpr bool fenv_is_round_up() { } } -LIBC_INLINE static constexpr bool fenv_is_round_down() { +LIBC_INLINE LIBC_CONSTEXPR_DEFAULT bool fenv_is_round_down() { if (cpp::is_constant_evaluated()) { return false; } else { @@ -96,7 +116,7 @@ LIBC_INLINE static constexpr bool fenv_is_round_down() { } } -LIBC_INLINE static constexpr bool fenv_is_round_to_nearest() { +LIBC_INLINE LIBC_CONSTEXPR_DEFAULT bool fenv_is_round_to_nearest() { if (cpp::is_constant_evaluated()) { return true; } else { @@ -104,7 +124,7 @@ LIBC_INLINE static constexpr bool fenv_is_round_to_nearest() { } } -LIBC_INLINE static constexpr bool fenv_is_round_to_zero() { +LIBC_INLINE LIBC_CONSTEXPR_DEFAULT bool fenv_is_round_to_zero() { if (cpp::is_constant_evaluated()) { return false; } else { @@ -113,7 +133,7 @@ LIBC_INLINE static constexpr bool fenv_is_round_to_zero() { } // Quick free standing get rounding mode based on the above observations. -LIBC_INLINE static constexpr int quick_get_round() { +LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int quick_get_round() { if (cpp::is_constant_evaluated()) { return FE_TONEAREST; } else { diff --git a/lib/libcxx/libc/src/__support/big_int.h b/lib/libcxx/libc/src/__support/big_int.h index bb9cefd67b552b8825176c13718490d0064e1e8a..29da5b9866bb009576bed2713b08651687181883 100644 --- a/lib/libcxx/libc/src/__support/big_int.h +++ b/lib/libcxx/libc/src/__support/big_int.h @@ -242,10 +242,9 @@ LIBC_INLINE constexpr void quick_mul_hi(cpp::array &dst, template LIBC_INLINE constexpr bool is_negative(const cpp::array &array) { - using signed_word = cpp::make_signed_t; - return cpp::bit_cast(array.back()) < 0; + constexpr size_t WORD_BITS = cpp::numeric_limits::digits; + return (array.back() >> (WORD_BITS - 1)) != 0; } - // An enum for the shift function below. enum Direction { LEFT, RIGHT }; @@ -257,9 +256,11 @@ LIBC_INLINE constexpr cpp::array shift(cpp::array array, size_t offset) { static_assert(direction == LEFT || direction == RIGHT); constexpr size_t WORD_BITS = cpp::numeric_limits::digits; +#if LIBC_HAS_BUILTIN_BIT_CAST #ifdef LIBC_TYPES_HAS_INT128 constexpr size_t TOTAL_BITS = N * WORD_BITS; - if constexpr (TOTAL_BITS == 128) { + if constexpr (TOTAL_BITS == 128 && + __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) { using type = cpp::conditional_t; auto tmp = cpp::bit_cast(array); if constexpr (direction == LEFT) @@ -269,6 +270,8 @@ LIBC_INLINE constexpr cpp::array shift(cpp::array array, return cpp::bit_cast>(tmp); } #endif +#endif // LIBC_HAS_BUILTIN_BIT_CAST + if (LIBC_UNLIKELY(offset == 0)) return array; const bool is_neg = is_signed && is_negative(array); @@ -336,8 +339,8 @@ private: "WordType must be unsigned integer."); struct Division { - BigInt quotient; - BigInt remainder; + BigInt quotient{}; + BigInt remainder{}; }; public: @@ -355,7 +358,7 @@ public: LIBC_INLINE_VAR static constexpr size_t WORD_COUNT = Bits / WORD_SIZE; - cpp::array val{}; // zero initialized. + cpp::array val; LIBC_INLINE constexpr BigInt() = default; @@ -363,9 +366,10 @@ public: template LIBC_INLINE constexpr BigInt( - const BigInt &other) { + const BigInt &other) + : val{} { using BigIntOther = BigInt; - const bool should_sign_extend = Signed && other.is_neg(); + [[maybe_unused]] const bool should_sign_extend = Signed && other.is_neg(); static_assert(!(Bits == OtherBits && WORD_SIZE != BigIntOther::WORD_SIZE) && "This is currently untested for casting between bigints with " @@ -453,20 +457,22 @@ public: } // Construct a BigInt from a C array. - template LIBC_INLINE constexpr BigInt(const WordType (&nums)[N]) { + template + LIBC_INLINE constexpr BigInt(const WordType (&nums)[N]) : val{} { static_assert(N == WORD_COUNT); for (size_t i = 0; i < WORD_COUNT; ++i) val[i] = nums[i]; } LIBC_INLINE constexpr explicit BigInt( - const cpp::array &words) { + const cpp::array &words) + : val{} { val = words; } // Initialize the first word to |v| and the rest to 0. template >> - LIBC_INLINE constexpr BigInt(T v) { + LIBC_INLINE constexpr BigInt(T v) : val{} { constexpr size_t T_SIZE = sizeof(T) * CHAR_BIT; const bool is_neg = v < 0; for (size_t i = 0; i < WORD_COUNT; ++i) { @@ -488,7 +494,7 @@ public: LIBC_INLINE static constexpr BigInt one() { return BigInt(1); } LIBC_INLINE static constexpr BigInt all_ones() { return ~zero(); } LIBC_INLINE static constexpr BigInt min() { - BigInt out; + BigInt out{}; if constexpr (SIGNED) out.set_msb(); return out; @@ -601,7 +607,7 @@ public: template LIBC_INLINE constexpr auto ful_mul(const BigInt &other) const { - BigInt result; + BigInt result{}; multiword::multiply_with_carry(result.val, val, other.val); return result; } @@ -633,7 +639,7 @@ public: // 256 4 16 10 3 // 512 8 64 36 7 LIBC_INLINE constexpr BigInt quick_mul_hi(const BigInt &other) const { - BigInt result; + BigInt result{}; multiword::quick_mul_hi(result.val, val, other.val); return result; } @@ -686,7 +692,7 @@ public: // And finally we perform some extra alignment steps for the remaining bits. LIBC_INLINE constexpr cpp::optional div_uint_half_times_pow_2(multiword::half_width_t x, size_t e) { - BigInt remainder; + BigInt remainder{}; if (x == 0) return cpp::nullopt; if (e >= Bits) { @@ -694,7 +700,7 @@ public: *this = BigInt(); return remainder; } - BigInt quotient; + BigInt quotient{}; WordType x_word = static_cast(x); constexpr size_t LOG2_WORD_SIZE = static_cast(cpp::bit_width(WORD_SIZE) - 1); @@ -846,13 +852,13 @@ public: #define DEFINE_BINOP(OP) \ LIBC_INLINE friend constexpr BigInt operator OP(const BigInt &lhs, \ const BigInt &rhs) { \ - BigInt result; \ + BigInt result{}; \ for (size_t i = 0; i < WORD_COUNT; ++i) \ result[i] = lhs[i] OP rhs[i]; \ return result; \ } \ - LIBC_INLINE friend constexpr BigInt operator OP##=(BigInt &lhs, \ - const BigInt &rhs) { \ + LIBC_INLINE friend constexpr BigInt operator OP## = \ + (BigInt & lhs, const BigInt &rhs) { \ for (size_t i = 0; i < WORD_COUNT; ++i) \ lhs[i] OP## = rhs[i]; \ return lhs; \ @@ -864,7 +870,7 @@ public: #undef DEFINE_BINOP LIBC_INLINE constexpr BigInt operator~() const { - BigInt result; + BigInt result{}; for (size_t i = 0; i < WORD_COUNT; ++i) result[i] = static_cast(~val[i]); return result; @@ -1004,7 +1010,7 @@ private: LIBC_INLINE constexpr static Division divide_unsigned(const BigInt ÷nd, const BigInt ÷r) { BigInt remainder = dividend; - BigInt quotient; + BigInt quotient{}; if (remainder >= divider) { BigInt subtractor = divider; int cur_bit = multiword::countl_zero(subtractor.val) - @@ -1181,31 +1187,6 @@ LIBC_INLINE_VAR constexpr bool is_unsigned_integral_or_big_int_v = namespace cpp { -// Specialization of cpp::bit_cast ('bit.h') from T to BigInt. -template -LIBC_INLINE constexpr cpp::enable_if_t< - (sizeof(To) == sizeof(From)) && cpp::is_trivially_copyable::value && - cpp::is_trivially_copyable::value && is_big_int::value, - To> -bit_cast(const From &from) { - To out; - using Storage = decltype(out.val); - out.val = cpp::bit_cast(from); - return out; -} - -// Specialization of cpp::bit_cast ('bit.h') from BigInt to T. -template -LIBC_INLINE constexpr cpp::enable_if_t< - sizeof(To) == sizeof(UInt) && - cpp::is_trivially_constructible::value && - cpp::is_trivially_copyable::value && - cpp::is_trivially_copyable>::value, - To> -bit_cast(const UInt &from) { - return cpp::bit_cast(from.val); -} - // Specialization of cpp::popcount ('bit.h') for BigInt. template [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t, int> @@ -1311,7 +1292,7 @@ mask_trailing_ones() { return T::all_ones(); constexpr size_t QUOTIENT = count / T::WORD_SIZE; constexpr size_t REMAINDER = count % T::WORD_SIZE; - T out; // zero initialized + T out{}; for (size_t i = 0; i <= QUOTIENT; ++i) out[i] = i < QUOTIENT ? cpp::numeric_limits::max() @@ -1327,7 +1308,7 @@ LIBC_INLINE constexpr cpp::enable_if_t, T> mask_leading_ones() { return T::all_ones(); constexpr size_t QUOTIENT = (T::BITS - count - 1U) / T::WORD_SIZE; constexpr size_t REMAINDER = count % T::WORD_SIZE; - T out; // zero initialized + T out{}; for (size_t i = QUOTIENT; i < T::WORD_COUNT; ++i) out[i] = i > QUOTIENT ? cpp::numeric_limits::max() @@ -1386,6 +1367,11 @@ first_trailing_one(T value) { return value == 0 ? 0 : cpp::countr_zero(value) + 1; } +static_assert(LIBC_NAMESPACE::cpp::is_trivially_constructible< + LIBC_NAMESPACE::BigInt<128, false>>::value); +static_assert(LIBC_NAMESPACE::cpp::is_trivially_copyable< + LIBC_NAMESPACE::BigInt<128, false>>::value); + } // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC___SUPPORT_BIG_INT_H diff --git a/lib/libcxx/libc/src/__support/common.h b/lib/libcxx/libc/src/__support/common.h index a2808147f3e543c2d1a2ac058d681e16962cd160..d90fe7b8ae98d5c81a3bec0c1adab7922a857045 100644 --- a/lib/libcxx/libc/src/__support/common.h +++ b/lib/libcxx/libc/src/__support/common.h @@ -22,6 +22,10 @@ #define LLVM_LIBC_FUNCTION_ATTR #endif +#ifndef LLVM_LIBC_VARIABLE_ATTR +#define LLVM_LIBC_VARIABLE_ATTR +#endif + // clang-format off // Allow each function `func` to have extra attributes specified by defining: // `LLVM_LIBC_FUNCTION_ATTR_func` macro, which should always start with @@ -33,7 +37,9 @@ // clang-format on #define LLVM_LIBC_EMPTY +#define GET_NOTHING(...) 0 #define GET_SECOND(first, second, ...) second +#define GET_FIFTH(first, second, third, fourth, fifth, ...) fifth #define EXPAND_THEN_SECOND(name) GET_SECOND(name, LLVM_LIBC_EMPTY) #define LLVM_LIBC_ATTR(name) EXPAND_THEN_SECOND(LLVM_LIBC_FUNCTION_ATTR_##name) @@ -44,50 +50,57 @@ // symbol. Moreover, a C symbol `func` in macOS is mangled as `_func`. #if defined(LIBC_COPT_PUBLIC_PACKAGING) && !defined(LIBC_COMPILER_IS_MSVC) #ifndef __APPLE__ -#define LLVM_LIBC_FUNCTION_IMPL(type, name, arglist) \ +#define LLVM_LIBC_FUNCTION_IMPL_4(type, name, arglist, c_alias) \ LLVM_LIBC_ATTR(name) \ LLVM_LIBC_FUNCTION_ATTR decltype(LIBC_NAMESPACE::name) \ - __##name##_impl__ asm(#name); \ - decltype(LIBC_NAMESPACE::name) name [[gnu::alias(#name)]]; \ + __##name##_impl__ asm(c_alias); \ + decltype(LIBC_NAMESPACE::name) name [[gnu::alias(c_alias)]]; \ type __##name##_impl__ arglist #else // __APPLE__ -#define LLVM_LIBC_FUNCTION_IMPL(type, name, arglist) \ +#define LLVM_LIBC_FUNCTION_IMPL_4(type, name, arglist, c_alias) \ LLVM_LIBC_ATTR(name) \ - LLVM_LIBC_FUNCTION_ATTR decltype(LIBC_NAMESPACE::name) name asm("_" #name); \ + LLVM_LIBC_FUNCTION_ATTR decltype(LIBC_NAMESPACE::name) name asm( \ + "_" c_alias); \ type name arglist #endif // __APPLE__ + #else // LIBC_COPT_PUBLIC_PACKAGING -#define LLVM_LIBC_FUNCTION_IMPL(type, name, arglist) type name arglist +#define LLVM_LIBC_FUNCTION_IMPL_4(type, name, arglist, c_alias) \ + type name arglist #endif // LIBC_COPT_PUBLIC_PACKAGING -// This extra layer of macro allows `name` to be a macro to rename a function. -#define LLVM_LIBC_FUNCTION(type, name, arglist) \ - LLVM_LIBC_FUNCTION_IMPL(type, name, arglist) +#define LLVM_LIBC_FUNCTION_IMPL_3(type, name, arglist) \ + LLVM_LIBC_FUNCTION_IMPL_4(type, name, arglist, #name) -namespace LIBC_NAMESPACE_DECL { -namespace internal { -LIBC_INLINE constexpr bool same_string(char const *lhs, char const *rhs) { - for (; *lhs || *rhs; ++lhs, ++rhs) - if (*lhs != *rhs) - return false; - return true; -} -} // namespace internal -} // namespace LIBC_NAMESPACE_DECL +// LLVM_LIBC_FUNCTION(type, name, arglist) is equivalent to +// LLVM_LIBC_FUNCTION(type, name, arglist, #name) +#define LLVM_LIBC_FUNCTION(...) \ + GET_FIFTH(__VA_ARGS__, LLVM_LIBC_FUNCTION_IMPL_4, LLVM_LIBC_FUNCTION_IMPL_3, \ + GET_NOTHING)(__VA_ARGS__) -#define __LIBC_MACRO_TO_STRING(str) #str -#define LIBC_MACRO_TO_STRING(str) __LIBC_MACRO_TO_STRING(str) +// At the moment, [[gnu::alias()]] is not supported on MacOS, and it is needed +// to cleanly export and alias the C++ symbol `LIBC_NAMESPACE::func` with the C +// symbol `func`. So for public packaging on MacOS, we will only export the C +// symbol. Moreover, a C symbol `func` in macOS is mangled as `_func`. +#if defined(LIBC_COPT_PUBLIC_PACKAGING) && !defined(LIBC_COMPILER_IS_MSVC) +#ifndef __APPLE__ +#define LLVM_LIBC_VARIABLE_IMPL(type, name) \ + LLVM_LIBC_ATTR(name) \ + extern LLVM_LIBC_VARIABLE_ATTR decltype(LIBC_NAMESPACE::name) \ + __##name##_impl__ asm(#name); \ + extern decltype(LIBC_NAMESPACE::name) name [[gnu::alias(#name)]]; \ + type __##name##_impl__ +#else // __APPLE__ +#define LLVM_LIBC_VARIABLE_IMPL(type, name) \ + LLVM_LIBC_ATTR(name) \ + extern LLVM_LIBC_VARIABLE_ATTR decltype(LIBC_NAMESPACE::name) name asm( \ + "_" #name); \ + type name +#endif // __APPLE__ +#else // LIBC_COPT_PUBLIC_PACKAGING +#define LLVM_LIBC_VARIABLE_IMPL(type, name) type name +#endif // LIBC_COPT_PUBLIC_PACKAGING -// LLVM_LIBC_IS_DEFINED checks whether a particular macro is defined. -// Usage: constexpr bool kUseAvx = LLVM_LIBC_IS_DEFINED(__AVX__); -// -// This works by comparing the stringified version of the macro with and without -// evaluation. If FOO is not undefined both stringifications yield "FOO". If FOO -// is defined, one stringification yields "FOO" while the other yields its -// stringified value "1". -#define LLVM_LIBC_IS_DEFINED(macro) \ - !LIBC_NAMESPACE::internal::same_string( \ - LLVM_LIBC_IS_DEFINED__EVAL_AND_STRINGIZE(macro), #macro) -#define LLVM_LIBC_IS_DEFINED__EVAL_AND_STRINGIZE(s) #s +#define LLVM_LIBC_VARIABLE(type, name) LLVM_LIBC_VARIABLE_IMPL(type, name) #endif // LLVM_LIBC_SRC___SUPPORT_COMMON_H diff --git a/lib/libcxx/libc/src/__support/ctype_utils.h b/lib/libcxx/libc/src/__support/ctype_utils.h index d60562c02e81cc0457c3837c34b76bd23b285433..e52f6ec425e288f1bba11152d0fde53411d5d435 100644 --- a/lib/libcxx/libc/src/__support/ctype_utils.h +++ b/lib/libcxx/libc/src/__support/ctype_utils.h @@ -37,7 +37,7 @@ namespace internal { // EBCDIC. Technically we could use some smaller ranges, but that's even harder // to read. -LIBC_INLINE static constexpr bool islower(char ch) { +LIBC_INLINE constexpr bool islower(char ch) { switch (ch) { case 'a': case 'b': @@ -71,7 +71,7 @@ LIBC_INLINE static constexpr bool islower(char ch) { } } -LIBC_INLINE static constexpr bool isupper(char ch) { +LIBC_INLINE constexpr bool isupper(char ch) { switch (ch) { case 'A': case 'B': @@ -105,7 +105,7 @@ LIBC_INLINE static constexpr bool isupper(char ch) { } } -LIBC_INLINE static constexpr bool isdigit(char ch) { +LIBC_INLINE constexpr bool isdigit(char ch) { switch (ch) { case '0': case '1': @@ -123,7 +123,7 @@ LIBC_INLINE static constexpr bool isdigit(char ch) { } } -LIBC_INLINE static constexpr char tolower(char ch) { +LIBC_INLINE constexpr char tolower(char ch) { switch (ch) { case 'A': return 'a'; @@ -182,7 +182,7 @@ LIBC_INLINE static constexpr char tolower(char ch) { } } -LIBC_INLINE static constexpr char toupper(char ch) { +LIBC_INLINE constexpr char toupper(char ch) { switch (ch) { case 'a': return 'A'; @@ -241,7 +241,7 @@ LIBC_INLINE static constexpr char toupper(char ch) { } } -LIBC_INLINE static constexpr bool isalpha(char ch) { +LIBC_INLINE constexpr bool isalpha(char ch) { switch (ch) { case 'a': case 'b': @@ -301,7 +301,7 @@ LIBC_INLINE static constexpr bool isalpha(char ch) { } } -LIBC_INLINE static constexpr bool isalnum(char ch) { +LIBC_INLINE constexpr bool isalnum(char ch) { switch (ch) { case 'a': case 'b': @@ -371,7 +371,8 @@ LIBC_INLINE static constexpr bool isalnum(char ch) { } } -LIBC_INLINE static constexpr int b36_char_to_int(char ch) { +#ifndef LIBC_COPT_CTYPE_SMALLER_ASCII +LIBC_INLINE constexpr int b36_char_to_int(char ch) { switch (ch) { case '0': return 0; @@ -475,8 +476,21 @@ LIBC_INLINE static constexpr int b36_char_to_int(char ch) { return 0; } } +#else // LIBC_COPT_SMALL_ASCII_CTYPE +// This version assumes ASCII for the tolower, but generates smaller code since +// the switch version of this function ends up with a table. This should only be +// used when the target is known to be ASCII. +LIBC_INLINE constexpr int b36_char_to_int(char ch) { + if (ch >= '0' && ch <= '9') + return ch - '0'; + char ch_unsafe_lower = ch | 32; + if (ch_unsafe_lower >= 'a' && ch_unsafe_lower <= 'z') + return ch_unsafe_lower - 'a' + 10; + return 0; +} +#endif // LIBC_COPT_SMALL_ASCII_CTYPE -LIBC_INLINE static constexpr char int_to_b36_char(int num) { +LIBC_INLINE constexpr char int_to_b36_char(int num) { // Can't actually use LIBC_ASSERT here because it depends on integer_to_string // which depends on this. @@ -559,7 +573,7 @@ LIBC_INLINE static constexpr char int_to_b36_char(int num) { } } -LIBC_INLINE static constexpr bool isspace(char ch) { +LIBC_INLINE constexpr bool isspace(char ch) { switch (ch) { case ' ': case '\t': @@ -574,14 +588,12 @@ LIBC_INLINE static constexpr bool isspace(char ch) { } // not yet encoding independent. -LIBC_INLINE static constexpr bool isgraph(char ch) { - return 0x20 < ch && ch < 0x7f; -} +LIBC_INLINE constexpr bool isgraph(char ch) { return 0x20 < ch && ch < 0x7f; } // An overload which provides a way to compare input with specific character // values, when input can be of a regular or a wide character type. -LIBC_INLINE static constexpr bool is_char_or_wchar(char ch, char c_value, - [[maybe_unused]] wchar_t) { +LIBC_INLINE constexpr bool is_char_or_wchar(char ch, char c_value, + [[maybe_unused]] wchar_t) { return (ch == c_value); } diff --git a/lib/libcxx/libc/src/__support/high_precision_decimal.h b/lib/libcxx/libc/src/__support/high_precision_decimal.h index 75f2a7607b4253f9eccbd4241cd3b3910f5fa5bf..de22172fd8d3e790c23dcfd350968ad4759fccec 100644 --- a/lib/libcxx/libc/src/__support/high_precision_decimal.h +++ b/lib/libcxx/libc/src/__support/high_precision_decimal.h @@ -1,7 +1,7 @@ //===-- High Precision Decimal ----------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See httpss//llvm.org/LICENSE.txt for license information. +// See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/lib/libcxx/libc/src/__support/libc_assert.h b/lib/libcxx/libc/src/__support/libc_assert.h index 6e0b5bd3d68b45c73685eb1e607f3c92cbb4acd3..26dd0fc2f95624d323b20d58101c852864f5c68f 100644 --- a/lib/libcxx/libc/src/__support/libc_assert.h +++ b/lib/libcxx/libc/src/__support/libc_assert.h @@ -25,8 +25,9 @@ #include "src/__support/OSUtil/exit.h" #include "src/__support/OSUtil/io.h" #include "src/__support/integer_to_string.h" -#include "src/__support/macros/attributes.h" // For LIBC_INLINE +#include "src/__support/macros/attributes.h" // For LIBC_INLINE #include "src/__support/macros/config.h" +#include "src/__support/macros/macro-utils.h" #include "src/__support/macros/optimization.h" // For LIBC_UNLIKELY namespace LIBC_NAMESPACE_DECL { @@ -65,19 +66,11 @@ LIBC_INLINE void report_assertion_failure(const char *assertion, } while (false) #else -// Convert __LINE__ to a string using macros. The indirection is necessary -// because otherwise it will turn "__LINE__" into a string, not its value. The -// value is evaluated in the indirection step. -#define __LIBC_MACRO_TO_STR(x) #x -#define __LIBC_MACRO_TO_STR_INDIR(y) __LIBC_MACRO_TO_STR(y) -#define __LIBC_LINE_STR__ __LIBC_MACRO_TO_STR_INDIR(__LINE__) - #define LIBC_ASSERT(COND) \ do { \ if (LIBC_UNLIKELY(!(COND))) { \ - LIBC_NAMESPACE::write_to_stderr(__FILE__ ":" __LIBC_LINE_STR__ \ - ": Assertion failed: '" #COND \ - "' in function: '"); \ + LIBC_NAMESPACE::write_to_stderr(__FILE__ ":" LLVM_LIBC_STRINGIFY( \ + __LINE__) ": Assertion failed: '" #COND "' in function: '"); \ LIBC_NAMESPACE::write_to_stderr(__PRETTY_FUNCTION__); \ LIBC_NAMESPACE::write_to_stderr("'\n"); \ LIBC_NAMESPACE::internal::exit(0xFF); \ diff --git a/lib/libcxx/libc/src/__support/macros/attributes.h b/lib/libcxx/libc/src/__support/macros/attributes.h index d5ff028634940fdb375b74d477db72651bb4b713..cffcabcd29bd3cd9150b18bdc0416db376f01cd7 100644 --- a/lib/libcxx/libc/src/__support/macros/attributes.h +++ b/lib/libcxx/libc/src/__support/macros/attributes.h @@ -29,6 +29,80 @@ #define LIBC_INLINE_ASM __asm__ __volatile__ #define LIBC_UNUSED __attribute__((unused)) +#ifndef LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED +#if (defined(LIBC_COMPILER_IS_GCC) && (LIBC_COMPILER_GCC_VER >= 900)) || \ + (defined(LIBC_COMPILER_IS_CLANG) && LIBC_COMPILER_CLANG_VER >= 900) +#define LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED 1 +#else +#define LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED \ + (__has_builtin(__builtin_is_constant_evaluated)) +#endif // (defined(LIBC_COMPILER_IS_GCC) && (LIBC_COMPILER_GCC_VER >= 900)) || + // (defined(LIBC_COMPILER_IS_CLANG) && LIBC_COMPILER_CLANG +#endif // LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED + +#ifndef LIBC_HAS_BUILTIN_BIT_CAST +#if __has_builtin(__builtin_bit_cast) || defined(LIBC_COMPILER_IS_MSVC) +#define LIBC_HAS_BUILTIN_BIT_CAST 1 +#else +#define LIBC_HAS_BUILTIN_BIT_CAST 0 +#endif // has_builtin(__builtin_bit_cast) +#endif // LIBC_HAS_BUILTIN_BIT_CAST + +#if LIBC_HAS_BUILTIN_BIT_CAST +#define LIBC_BIT_CAST_CONSTEXPR constexpr +#define LIBC_BIT_CAST_CONSTEXPR_VAR constexpr +#else +#define LIBC_BIT_CAST_CONSTEXPR +#define LIBC_BIT_CAST_CONSTEXPR_VAR const +#endif // LIBC_HAS_BUILTIN_BIT_CAST + +#ifndef LIBC_HAS_CONSTANT_EVALUATION +#define LIBC_HAS_CONSTANT_EVALUATION \ + (LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED && LIBC_HAS_BUILTIN_BIT_CAST) +#endif // LIBC_HAS_CONSTANT_EVALUATION + +#if LIBC_HAS_CONSTANT_EVALUATION +#define LIBC_CONSTEXPR_DEFAULT constexpr +#define LIBC_CONSTEXPR_VAR_DEFAULT constexpr +#else +#define LIBC_CONSTEXPR_DEFAULT +#define LIBC_CONSTEXPR_VAR_DEFAULT const +#endif // LIBC_HAS_CONSTANT_EVALUATION + +// TODO: Remove the macro once Clang/LLVM bump their minimum compilers' version. +// The reason for indirection is GCC is known to fail with constexpr qualified +// functions that doesn't produce constant expression. +// Also, there are some circular dependency in the generic functions without +// __builtin_func for the following functions: +// fputil::fma +// fputil::sqrt +#if LIBC_ENABLE_CONSTEXPR && LIBC_HAS_CONSTANT_EVALUATION +#define LIBC_USE_CONSTEXPR +#define LIBC_CONSTEXPR constexpr +#define LIBC_CONSTEXPR_VAR constexpr +#else +#define LIBC_CONSTEXPR +#define LIBC_CONSTEXPR_VAR const +#endif // LIBC_USE_CONSTEXPR + +#ifndef LIBC_HAS_BUILTIN_IS_ASSIGNABLE +#if (__has_builtin(__is_assignable) || \ + (defined(LIBC_COMPILER_IS_GCC) && (LIBC_COMPILER_GCC_VER >= 800))) +#define LIBC_HAS_BUILTIN_IS_ASSIGNABLE 1 +#else +#define LIBC_HAS_BUILTIN_IS_ASSIGNABLE 0 +#endif +#endif // LIBC_HAS_BUILTIN_IS_ASSIGNABLE + +#ifndef LIBC_HAS_BUILTIN_IS_CONSTRUCTIBLE +#if (__has_builtin(__is_constructible) || \ + (defined(LIBC_COMPILER_IS_GCC) && (LIBC_COMPILER_GCC_VER >= 800))) +#define LIBC_HAS_BUILTIN_IS_CONSTRUCTIBLE 1 +#else +#define LIBC_HAS_BUILTIN_IS_CONSTRUCTIBLE 0 +#endif +#endif // LIBC_HAS_BUILTIN_IS_CONSTRUCTIBLE + // Uses the platform specific specialization #define LIBC_THREAD_MODE_PLATFORM 0 diff --git a/lib/libcxx/libc/src/__support/macros/config.h b/lib/libcxx/libc/src/__support/macros/config.h index b06a890c9c13ccf424267e908fd6844e0540d189..38ad6054738448be04aec16f9788758d83bec3c5 100644 --- a/lib/libcxx/libc/src/__support/macros/config.h +++ b/lib/libcxx/libc/src/__support/macros/config.h @@ -48,6 +48,10 @@ #define __builtin_prefetch(X, Y, Z) +#define LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED 1 +#define LIBC_HAS_BUILTIN_IS_ASSIGNABLE 1 +#define LIBC_HAS_BUILTIN_IS_CONSTRUCTIBLE 1 + #endif // LIBC_COMPILER_IS_MSVC #ifdef __clang__ @@ -66,4 +70,14 @@ #define LIBC_NAMESPACE_DECL LIBC_NAMESPACE #endif +// IMPORTANT (USE WITH CAUTION): This macro is intended to be used at the top of +// the file and set to 1. It alters the signatures of some functions to have +// constexpr qualifier and forces the use of constexpr-compatible +// implementation, which might be a completely different code path or +// instructions. Some of these functions exploit platform-specific non-constexpr +// implementations to achieve certain goals, thus it is disabled by default. +#ifndef LIBC_ENABLE_CONSTEXPR +#define LIBC_ENABLE_CONSTEXPR 0 +#endif + #endif // LLVM_LIBC_SRC___SUPPORT_MACROS_CONFIG_H diff --git a/lib/libcxx/libc/src/__support/macros/macro-utils.h b/lib/libcxx/libc/src/__support/macros/macro-utils.h new file mode 100644 index 0000000000000000000000000000000000000000..1831b820825fa866246d5b99f1b737a40a22c898 --- /dev/null +++ b/lib/libcxx/libc/src/__support/macros/macro-utils.h @@ -0,0 +1,16 @@ +//===-- Macros used by other macros ----------------------------*- 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_MACROS_MACRO_UTILS_H +#define LLVM_LIBC_SRC___SUPPORT_MACROS_MACRO_UTILS_H + +// Stringify the argument after an extra pass of macro expansion. +#define LLVM_LIBC_STRINGIFY(x) LLVM_LIBC_STRINGIFY_IMPL(x) +#define LLVM_LIBC_STRINGIFY_IMPL(x) #x + +#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_MACRO_UTILS_H diff --git a/lib/libcxx/libc/src/__support/macros/optimization.h b/lib/libcxx/libc/src/__support/macros/optimization.h index dbefd20a5cd16bc8e3a3e055447e69001c6e3c03..51091b6d4640430dcf98cb37345642b67601bf75 100644 --- a/lib/libcxx/libc/src/__support/macros/optimization.h +++ b/lib/libcxx/libc/src/__support/macros/optimization.h @@ -32,8 +32,13 @@ LIBC_INLINE constexpr bool expects_bool_condition(T value, T expected) { #define LIBC_LOOP_NOUNROLL _Pragma("nounroll") #define LIBC_LOOP_UNROLL _Pragma("unroll") #elif defined(LIBC_COMPILER_IS_GCC) +#if LIBC_COMPILER_GCC_VER >= 800 #define LIBC_LOOP_NOUNROLL _Pragma("GCC unroll 0") #define LIBC_LOOP_UNROLL _Pragma("GCC unroll 2048") +#else +#define LIBC_LOOP_NOUNROLL +#define LIBC_LOOP_UNROLL +#endif #elif defined(LIBC_COMPILER_IS_MSVC) #define LIBC_LOOP_NOUNROLL #define LIBC_LOOP_UNROLL @@ -47,33 +52,39 @@ LIBC_INLINE constexpr bool expects_bool_condition(T value, T expected) { #define LIBC_MATH_SMALL_TABLES 0x02 #define LIBC_MATH_NO_ERRNO 0x04 #define LIBC_MATH_NO_EXCEPT 0x08 +#define LIBC_MATH_INTERMEDIATE_COMP_IN_FLOAT 0x10 +#define LIBC_MATH_ASSUME_ROUND_NEAREST_ONLY 0x20 #define LIBC_MATH_FAST \ (LIBC_MATH_SKIP_ACCURATE_PASS | LIBC_MATH_SMALL_TABLES | \ - LIBC_MATH_NO_ERRNO | LIBC_MATH_NO_EXCEPT) -#define LIBC_MATH_INTERMEDIATE_COMP_IN_FLOAT 0x10 + LIBC_MATH_NO_ERRNO | LIBC_MATH_NO_EXCEPT | \ + LIBC_MATH_ASSUME_ROUND_NEAREST_ONLY) #ifndef LIBC_MATH #define LIBC_MATH 0 #endif // LIBC_MATH -#if (LIBC_MATH & LIBC_MATH_SKIP_ACCURATE_PASS) +#if ((LIBC_MATH) & LIBC_MATH_SKIP_ACCURATE_PASS) #define LIBC_MATH_HAS_SKIP_ACCURATE_PASS #endif -#if (LIBC_MATH & LIBC_MATH_SMALL_TABLES) +#if ((LIBC_MATH) & LIBC_MATH_SMALL_TABLES) #define LIBC_MATH_HAS_SMALL_TABLES #endif -#if (LIBC_MATH & LIBC_MATH_INTERMEDIATE_COMP_IN_FLOAT) +#if ((LIBC_MATH) & LIBC_MATH_INTERMEDIATE_COMP_IN_FLOAT) #define LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT #endif -#if (LIBC_MATH & LIBC_MATH_NO_ERRNO) +#if ((LIBC_MATH) & LIBC_MATH_NO_ERRNO) #define LIBC_MATH_HAS_NO_ERRNO #endif -#if (LIBC_MATH & LIBC_MATH_NO_EXCEPT) +#if ((LIBC_MATH) & LIBC_MATH_NO_EXCEPT) #define LIBC_MATH_HAS_NO_EXCEPT #endif +#if ((LIBC_MATH) & LIBC_MATH_ASSUME_ROUND_NEAREST_ONLY) +#define LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY +#endif + #endif // LLVM_LIBC_SRC___SUPPORT_MACROS_OPTIMIZATION_H diff --git a/lib/libcxx/libc/src/__support/macros/properties/architectures.h b/lib/libcxx/libc/src/__support/macros/properties/architectures.h index 21e9bc4288cd7c0fcdea0c8b41426226b3b7546f..f73fa7a7643ab605d6fcb10a20f3cdf28a767026 100644 --- a/lib/libcxx/libc/src/__support/macros/properties/architectures.h +++ b/lib/libcxx/libc/src/__support/macros/properties/architectures.h @@ -13,11 +13,16 @@ #define LIBC_TARGET_ARCH_IS_AMDGPU #endif +#if defined(__SPIRV__) +#define LIBC_TARGET_ARCH_IS_SPIRV +#endif + #if defined(__NVPTX__) #define LIBC_TARGET_ARCH_IS_NVPTX #endif -#if defined(LIBC_TARGET_ARCH_IS_NVPTX) || defined(LIBC_TARGET_ARCH_IS_AMDGPU) +#if defined(LIBC_TARGET_ARCH_IS_NVPTX) || \ + defined(LIBC_TARGET_ARCH_IS_AMDGPU) || defined(LIBC_TARGET_ARCH_IS_SPIRV) #define LIBC_TARGET_ARCH_IS_GPU #endif diff --git a/lib/libcxx/libc/src/__support/macros/properties/cpu_features.h b/lib/libcxx/libc/src/__support/macros/properties/cpu_features.h index 1fe20d9b23a34baf470360c34b53475616ff023d..08b5226feff264c38f26ed4c2783874bad46370f 100644 --- a/lib/libcxx/libc/src/__support/macros/properties/cpu_features.h +++ b/lib/libcxx/libc/src/__support/macros/properties/cpu_features.h @@ -56,6 +56,10 @@ #define LIBC_TARGET_CPU_HAS_AVX512BW #endif +#if defined(__AVX512F__) || defined(__AVX2__) +#define LIBC_TARGET_CPU_HAS_GATHER +#endif + #if defined(__ARM_FP) #if (__ARM_FP & 0x2) #define LIBC_TARGET_CPU_HAS_ARM_FPU_HALF @@ -91,13 +95,14 @@ #endif // LIBC_TARGET_CPU_HAS_RISCV_FPU_DOUBLE #endif // __riscv_flen -#if defined(__NVPTX__) || defined(__AMDGPU__) +#if defined(__NVPTX__) || defined(__AMDGPU__) || defined(__SPIRV__) #define LIBC_TARGET_CPU_HAS_FPU_FLOAT #define LIBC_TARGET_CPU_HAS_FPU_DOUBLE #endif #if defined(__ARM_FEATURE_FMA) || (defined(__AVX2__) && defined(__FMA__)) || \ - defined(__NVPTX__) || defined(__AMDGPU__) || defined(__riscv_flen) + defined(__NVPTX__) || defined(__AMDGPU__) || defined(__riscv_flen) || \ + defined(__SPIRV__) #define LIBC_TARGET_CPU_HAS_FMA // Provide a more fine-grained control of FMA instruction for ARM targets. #if defined(LIBC_TARGET_CPU_HAS_FPU_HALF) diff --git a/lib/libcxx/libc/src/__support/macros/sanitizer.h b/lib/libcxx/libc/src/__support/macros/sanitizer.h index 84268a19abbb4608eacaa5b741b07d42d91d6008..abed7a20a35b87a3bf52ae9c9481b3b8276ae6d1 100644 --- a/lib/libcxx/libc/src/__support/macros/sanitizer.h +++ b/lib/libcxx/libc/src/__support/macros/sanitizer.h @@ -26,24 +26,25 @@ #ifdef LIBC_HAS_MEMORY_SANITIZER // Only perform MSAN unpoison in non-constexpr context. #include -#define MSAN_UNPOISON(addr, size) \ +#define LIBC_MSAN_UNPOISON(addr, size) \ do { \ if (!__builtin_is_constant_evaluated()) \ __msan_unpoison(addr, size); \ } while (0) #else -#define MSAN_UNPOISON(ptr, size) +#define LIBC_MSAN_UNPOISON(ptr, size) #endif #ifdef LIBC_HAS_ADDRESS_SANITIZER #include -#define ASAN_POISON_MEMORY_REGION(addr, size) \ +#define LIBC_ASAN_POISON_MEMORY_REGION(addr, size) \ __asan_poison_memory_region((addr), (size)) -#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \ +#define LIBC_ASAN_UNPOISON_MEMORY_REGION(addr, size) \ __asan_unpoison_memory_region((addr), (size)) #else -#define ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size)) -#define ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size)) +#define LIBC_ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size)) +#define LIBC_ASAN_UNPOISON_MEMORY_REGION(addr, size) \ + ((void)(addr), (void)(size)) #endif #endif // LLVM_LIBC_SRC___SUPPORT_MACROS_SANITIZER_H diff --git a/lib/libcxx/libc/src/__support/math_extras.h b/lib/libcxx/libc/src/__support/math_extras.h index 3d0f2703b69a49de4b5f860acd78b1d109767eb3..b8abf8041c8e7b3a390544078debca98bffaa3ce 100644 --- a/lib/libcxx/libc/src/__support/math_extras.h +++ b/lib/libcxx/libc/src/__support/math_extras.h @@ -80,6 +80,21 @@ template #endif // __builtin_sub_overflow } +template +[[nodiscard]] LIBC_INLINE constexpr bool mul_overflow(T a, T b, T &res) { +#if __has_builtin(__builtin_mul_overflow) + return __builtin_mul_overflow(a, b, &res); +#else + T max = cpp::numeric_limits::max(); + T min = cpp::numeric_limits::min(); + bool overflow = (b > 0 && (a > max / b || a < min / b)) || + (b < 0 && (a < max / b || a > min / b)); + if (!overflow) + res = a * b; + return overflow; +#endif +} + #define RETURN_IF(TYPE, BUILTIN) \ if constexpr (cpp::is_same_v) \ return BUILTIN(a, b, carry_in, &carry_out); diff --git a/lib/libcxx/libc/src/__support/str_to_float.h b/lib/libcxx/libc/src/__support/str_to_float.h index 873a113780650e94bcfe4b37d8a531d8328ef62a..ace2e130a5e19674b9db2ed6d362e1ec27d3e8f9 100644 --- a/lib/libcxx/libc/src/__support/str_to_float.h +++ b/lib/libcxx/libc/src/__support/str_to_float.h @@ -124,7 +124,7 @@ eisel_lemire(ExpandedFloat init_num, // Wider Approximation UInt128 final_approx; // The halfway constant is used to check if the bits that will be shifted away - // intially are all 1. For doubles this is 64 (bitstype size) - 52 (final + // initially are all 1. For doubles this is 64 (bitstype size) - 52 (final // mantissa size) - 3 (we shift away the last two bits separately for // accuracy, and the most significant bit is ignored.) = 9 bits. Similarly, // it's 6 bits for floats in this case. @@ -262,7 +262,7 @@ eisel_lemire(ExpandedFloat init_num, (final_approx_lower < approx_lower ? 1 : 0); // The halfway constant is used to check if the bits that will be shifted away - // intially are all 1. For 80 bit floats this is 128 (bitstype size) - 64 + // initially are all 1. For 80 bit floats this is 128 (bitstype size) - 64 // (final mantissa size) - 3 (we shift away the last two bits separately for // accuracy, and the most significant bit is ignored.) = 61 bits. Similarly, // it's 12 bits for 128 bit floats in this case. @@ -680,17 +680,15 @@ template <> LIBC_INLINE constexpr int32_t get_lower_bound() { // accuracy. template LIBC_INLINE FloatConvertReturn decimal_exp_to_float( - ExpandedFloat init_num, bool truncated, RoundDirection round, - const CharType *__restrict numStart, + ExpandedFloat init_num, [[maybe_unused]] bool truncated, + RoundDirection round, const CharType *__restrict numStart, const size_t num_len = cpp::numeric_limits::max()) { using FPBits = typename fputil::FPBits; - using StorageType = typename FPBits::StorageType; - StorageType mantissa = init_num.mantissa; int32_t exp10 = init_num.exponent; FloatConvertReturn output; - cpp::optional> opt_output; + [[maybe_unused]] cpp::optional> opt_output; // If the exponent is too large and can't be represented in this size of // float, return inf. These bounds are relatively loose, but are mostly @@ -725,6 +723,8 @@ LIBC_INLINE FloatConvertReturn decimal_exp_to_float( #ifndef LIBC_COPT_STRTOFLOAT_DISABLE_EISEL_LEMIRE // Try Eisel-Lemire + using StorageType = typename FPBits::StorageType; + StorageType mantissa = init_num.mantissa; opt_output = eisel_lemire(init_num, round); if (opt_output.has_value()) { if (!truncated) { @@ -1093,7 +1093,7 @@ hexadecimal_string_to_float(const CharType *__restrict src, } template -LIBC_INLINE typename fputil::FPBits::StorageType +LIBC_INLINE constexpr typename fputil::FPBits::StorageType nan_mantissa_from_ncharseq(const CharType *str, size_t len) { using FPBits = typename fputil::FPBits; using StorageType = typename FPBits::StorageType; @@ -1129,7 +1129,9 @@ strtofloatingpoint(const CharType *__restrict src) { size_t index = first_non_whitespace(src); int sign = get_sign(src + index); +#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY bool is_positive = (sign >= 0); +#endif index += (sign != 0); if (sign < 0) { @@ -1146,6 +1148,7 @@ strtofloatingpoint(const CharType *__restrict src) { } RoundDirection round_direction = RoundDirection::Nearest; +#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY switch (fputil::quick_get_round()) { case FE_TONEAREST: round_direction = RoundDirection::Nearest; @@ -1160,6 +1163,7 @@ strtofloatingpoint(const CharType *__restrict src) { round_direction = RoundDirection::Down; break; } +#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY StrToNumResult> parse_result({0, 0}); if (base == 16) { @@ -1221,7 +1225,8 @@ strtofloatingpoint(const CharType *__restrict src) { return {result.get_val(), static_cast(index), error}; } -template LIBC_INLINE StrToNumResult strtonan(const char *arg) { +template +LIBC_INLINE constexpr StrToNumResult strtonan(const char *arg) { using FPBits = typename fputil::FPBits; using StorageType = typename FPBits::StorageType; diff --git a/lib/libcxx/libc/src/__support/str_to_integer.h b/lib/libcxx/libc/src/__support/str_to_integer.h index 2df1ea894e53a5c5207317a284c45c8e1a3bf123..e6e599738bf442d9d43aaf45597eb3a95cf91ab0 100644 --- a/lib/libcxx/libc/src/__support/str_to_integer.h +++ b/lib/libcxx/libc/src/__support/str_to_integer.h @@ -33,7 +33,7 @@ namespace internal { // Returns the idx to the first character in src that is not a whitespace // character (as determined by isspace()) template -LIBC_INLINE size_t +LIBC_INLINE constexpr size_t first_non_whitespace(const CharType *__restrict src, size_t src_len = cpp::numeric_limits::max()) { size_t src_cur = 0; @@ -65,6 +65,18 @@ LIBC_INLINE static bool is_hex_start(const CharType *__restrict src, b36_char_to_int(src[2]) < 16; } +// checks if the next 3 characters of the string pointer are the start of a +// binary number. Does not advance the string pointer. +template +LIBC_INLINE static bool is_binary_start(const CharType *__restrict src, + size_t src_len) { + if (src_len < 3) + return false; + return is_char_or_wchar(src[0], '0', L'0') && + is_char_or_wchar(tolower(src[1]), 'b', L'b') && isalnum(src[2]) && + b36_char_to_int(src[2]) < 2; +} + // Takes the address of the string pointer and parses the base from the start of // it. template @@ -75,6 +87,10 @@ LIBC_INLINE static int infer_base(const CharType *__restrict src, // with values 10 through 15 respectively." (C standard 6.4.4.1) if (is_hex_start(src, src_len)) return 16; + // A binary number is defined as "the prefix 0b or 0B optionally followed + // by a sequence of letters and digits." (C standard 7.24.1.7) + if (is_binary_start(src, src_len)) + return 2; // 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. @@ -94,7 +110,7 @@ LIBC_INLINE static int infer_base(const CharType *__restrict src, // Takes a pointer to a string and the base to convert to. This function is used // as the backend for all of the string to int functions. template -LIBC_INLINE StrToNumResult +LIBC_INLINE constexpr StrToNumResult strtointeger(const CharType *__restrict src, int base, const size_t src_len = cpp::numeric_limits::max()) { using ResultType = make_integral_or_big_int_unsigned_t; @@ -120,6 +136,9 @@ strtointeger(const CharType *__restrict src, int base, if (base == 16 && is_hex_start(src + src_cur, src_len - src_cur)) src_cur = src_cur + 2; + if (base == 2 && is_binary_start(src + src_cur, src_len - src_cur)) + src_cur = src_cur + 2; + constexpr bool IS_UNSIGNED = cpp::is_unsigned_v; ResultType constexpr NEGATIVE_MAX = !IS_UNSIGNED ? static_cast(cpp::numeric_limits::max()) + 1 diff --git a/lib/libcxx/libc/src/__support/wctype/wctype_classification_utils.h b/lib/libcxx/libc/src/__support/wctype/wctype_classification_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..f75c3b674efb4d102c9a955141b205a7691d0500 --- /dev/null +++ b/lib/libcxx/libc/src/__support/wctype/wctype_classification_utils.h @@ -0,0 +1,66 @@ +//===-- Utils for wctype classification 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 +// +//===----------------------------------------------------------------------===// +// DO NOT EDIT MANUALLY. +// This file is generated by libc/utils/wctype_utils scripts. + +#ifndef LLVM_LIBC_SRC___SUPPORT_WCTYPE_WCTYPE_CLASSIFICATION_UTILS_H +#define LLVM_LIBC_SRC___SUPPORT_WCTYPE_WCTYPE_CLASSIFICATION_UTILS_H + +#include "hdr/stdint_proxy.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/CPP/limits.h" +#include "src/__support/libc_assert.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +// Property flags for Unicode categories +enum PropertyFlag : uint8_t { + UPPER = 1 << 0, + LOWER = 1 << 1, + ALPHA = 1 << 2, + SPACE = 1 << 3, + PRINT = 1 << 4, + BLANK = 1 << 5, + CNTRL = 1 << 6, + PUNCT = 1 << 7, +}; + +static_assert(4352 <= cpp::numeric_limits::max()); +static_assert(39168 <= cpp::numeric_limits::max()); + +LIBC_INLINE_VAR constexpr uint16_t LEVEL1_SIZE = 4352; +LIBC_INLINE_VAR constexpr uint16_t LEVEL2_SIZE = 39168; + +// Level 1 table: indexed by (codepoint >> 8), stores level2 block offsets +extern const uint16_t LEVEL1[LEVEL1_SIZE]; + +// Level 2 table: blocks of 256 property flags +extern const uint8_t LEVEL2[LEVEL2_SIZE]; + +// Returns the Unicode property flag for a given wide character. +LIBC_INLINE uint8_t lookup_properties(const wchar_t wc) { + // Out of Unicode range + if (static_cast(wc) > 0x10FFFF) { + return 0; + } + + uint16_t l1_idx = static_cast(wc >> 8); + LIBC_ASSERT(l1_idx < LEVEL1_SIZE); + + uint16_t l2_offset = LEVEL1[l1_idx]; + uint16_t l2_idx = l2_offset + (wc & 0xFF); + LIBC_ASSERT(l2_idx < LEVEL2_SIZE); + + return LEVEL2[l2_idx]; +} + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_WCTYPE_WCTYPE_CLASSIFICATION_UTILS_H diff --git a/lib/libcxx/libc/src/__support/wctype/wctype_conversion_utils.h b/lib/libcxx/libc/src/__support/wctype/wctype_conversion_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..0b799250d675e0592bc63178791227d233a3c9af --- /dev/null +++ b/lib/libcxx/libc/src/__support/wctype/wctype_conversion_utils.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Interface for wctype conversion functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_WCTYPE_WCTYPE_CONVERSION_UTILS_H +#define LLVM_LIBC_SRC___SUPPORT_WCTYPE_WCTYPE_CONVERSION_UTILS_H + +#include "hdr/types/wchar_t.h" +#include "hdr/types/wint_t.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace wctype_internal { + +// Helper functions for non-ASCII case conversions. +// These are implemented in wctype_conversion_utils.cpp using the generated +// maps. +wint_t tolower(wchar_t wch); +wint_t toupper(wchar_t wch); + +} // namespace wctype_internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_WCTYPE_WCTYPE_CONVERSION_UTILS_H diff --git a/lib/libcxx/libc/src/__support/wctype_utils.h b/lib/libcxx/libc/src/__support/wctype_utils.h index 7f17224104ffb9b604bbbea69379527aeee59cc5..4d0ecd2c1c0dcb36ac1b872b09438de45cb50b73 100644 --- a/lib/libcxx/libc/src/__support/wctype_utils.h +++ b/lib/libcxx/libc/src/__support/wctype_utils.h @@ -13,6 +13,18 @@ #include "src/__support/macros/attributes.h" // LIBC_INLINE #include "src/__support/macros/config.h" +#define LIBC_WCTYPE_MODE_ASCII 0 +#define LIBC_WCTYPE_MODE_UTF8 1 + +#ifndef LIBC_CONF_WCTYPE_MODE +#define LIBC_CONF_WCTYPE_MODE LIBC_WCTYPE_MODE_ASCII +#endif + +#if LIBC_CONF_WCTYPE_MODE == LIBC_WCTYPE_MODE_UTF8 +#include "src/__support/wctype/wctype_classification_utils.h" +#include "src/__support/wctype/wctype_conversion_utils.h" +#endif + namespace LIBC_NAMESPACE_DECL { namespace internal { @@ -38,8 +50,94 @@ namespace internal { // 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. +namespace ascii { +LIBC_INLINE constexpr bool islower(wchar_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 islower(wchar_t wch) { +LIBC_INLINE constexpr bool isupper(wchar_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 constexpr bool isdigit(wchar_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 constexpr bool isalpha(wchar_t wch) { switch (wch) { case L'a': case L'b': @@ -67,14 +165,66 @@ LIBC_INLINE static constexpr bool islower(wchar_t wch) { 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 isupper(wchar_t wch) { +LIBC_INLINE constexpr bool isalnum(wchar_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': @@ -101,14 +251,68 @@ LIBC_INLINE static constexpr bool isupper(wchar_t wch) { 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 constexpr bool isspace(wchar_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; + } +} + +LIBC_INLINE constexpr bool isblank(wchar_t wch) { + switch (wch) { + case L' ': + case L'\t': return true; default: return false; } } -LIBC_INLINE static constexpr bool isdigit(wchar_t wch) { +LIBC_INLINE constexpr bool isgraph(wchar_t wch) { + return 0x20 < wch && wch < 0x7f; +} + +LIBC_INLINE constexpr bool isprint(wchar_t wch) { + return (static_cast(wch) - ' ') < 95; +} + +LIBC_INLINE constexpr bool isxdigit(wchar_t wch) { switch (wch) { + case L'a': + case L'b': + case L'c': + case L'd': + case L'e': + case L'f': + case L'A': + case L'B': + case L'C': + case L'D': + case L'E': + case L'F': case L'0': case L'1': case L'2': @@ -125,7 +329,15 @@ LIBC_INLINE static constexpr bool isdigit(wchar_t wch) { } } -LIBC_INLINE static constexpr wchar_t tolower(wchar_t wch) { +LIBC_INLINE constexpr bool iscntrl(wchar_t wch) { + return (wch < 0x20 || wch == 0x7f); +} + +LIBC_INLINE constexpr bool ispunct(wchar_t wch) { + return !isalnum(wch) && isgraph(wch); +} + +LIBC_INLINE constexpr wchar_t tolower(wchar_t wch) { switch (wch) { case L'A': return L'a'; @@ -184,7 +396,7 @@ LIBC_INLINE static constexpr wchar_t tolower(wchar_t wch) { } } -LIBC_INLINE static constexpr wchar_t toupper(wchar_t wch) { +LIBC_INLINE constexpr wchar_t toupper(wchar_t wch) { switch (wch) { case L'a': return L'A'; @@ -243,137 +455,153 @@ LIBC_INLINE static constexpr wchar_t toupper(wchar_t wch) { } } -LIBC_INLINE static constexpr bool isalpha(wchar_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; +} // namespace ascii + +LIBC_INLINE constexpr bool islower(wchar_t wch) { +#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8 + return ascii::islower(wch); +#else + if (static_cast(wch) < 128) { + return ascii::islower(wch); + } + return lookup_properties(wch) & PropertyFlag::LOWER; +#endif +} + +LIBC_INLINE constexpr bool isupper(wchar_t wch) { +#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8 + return ascii::isupper(wch); +#else + if (static_cast(wch) < 128) { + return ascii::isupper(wch); + } + return lookup_properties(wch) & PropertyFlag::UPPER; +#endif +} + +LIBC_INLINE constexpr bool isdigit(wchar_t wch) { + // In C.UT8, only ASCII digits are considered digits + return ascii::isdigit(wch); +} + +LIBC_INLINE constexpr bool isalpha(wchar_t wch) { +#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8 + return ascii::isalpha(wch); +#else + if (static_cast(wch) < 128) { + return ascii::isalpha(wch); + } + return lookup_properties(wch) & PropertyFlag::ALPHA; +#endif +} + +LIBC_INLINE constexpr bool isalnum(wchar_t wch) { +#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8 + return ascii::isalnum(wch); +#else + if (static_cast(wch) < 128) { + return ascii::isalnum(wch); + } + // Only need to check ALPHA, digit cases are covered by ASCII path + return lookup_properties(wch) & PropertyFlag::ALPHA; +#endif +} + +LIBC_INLINE constexpr bool isspace(wchar_t wch) { +#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8 + return ascii::isspace(wch); +#else + if (static_cast(wch) < 128) { + return ascii::isspace(wch); + } + return lookup_properties(wch) & PropertyFlag::SPACE; +#endif +} + +LIBC_INLINE constexpr bool isblank(wchar_t wch) { +#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8 + return ascii::isblank(wch); +#else + if (static_cast(wch) < 128) { + return ascii::isblank(wch); + } + return lookup_properties(wch) & PropertyFlag::BLANK; +#endif +} + +LIBC_INLINE constexpr bool isgraph(wchar_t wch) { +#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8 + return ascii::isgraph(wch); +#else + if (static_cast(wch) < 128) { + return ascii::isgraph(wch); + } + // print && !space + return (lookup_properties(wch) & + (PropertyFlag::PRINT | PropertyFlag::SPACE)) == PropertyFlag::PRINT; +#endif +} + +LIBC_INLINE constexpr bool isprint(wchar_t wch) { +#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8 + return ascii::isprint(wch); +#else + if (static_cast(wch) < 128) { + return ascii::isprint(wch); + } + return lookup_properties(wch) & PropertyFlag::PRINT; +#endif +} +LIBC_INLINE constexpr bool isxdigit(wchar_t wch) { + // Hexadecimal digits are the same in C.UTF8 as in ASCII + return ascii::isxdigit(wch); +} + +LIBC_INLINE constexpr bool iscntrl(wchar_t wch) { +#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8 + return ascii::iscntrl(wch); +#else + if (static_cast(wch) < 128) { + return ascii::iscntrl(wch); + } + return lookup_properties(wch) & PropertyFlag::CNTRL; +#endif +} + +LIBC_INLINE constexpr bool ispunct(wchar_t wch) { +#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8 + return ascii::ispunct(wch); +#else + if (static_cast(wch) < 128) { + return ascii::ispunct(wch); + } + return lookup_properties(wch) & PropertyFlag::PUNCT; +#endif +} + +LIBC_INLINE constexpr wchar_t tolower(wchar_t wch) { +#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8 + return ascii::tolower(wch); +#else + if (static_cast(wch) < 128) { + return ascii::tolower(wch); } + return static_cast(wctype_internal::tolower(wch)); +#endif } -LIBC_INLINE static constexpr bool isalnum(wchar_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 constexpr wchar_t toupper(wchar_t wch) { +#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8 + return ascii::toupper(wch); +#else + if (static_cast(wch) < 128) { + return ascii::toupper(wch); } + return static_cast(wctype_internal::toupper(wch)); +#endif } -LIBC_INLINE static constexpr int b36_char_to_int(wchar_t wch) { +LIBC_INLINE constexpr int b36_char_to_int(wchar_t wch) { switch (wch) { case L'0': return 0; @@ -561,20 +789,6 @@ LIBC_INLINE static constexpr wchar_t int_to_b36_wchar(int num) { } } -LIBC_INLINE static constexpr bool isspace(wchar_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; - } -} - // An overload which provides a way to compare input with specific character // values, when input can be of a regular or a wide character type. LIBC_INLINE static constexpr bool