diff options
| author | Mingming Liu <mingmingl@google.com> | 2025-09-10 15:25:31 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-10 15:25:31 -0700 |
| commit | 1417dafa1db9cb1b2b09438aa9f53ea5ab6e36e2 (patch) | |
| tree | 57f4b1f313c8cf74eed8819870f39c36ea263c68 /libc/src/__support | |
| parent | 898b813bc8a6d0276bf0f4769f5f2f64b34e632d (diff) | |
| parent | b8cefcb601ddaa18482555c4ff363c01a270c2fe (diff) | |
Merge branch 'main' into users/mingmingl-llvm/samplefdo-profile-formatusers/mingmingl-llvm/samplefdo-profile-format
Diffstat (limited to 'libc/src/__support')
25 files changed, 576 insertions, 37 deletions
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt index 2196d9e23bba..b6e87ac336fb 100644 --- a/libc/src/__support/CMakeLists.txt +++ b/libc/src/__support/CMakeLists.txt @@ -97,6 +97,7 @@ add_header_library( common.h endian_internal.h macros/properties/architectures.h + macros/properties/compiler.h macros/attributes.h macros/config.h DEPENDS diff --git a/libc/src/__support/CPP/CMakeLists.txt b/libc/src/__support/CPP/CMakeLists.txt index 8b65a8839ab2..d9b86b4fd297 100644 --- a/libc/src/__support/CPP/CMakeLists.txt +++ b/libc/src/__support/CPP/CMakeLists.txt @@ -171,6 +171,7 @@ add_header_library( libc.include.llvm-libc-macros.stdfix_macros libc.src.__support.macros.attributes libc.src.__support.macros.properties.types + libc.src.__support.macros.properties.compiler libc.src.__support.macros.properties.complex_types ) @@ -210,3 +211,17 @@ add_object_library( libc.src.__support.common libc.src.__support.macros.properties.os ) + +add_header_library( + tuple + HDRS + tuple.h + DEPENDS + .utility +) + +add_header_library( + simd + HDRS + simd.h +) diff --git a/libc/src/__support/CPP/algorithm.h b/libc/src/__support/CPP/algorithm.h index 7704b3fa81f0..de0c47369d94 100644 --- a/libc/src/__support/CPP/algorithm.h +++ b/libc/src/__support/CPP/algorithm.h @@ -18,6 +18,12 @@ namespace LIBC_NAMESPACE_DECL { namespace cpp { +template <class T = void> struct plus {}; +template <class T = void> struct multiplies {}; +template <class T = void> struct bit_and {}; +template <class T = void> struct bit_or {}; +template <class T = void> struct bit_xor {}; + template <class T> LIBC_INLINE constexpr const T &max(const T &a, const T &b) { return (a < b) ? b : a; } diff --git a/libc/src/__support/CPP/bit.h b/libc/src/__support/CPP/bit.h index df1b177ecb10..5a997ef55570 100644 --- a/libc/src/__support/CPP/bit.h +++ b/libc/src/__support/CPP/bit.h @@ -104,10 +104,16 @@ countr_zero(T value) { } #if __has_builtin(__builtin_ctzs) ADD_SPECIALIZATION(countr_zero, unsigned short, __builtin_ctzs) -#endif +#endif // __has_builtin(__builtin_ctzs) +#if __has_builtin(__builtin_ctz) ADD_SPECIALIZATION(countr_zero, unsigned int, __builtin_ctz) +#endif // __has_builtin(__builtin_ctz) +#if __has_builtin(__builtin_ctzl) ADD_SPECIALIZATION(countr_zero, unsigned long, __builtin_ctzl) +#endif // __has_builtin(__builtin_ctzl) +#if __has_builtin(__builtin_ctzll) ADD_SPECIALIZATION(countr_zero, unsigned long long, __builtin_ctzll) +#endif // __has_builtin(__builtin_ctzll) #endif // __has_builtin(__builtin_ctzg) /// Count number of 0's from the most significant bit to the least @@ -143,10 +149,16 @@ countl_zero(T value) { } #if __has_builtin(__builtin_clzs) ADD_SPECIALIZATION(countl_zero, unsigned short, __builtin_clzs) -#endif +#endif // __has_builtin(__builtin_clzs) +#if __has_builtin(__builtin_clz) ADD_SPECIALIZATION(countl_zero, unsigned int, __builtin_clz) +#endif // __has_builtin(__builtin_clz) +#if __has_builtin(__builtin_clzl) ADD_SPECIALIZATION(countl_zero, unsigned long, __builtin_clzl) +#endif // __has_builtin(__builtin_clzl) +#if __has_builtin(__builtin_clzll) ADD_SPECIALIZATION(countl_zero, unsigned long long, __builtin_clzll) +#endif // __has_builtin(__builtin_clzll) #endif // __has_builtin(__builtin_clzg) #undef ADD_SPECIALIZATION @@ -283,11 +295,17 @@ popcount(T value) { [[nodiscard]] LIBC_INLINE constexpr int popcount<TYPE>(TYPE value) { \ return BUILTIN(value); \ } +#if __has_builtin(__builtin_popcount) ADD_SPECIALIZATION(unsigned char, __builtin_popcount) ADD_SPECIALIZATION(unsigned short, __builtin_popcount) ADD_SPECIALIZATION(unsigned, __builtin_popcount) +#endif // __builtin_popcount +#if __has_builtin(__builtin_popcountl) ADD_SPECIALIZATION(unsigned long, __builtin_popcountl) +#endif // __builtin_popcountl +#if __has_builtin(__builtin_popcountll) ADD_SPECIALIZATION(unsigned long long, __builtin_popcountll) +#endif // __builtin_popcountll #endif // __builtin_popcountg #undef ADD_SPECIALIZATION diff --git a/libc/src/__support/CPP/simd.h b/libc/src/__support/CPP/simd.h new file mode 100644 index 000000000000..54fe70a6e983 --- /dev/null +++ b/libc/src/__support/CPP/simd.h @@ -0,0 +1,282 @@ +//===-- Portable SIMD library similar to stdx::simd -------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file provides a generic interface into fixed-size SIMD instructions +// using the clang vector type. The API shares some similarities with the +// stdx::simd proposal, but instead chooses to use vectors as primitive types +// with several extra helper functions. +// +//===----------------------------------------------------------------------===// + +#include "hdr/stdint_proxy.h" +#include "src/__support/CPP/algorithm.h" +#include "src/__support/CPP/limits.h" +#include "src/__support/CPP/type_traits.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +#include <stddef.h> + +#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_SIMD_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_SIMD_H + +#if LIBC_HAS_VECTOR_TYPE + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +namespace internal { + +template <typename T> +using get_as_integer_type_t = unsigned _BitInt(sizeof(T) * CHAR_BIT); + +#if defined(LIBC_TARGET_CPU_HAS_AVX512F) +template <typename T> +LIBC_INLINE_VAR constexpr size_t native_vector_size = 64 / sizeof(T); +#elif defined(LIBC_TARGET_CPU_HAS_AVX2) +template <typename T> +LIBC_INLINE_VAR constexpr size_t native_vector_size = 32 / sizeof(T); +#elif defined(LIBC_TARGET_CPU_HAS_SSE2) || defined(LIBC_TARGET_CPU_HAS_ARM_NEON) +template <typename T> +LIBC_INLINE_VAR constexpr size_t native_vector_size = 16 / sizeof(T); +#else +template <typename T> LIBC_INLINE constexpr size_t native_vector_size = 1; +#endif + +template <typename T> LIBC_INLINE constexpr T poison() { + return __builtin_nondeterministic_value(T()); +} +} // namespace internal + +// Type aliases. +template <typename T, size_t N> +using fixed_size_simd = T [[clang::ext_vector_type(N)]]; +template <typename T, size_t N = internal::native_vector_size<T>> +using simd = T [[clang::ext_vector_type(N)]]; +template <typename T> +using simd_mask = simd<bool, internal::native_vector_size<T>>; + +// Type trait helpers. +template <typename T> +struct simd_size : cpp::integral_constant<size_t, __builtin_vectorelements(T)> { +}; +template <class T> constexpr size_t simd_size_v = simd_size<T>::value; + +template <typename T> struct is_simd : cpp::integral_constant<bool, false> {}; +template <typename T, unsigned N> +struct is_simd<simd<T, N>> : cpp::integral_constant<bool, true> {}; +template <class T> constexpr bool is_simd_v = is_simd<T>::value; + +template <typename T> +struct is_simd_mask : cpp::integral_constant<bool, false> {}; +template <unsigned N> +struct is_simd_mask<simd<bool, N>> : cpp::integral_constant<bool, true> {}; +template <class T> constexpr bool is_simd_mask_v = is_simd_mask<T>::value; + +template <typename T> struct simd_element_type; +template <typename T, size_t N> struct simd_element_type<simd<T, N>> { + using type = T; +}; +template <typename T> +using simd_element_type_t = typename simd_element_type<T>::type; + +template <typename T> +using enable_if_simd_t = cpp::enable_if_t<is_simd_v<T>, T>; + +// Casting. +template <typename To, typename From, size_t N> +LIBC_INLINE constexpr static simd<To, N> simd_cast(simd<From, N> v) { + return __builtin_convertvector(v, simd<To, N>); +} + +// SIMD mask operations. +template <size_t N> LIBC_INLINE constexpr static bool all_of(simd<bool, N> m) { + return __builtin_reduce_and(m); +} +template <size_t N> LIBC_INLINE constexpr static bool any_of(simd<bool, N> m) { + return __builtin_reduce_or(m); +} +template <size_t N> LIBC_INLINE constexpr static bool none_of(simd<bool, N> m) { + return !any_of(m); +} +template <size_t N> LIBC_INLINE constexpr static bool some_of(simd<bool, N> m) { + return any_of(m) && !all_of(m); +} +template <size_t N> LIBC_INLINE constexpr static int popcount(simd<bool, N> m) { + return __builtin_popcountg(m); +} +template <size_t N> +LIBC_INLINE constexpr static int find_first_set(simd<bool, N> m) { + return __builtin_ctzg(m); +} +template <size_t N> +LIBC_INLINE constexpr static int find_last_set(simd<bool, N> m) { + constexpr size_t size = simd_size_v<simd<bool, N>>; + return size - 1 - __builtin_clzg(m); +} + +// Elementwise operations. +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> min(simd<T, N> x, simd<T, N> y) { + return __builtin_elementwise_min(x, y); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> max(simd<T, N> x, simd<T, N> y) { + return __builtin_elementwise_max(x, y); +} + +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> abs(simd<T, N> x) { + return __builtin_elementwise_abs(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> fma(simd<T, N> x, simd<T, N> y, + simd<T, N> z) { + return __builtin_elementwise_fma(x, y, z); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> ceil(simd<T, N> x) { + return __builtin_elementwise_ceil(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> floor(simd<T, N> x) { + return __builtin_elementwise_floor(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> roundeven(simd<T, N> x) { + return __builtin_elementwise_roundeven(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> round(simd<T, N> x) { + return __builtin_elementwise_round(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> trunc(simd<T, N> x) { + return __builtin_elementwise_trunc(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> nearbyint(simd<T, N> x) { + return __builtin_elementwise_nearbyint(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> rint(simd<T, N> x) { + return __builtin_elementwise_rint(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> canonicalize(simd<T, N> x) { + return __builtin_elementwise_canonicalize(x); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> copysign(simd<T, N> x, simd<T, N> y) { + return __builtin_elementwise_copysign(x, y); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> fmod(simd<T, N> x, simd<T, N> y) { + return __builtin_elementwise_fmod(x, y); +} + +// Reduction operations. +template <typename T, size_t N, typename Op = cpp::plus<>> +LIBC_INLINE constexpr static T reduce(simd<T, N> v, Op op = {}) { + return reduce(v, op); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static T reduce(simd<T, N> v, cpp::plus<>) { + return __builtin_reduce_add(v); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static T reduce(simd<T, N> v, cpp::multiplies<>) { + return __builtin_reduce_mul(v); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static T reduce(simd<T, N> v, cpp::bit_and<>) { + return __builtin_reduce_and(v); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static T reduce(simd<T, N> v, cpp::bit_or<>) { + return __builtin_reduce_or(v); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static T reduce(simd<T, N> v, cpp::bit_xor<>) { + return __builtin_reduce_xor(v); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static T hmin(simd<T, N> v) { + return __builtin_reduce_min(v); +} +template <typename T, size_t N> +LIBC_INLINE constexpr static T hmax(simd<T, N> v) { + return __builtin_reduce_max(v); +} + +// Accessor helpers. +template <typename T> +LIBC_INLINE enable_if_simd_t<T> load_unaligned(const void *ptr) { + T tmp; + __builtin_memcpy(&tmp, ptr, sizeof(T)); + return tmp; +} +template <typename T> +LIBC_INLINE enable_if_simd_t<T> load_aligned(const void *ptr) { + return load_unaligned<T>(__builtin_assume_aligned(ptr, alignof(T))); +} +template <typename T> +LIBC_INLINE enable_if_simd_t<T> store_unaligned(T v, void *ptr) { + __builtin_memcpy(ptr, &v, sizeof(T)); +} +template <typename T> +LIBC_INLINE enable_if_simd_t<T> store_aligned(T v, void *ptr) { + store_unaligned<T>(v, __builtin_assume_aligned(ptr, alignof(T))); +} +template <typename T> +LIBC_INLINE enable_if_simd_t<T> +masked_load(simd<bool, simd_size_v<T>> m, void *ptr, + T passthru = internal::poison<simd_element_type<T>>()) { + return __builtin_masked_load(m, ptr, passthru); +} +template <typename T> +LIBC_INLINE enable_if_simd_t<T> masked_store(simd<bool, simd_size_v<T>> m, T v, + void *ptr) { + __builtin_masked_store( + m, v, static_cast<T *>(__builtin_assume_aligned(ptr, alignof(T)))); +} + +// Construction helpers. +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> splat(T v) { + return simd<T, N>(v); +} +template <typename T> LIBC_INLINE constexpr static simd<T> splat(T v) { + return splat<T, simd_size_v<simd<T>>>(v); +} +template <typename T, unsigned N> +LIBC_INLINE constexpr static simd<T, N> iota(T base = T(0), T step = T(1)) { + simd<T, N> v{}; + for (unsigned i = 0; i < N; ++i) + v[i] = base + T(i) * step; + return v; +} +template <typename T> +LIBC_INLINE constexpr static simd<T> iota(T base = T(0), T step = T(1)) { + return iota<T, simd_size_v<simd<T>>>(base, step); +} + +// Conditional helpers. +template <typename T, size_t N> +LIBC_INLINE constexpr static simd<T, N> select(simd<bool, N> m, simd<T, N> x, + simd<T, N> y) { + return m ? x : y; +} + +// TODO: where expressions, scalar overloads, ABI types. + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_HAS_VECTOR_TYPE +#endif diff --git a/libc/src/__support/CPP/tuple.h b/libc/src/__support/CPP/tuple.h new file mode 100644 index 000000000000..cce8e0ef2bfa --- /dev/null +++ b/libc/src/__support/CPP/tuple.h @@ -0,0 +1,144 @@ +//===-- tuple utility -------------------------------------------*- 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_CPP_UTILITY_TUPLE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_TUPLE_H + +#include "src/__support/CPP/type_traits/decay.h" +#include "src/__support/CPP/utility/integer_sequence.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +template <typename... Ts> struct tuple; +template <> struct tuple<> {}; + +template <typename Head, typename... Tail> +struct tuple<Head, Tail...> : tuple<Tail...> { + Head head; + + LIBC_INLINE constexpr tuple() = default; + + template <typename OHead, typename... OTail> + LIBC_INLINE constexpr tuple &operator=(const tuple<OHead, OTail...> &other) { + head = other.get_head(); + this->get_tail() = other.get_tail(); + return *this; + } + + LIBC_INLINE constexpr tuple(const Head &h, const Tail &...t) + : tuple<Tail...>(t...), head(h) {} + + LIBC_INLINE constexpr Head &get_head() { return head; } + LIBC_INLINE constexpr const Head &get_head() const { return head; } + + LIBC_INLINE constexpr tuple<Tail...> &get_tail() { return *this; } + LIBC_INLINE constexpr const tuple<Tail...> &get_tail() const { return *this; } +}; + +template <typename... Ts> LIBC_INLINE constexpr auto make_tuple(Ts &&...args) { + return tuple<cpp::decay_t<Ts>...>(static_cast<Ts &&>(args)...); +} +template <typename... Ts> LIBC_INLINE constexpr auto tie(Ts &...args) { + return tuple<Ts &...>(args...); +} + +template <size_t I, typename Head, typename... Tail> +LIBC_INLINE constexpr auto &get(tuple<Head, Tail...> &t) { + if constexpr (I == 0) + return t.get_head(); + else + return get<I - 1>(t.get_tail()); +} +template <size_t I, typename Head, typename... Tail> +LIBC_INLINE constexpr const auto &get(const tuple<Head, Tail...> &t) { + if constexpr (I == 0) + return t.get_head(); + else + return get<I - 1>(t.get_tail()); +} +template <size_t I, typename Head, typename... Tail> +LIBC_INLINE constexpr auto &&get(tuple<Head, Tail...> &&t) { + if constexpr (I == 0) + return static_cast<Head &&>(t.get_head()); + else + return get<I - 1>(static_cast<tuple<Tail...> &&>(t.get_tail())); +} +template <size_t I, typename Head, typename... Tail> +LIBC_INLINE constexpr const auto &&get(const tuple<Head, Tail...> &&t) { + if constexpr (I == 0) + return static_cast<const Head &&>(t.get_head()); + else + return get<I - 1>(static_cast<const tuple<Tail...> &&>(t.get_tail())); +} + +template <typename T> struct tuple_size; +template <typename... Ts> struct tuple_size<tuple<Ts...>> { + static constexpr size_t value = sizeof...(Ts); +}; + +template <size_t I, typename T> struct tuple_element; +template <size_t I, typename Head, typename... Tail> +struct tuple_element<I, tuple<Head, Tail...>> + : tuple_element<I - 1, tuple<Tail...>> {}; +template <typename Head, typename... Tail> +struct tuple_element<0, tuple<Head, Tail...>> { + using type = cpp::remove_cv_t<cpp::remove_reference_t<Head>>; +}; + +namespace internal { +template <typename... As, typename... Bs, size_t... I, size_t... J> +LIBC_INLINE constexpr auto +tuple_cat(const tuple<As...> &a, const tuple<Bs...> &b, + cpp::index_sequence<I...>, cpp::index_sequence<J...>) { + return tuple<As..., Bs...>(get<I>(a)..., get<J>(b)...); +} + +template <typename First, typename Second, typename... Rest> +LIBC_INLINE constexpr auto tuple_cat(const First &f, const Second &s, + const Rest &...rest) { + auto concat = + tuple_cat(f, s, cpp::make_index_sequence<tuple_size<First>::value>{}, + cpp::make_index_sequence<tuple_size<Second>::value>{}); + if constexpr (sizeof...(Rest)) + return tuple_cat(concat, rest...); + else + return concat; +} +} // namespace internal + +template <typename... Tuples> +LIBC_INLINE constexpr auto tuple_cat(const Tuples &...tuples) { + static_assert(sizeof...(Tuples) > 0, "need at least one element"); + if constexpr (sizeof...(Tuples) == 1) + return (tuples, ...); + else + return internal::tuple_cat(tuples...); +} + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +// Standard namespace definitions required for structured binding support. +namespace std { + +template <class T> struct tuple_size; +template <size_t I, class T> struct tuple_element; + +template <typename... Ts> +struct tuple_size<LIBC_NAMESPACE::cpp::tuple<Ts...>> + : LIBC_NAMESPACE::cpp::tuple_size<LIBC_NAMESPACE::cpp::tuple<Ts...>> {}; + +template <size_t I, typename... Ts> +struct tuple_element<I, LIBC_NAMESPACE::cpp::tuple<Ts...>> + : LIBC_NAMESPACE::cpp::tuple_element<I, LIBC_NAMESPACE::cpp::tuple<Ts...>> { +}; + +} // namespace std + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_TUPLE_H diff --git a/libc/src/__support/CPP/type_traits/is_complex.h b/libc/src/__support/CPP/type_traits/is_complex.h index 23f05c08ccab..5da1a40892c2 100644 --- a/libc/src/__support/CPP/type_traits/is_complex.h +++ b/libc/src/__support/CPP/type_traits/is_complex.h @@ -13,12 +13,17 @@ #include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" // LIBC_TYPES_HAS_CFLOAT16 && LIBC_TYPES_HAS_CFLOAT128 +#include "src/__support/macros/properties/compiler.h" #include "src/__support/macros/properties/complex_types.h" namespace LIBC_NAMESPACE_DECL { namespace cpp { // is_complex +#ifdef LIBC_COMPILER_IS_MSVC +// TODO: Add support for complex types with MSVC. +template <typename T> struct is_complex : false_type {}; +#else template <typename T> struct is_complex { private: template <typename Head, typename... Args> @@ -40,6 +45,8 @@ public: #endif >(); }; +#endif // LIBC_COMPILER_IS_MSVC + template <typename T> LIBC_INLINE_VAR constexpr bool is_complex_v = is_complex<T>::value; template <typename T1, typename T2> diff --git a/libc/src/__support/CPP/utility/integer_sequence.h b/libc/src/__support/CPP/utility/integer_sequence.h index 06643d505aca..17c3dbfd229c 100644 --- a/libc/src/__support/CPP/utility/integer_sequence.h +++ b/libc/src/__support/CPP/utility/integer_sequence.h @@ -5,12 +5,15 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// + #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_INTEGER_SEQUENCE_H #define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_INTEGER_SEQUENCE_H #include "src/__support/CPP/type_traits/is_integral.h" #include "src/__support/macros/config.h" +#include <stddef.h> + namespace LIBC_NAMESPACE_DECL { namespace cpp { @@ -34,6 +37,13 @@ template <typename T, int N> using make_integer_sequence = typename detail::make_integer_sequence<T, N - 1>::type; +// index sequence +template <size_t... Ints> +using index_sequence = integer_sequence<size_t, Ints...>; +template <int N> +using make_index_sequence = + typename detail::make_integer_sequence<size_t, N - 1>::type; + } // namespace cpp } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/__support/FPUtil/BasicOperations.h b/libc/src/__support/FPUtil/BasicOperations.h index 994237ba8492..ca7be6676630 100644 --- a/libc/src/__support/FPUtil/BasicOperations.h +++ b/libc/src/__support/FPUtil/BasicOperations.h @@ -244,7 +244,7 @@ LIBC_INLINE T fdim(T x, T y) { return y; } - return (x > y ? x - y : 0); + return (x > y ? x - y : T(0)); } // Avoid reusing `issignaling` macro. @@ -354,10 +354,7 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> getpayload(T x) { return static_cast<T>(payload_dfloat); } else { - if constexpr (cpp::is_same_v<T, bfloat16>) - return T(static_cast<int>(payload)); - else - return static_cast<T>(payload); + return static_cast<T>(payload); } } diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt index 37520eadba00..e8fc539fd32e 100644 --- a/libc/src/__support/FPUtil/CMakeLists.txt +++ b/libc/src/__support/FPUtil/CMakeLists.txt @@ -231,6 +231,7 @@ add_header_library( Hypot.h DEPENDS .basic_operations + .cast .fenv_impl .fp_bits .rounding_mode diff --git a/libc/src/__support/FPUtil/Hypot.h b/libc/src/__support/FPUtil/Hypot.h index 94da259cd42f..e23f8b52d822 100644 --- a/libc/src/__support/FPUtil/Hypot.h +++ b/libc/src/__support/FPUtil/Hypot.h @@ -12,6 +12,7 @@ #include "BasicOperations.h" #include "FEnvImpl.h" #include "FPBits.h" +#include "cast.h" #include "rounding_mode.h" #include "src/__support/CPP/bit.h" #include "src/__support/CPP/type_traits.h" @@ -133,8 +134,18 @@ LIBC_INLINE T hypot(T x, T y) { uint16_t a_exp = a_bits.get_biased_exponent(); uint16_t b_exp = b_bits.get_biased_exponent(); - if ((a_exp - b_exp >= FPBits_t::FRACTION_LEN + 2) || (x == 0) || (y == 0)) - return x_abs.get_val() + y_abs.get_val(); + if ((a_exp - b_exp >= FPBits_t::FRACTION_LEN + 2) || (x == 0) || (y == 0)) { +#ifdef LIBC_TYPES_HAS_FLOAT16 + if constexpr (cpp::is_same_v<T, float16>) { + // Compiler runtime for basic operations of float16 might not be correctly + // rounded for all rounding modes. + float af = fputil::cast<float>(x_abs.get_val()); + float bf = fputil::cast<float>(y_abs.get_val()); + return fputil::cast<float16>(af + bf); + } else +#endif // LIBC_TYPES_HAS_FLOAT16 + return x_abs.get_val() + y_abs.get_val(); + } uint64_t out_exp = a_exp; StorageType a_mant = a_bits.get_mantissa(); diff --git a/libc/src/__support/FPUtil/bfloat16.h b/libc/src/__support/FPUtil/bfloat16.h index ba97b42e2321..13e151208567 100644 --- a/libc/src/__support/FPUtil/bfloat16.h +++ b/libc/src/__support/FPUtil/bfloat16.h @@ -29,7 +29,9 @@ struct BFloat16 { LIBC_INLINE BFloat16() = default; - template <typename T> LIBC_INLINE constexpr explicit BFloat16(T value) { + template <typename T> + LIBC_INLINE constexpr explicit BFloat16(T value) + : bits(static_cast<uint16_t>(0U)) { if constexpr (cpp::is_floating_point_v<T>) { bits = fputil::cast<bfloat16>(value).bits; } else if constexpr (cpp::is_integral_v<T>) { @@ -46,6 +48,8 @@ struct BFloat16 { xd(sign, 0, value); bits = xd.template as<bfloat16, /*ShouldSignalExceptions=*/true>().bits; + } else if constexpr (cpp::is_convertible_v<T, BFloat16>) { + bits = value.operator BFloat16().bits; } else { bits = fputil::cast<bfloat16>(static_cast<float>(value)).bits; } diff --git a/libc/src/__support/StringUtil/error_to_string.cpp b/libc/src/__support/StringUtil/error_to_string.cpp index 3b22021706bb..38916af83795 100644 --- a/libc/src/__support/StringUtil/error_to_string.cpp +++ b/libc/src/__support/StringUtil/error_to_string.cpp @@ -7,8 +7,10 @@ //===----------------------------------------------------------------------===// #include "error_to_string.h" -#include "platform_errors.h" +#include <stddef.h> + +#include "platform_errors.h" #include "src/__support/CPP/span.h" #include "src/__support/CPP/string_view.h" #include "src/__support/CPP/stringstream.h" @@ -17,10 +19,8 @@ #include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" -#include <stddef.h> - namespace LIBC_NAMESPACE_DECL { -namespace internal { +namespace { constexpr size_t max_buff_size() { constexpr size_t unknown_str_len = sizeof("Unknown error"); @@ -63,23 +63,22 @@ cpp::string_view build_error_string(int err_num, cpp::span<char> buffer) { return buffer_stream.str(); } -} // namespace internal +} // namespace cpp::string_view get_error_string(int err_num) { - return get_error_string(err_num, - {internal::error_buffer, internal::ERR_BUFFER_SIZE}); + return get_error_string(err_num, {error_buffer, ERR_BUFFER_SIZE}); } cpp::string_view get_error_string(int err_num, cpp::span<char> buffer) { - auto opt_str = internal::ERROR_MAPPER.get_str(err_num); + auto opt_str = ERROR_MAPPER.get_str(err_num); if (opt_str) return *opt_str; else - return internal::build_error_string(err_num, buffer); + return build_error_string(err_num, buffer); } cpp::optional<cpp::string_view> try_get_errno_name(int err_num) { - return internal::ERRNO_NAME_MAPPER.get_str(err_num); + return ERRNO_NAME_MAPPER.get_str(err_num); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/__support/StringUtil/platform_errors.h b/libc/src/__support/StringUtil/platform_errors.h index 32e8414b3e3d..5f83865482e7 100644 --- a/libc/src/__support/StringUtil/platform_errors.h +++ b/libc/src/__support/StringUtil/platform_errors.h @@ -9,7 +9,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_STRINGUTIL_PLATFORM_ERRORS_H #define LLVM_LIBC_SRC___SUPPORT_STRINGUTIL_PLATFORM_ERRORS_H -#if defined(__linux__) || defined(__Fuchsia__) +#if defined(__linux__) || defined(__Fuchsia__) || defined(__EMSCRIPTEN__) #include "tables/linux_platform_errors.h" #else #include "tables/minimal_platform_errors.h" diff --git a/libc/src/__support/StringUtil/signal_to_string.cpp b/libc/src/__support/StringUtil/signal_to_string.cpp index b67d28814816..e5863ff1e898 100644 --- a/libc/src/__support/StringUtil/signal_to_string.cpp +++ b/libc/src/__support/StringUtil/signal_to_string.cpp @@ -7,8 +7,11 @@ //===----------------------------------------------------------------------===// #include "signal_to_string.h" -#include "platform_signals.h" +#include <signal.h> +#include <stddef.h> + +#include "platform_signals.h" #include "src/__support/CPP/span.h" #include "src/__support/CPP/string_view.h" #include "src/__support/CPP/stringstream.h" @@ -17,11 +20,8 @@ #include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" -#include <signal.h> -#include <stddef.h> - namespace LIBC_NAMESPACE_DECL { -namespace internal { +namespace { constexpr size_t max_buff_size() { constexpr size_t base_str_len = sizeof("Real-time signal"); @@ -63,19 +63,18 @@ cpp::string_view build_signal_string(int sig_num, cpp::span<char> buffer) { return buffer_stream.str(); } -} // namespace internal +} // namespace cpp::string_view get_signal_string(int sig_num) { - return get_signal_string( - sig_num, {internal::signal_buffer, internal::SIG_BUFFER_SIZE}); + return get_signal_string(sig_num, {signal_buffer, SIG_BUFFER_SIZE}); } cpp::string_view get_signal_string(int sig_num, cpp::span<char> buffer) { - auto opt_str = internal::signal_mapper.get_str(sig_num); + auto opt_str = signal_mapper.get_str(sig_num); if (opt_str) return *opt_str; else - return internal::build_signal_string(sig_num, buffer); + return build_signal_string(sig_num, buffer); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/__support/common.h b/libc/src/__support/common.h index 15209b76978a..a2808147f3e5 100644 --- a/libc/src/__support/common.h +++ b/libc/src/__support/common.h @@ -16,6 +16,7 @@ #include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" #include "src/__support/macros/properties/architectures.h" +#include "src/__support/macros/properties/compiler.h" #ifndef LLVM_LIBC_FUNCTION_ATTR #define LLVM_LIBC_FUNCTION_ATTR @@ -41,12 +42,12 @@ // 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) +#if defined(LIBC_COPT_PUBLIC_PACKAGING) && !defined(LIBC_COMPILER_IS_MSVC) #ifndef __APPLE__ #define LLVM_LIBC_FUNCTION_IMPL(type, name, arglist) \ LLVM_LIBC_ATTR(name) \ LLVM_LIBC_FUNCTION_ATTR decltype(LIBC_NAMESPACE::name) \ - __##name##_impl__ __asm__(#name); \ + __##name##_impl__ asm(#name); \ decltype(LIBC_NAMESPACE::name) name [[gnu::alias(#name)]]; \ type __##name##_impl__ arglist #else // __APPLE__ diff --git a/libc/src/__support/macros/CMakeLists.txt b/libc/src/__support/macros/CMakeLists.txt index a639d3ef89e5..8e17642d02fb 100644 --- a/libc/src/__support/macros/CMakeLists.txt +++ b/libc/src/__support/macros/CMakeLists.txt @@ -4,6 +4,9 @@ add_header_library( config HDRS config.h + DEPENDS + libc.src.__support.macros.properties.architectures + libc.src.__support.macros.properties.compiler ) add_header_library( diff --git a/libc/src/__support/macros/attributes.h b/libc/src/__support/macros/attributes.h index 4ff374b0e4fb..145aa3b65057 100644 --- a/libc/src/__support/macros/attributes.h +++ b/libc/src/__support/macros/attributes.h @@ -17,6 +17,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_ATTRIBUTES_H #define LLVM_LIBC_SRC___SUPPORT_MACROS_ATTRIBUTES_H +#include "config.h" #include "properties/architectures.h" #ifndef __has_attribute @@ -73,4 +74,11 @@ LIBC_THREAD_MODE_EXTERNAL. #define LIBC_PREFERED_TYPE(TYPE) #endif +#if __has_attribute(ext_vector_type) && \ + LIBC_HAS_FEATURE(ext_vector_type_boolean) +#define LIBC_HAS_VECTOR_TYPE 1 +#else +#define LIBC_HAS_VECTOR_TYPE 0 +#endif + #endif // LLVM_LIBC_SRC___SUPPORT_MACROS_ATTRIBUTES_H diff --git a/libc/src/__support/macros/config.h b/libc/src/__support/macros/config.h index 2ab0fba095e6..685188893e7b 100644 --- a/libc/src/__support/macros/config.h +++ b/libc/src/__support/macros/config.h @@ -13,6 +13,13 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_CONFIG_H #define LLVM_LIBC_SRC___SUPPORT_MACROS_CONFIG_H +#include "src/__support/macros/properties/architectures.h" +#include "src/__support/macros/properties/compiler.h" + +#ifdef LIBC_COMPILER_IS_MSVC +#include <intrin.h> +#endif // LIBC_COMPILER_IS_MSVC + // Workaround for compilers that do not support builtin detection. // FIXME: This is only required for the GPU portion which should be moved. #ifndef __has_builtin @@ -27,6 +34,19 @@ #define LIBC_HAS_FEATURE(f) 0 #endif +#ifdef LIBC_COMPILER_IS_MSVC + +// __builtin_trap replacement +#ifdef LIBC_TARGET_ARCH_IS_X86 +#define __builtin_trap __ud2 +#else // arm64 +#define __builtin_trap() __break(1) +#endif + +#define __builtin_expect(value, expectation) (value) + +#endif // LIBC_COMPILER_IS_MSVC + #ifdef __clang__ // Declare a LIBC_NAMESPACE with hidden visibility. `namespace // LIBC_NAMESPACE_DECL {` should be used around all declarations and definitions diff --git a/libc/src/__support/macros/optimization.h b/libc/src/__support/macros/optimization.h index 250a9e060728..dbefd20a5cd1 100644 --- a/libc/src/__support/macros/optimization.h +++ b/libc/src/__support/macros/optimization.h @@ -34,6 +34,9 @@ LIBC_INLINE constexpr bool expects_bool_condition(T value, T expected) { #elif defined(LIBC_COMPILER_IS_GCC) #define LIBC_LOOP_NOUNROLL _Pragma("GCC unroll 0") #define LIBC_LOOP_UNROLL _Pragma("GCC unroll 2048") +#elif defined(LIBC_COMPILER_IS_MSVC) +#define LIBC_LOOP_NOUNROLL +#define LIBC_LOOP_UNROLL #else #error "Unhandled compiler" #endif diff --git a/libc/src/__support/macros/properties/architectures.h b/libc/src/__support/macros/properties/architectures.h index ecc93196be28..21e9bc4288cd 100644 --- a/libc/src/__support/macros/properties/architectures.h +++ b/libc/src/__support/macros/properties/architectures.h @@ -41,6 +41,10 @@ #define LIBC_TARGET_ARCH_IS_ARM #endif +#if defined(__wasm__) +#define LIBC_TARGET_ARCH_IS_WASM +#endif + #if defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) #define LIBC_TARGET_ARCH_IS_AARCH64 #endif diff --git a/libc/src/__support/macros/properties/compiler.h b/libc/src/__support/macros/properties/compiler.h index b9ec0dd1defb..6947bc7aa901 100644 --- a/libc/src/__support/macros/properties/compiler.h +++ b/libc/src/__support/macros/properties/compiler.h @@ -34,10 +34,10 @@ #define LIBC_COMPILER_GCC_VER (__GNUC__ * 100 + __GNUC_MINOR__) #endif -#if defined(_MSC_VER) -#define LIBC_COMPILER_IS_MSC +#if defined(_MSC_VER) && !defined(__clang__) +#define LIBC_COMPILER_IS_MSVC // https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros -#define LIBC_COMPILER_MSC_VER (_MSC_VER) +#define LIBC_COMPILER_MSVC_VER (_MSC_VER) #endif #endif // LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_COMPILER_H diff --git a/libc/src/__support/macros/properties/cpu_features.h b/libc/src/__support/macros/properties/cpu_features.h index fde30eadfd83..fc6099ca6ccc 100644 --- a/libc/src/__support/macros/properties/cpu_features.h +++ b/libc/src/__support/macros/properties/cpu_features.h @@ -59,6 +59,10 @@ #endif // LIBC_TARGET_CPU_HAS_ARM_FPU_DOUBLE #endif // __ARM_FP +#if defined(__ARM_NEON) +#define LIBC_TARGET_CPU_HAS_ARM_NEON +#endif + #if defined(__riscv_flen) // https://github.com/riscv-non-isa/riscv-c-api-doc/blob/main/src/c-api.adoc #if defined(__riscv_zfhmin) diff --git a/libc/src/__support/threads/thread.cpp b/libc/src/__support/threads/thread.cpp index 6f6b75be5766..9618d7829161 100644 --- a/libc/src/__support/threads/thread.cpp +++ b/libc/src/__support/threads/thread.cpp @@ -163,6 +163,8 @@ void call_atexit_callbacks(ThreadAttributes *attrib) { } } +extern "C" void __cxa_thread_finalize() { call_atexit_callbacks(self.attrib); } + } // namespace internal cpp::optional<unsigned int> new_tss_key(TSSDtor *dtor) { diff --git a/libc/src/__support/threads/thread.h b/libc/src/__support/threads/thread.h index 114ab4932af7..6806098653b2 100644 --- a/libc/src/__support/threads/thread.h +++ b/libc/src/__support/threads/thread.h @@ -110,7 +110,7 @@ struct alignas(STACK_ALIGNMENT) ThreadAttributes { ThreadAtExitCallbackMgr *atexit_callback_mgr; void *platform_data; - constexpr ThreadAttributes() + LIBC_INLINE constexpr ThreadAttributes() : detach_state(uint32_t(DetachState::DETACHED)), stack(nullptr), stacksize(0), guardsize(0), tls(0), tls_size(0), owned_stack(false), tid(-1), style(ThreadStyle::POSIX), retval(), |
