[libcxx-commits] [libcxx] [libc++] Start implementing std::datapar::simd (PR #139919)

via libcxx-commits libcxx-commits at lists.llvm.org
Wed May 14 07:54:25 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

<details>
<summary>Changes</summary>



---

Patch is 117.36 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/139919.diff


52 Files Affected:

- (modified) libcxx/include/CMakeLists.txt (+7) 
- (added) libcxx/include/__simd/abi.h (+165) 
- (added) libcxx/include/__simd/basic_simd.h (+350) 
- (added) libcxx/include/__simd/basic_simd_mask.h (+141) 
- (added) libcxx/include/__simd/simd_flags.h (+106) 
- (added) libcxx/include/__type_traits/pack_utils.h (+30) 
- (added) libcxx/include/__type_traits/standard_types.h (+88) 
- (added) libcxx/include/simd (+24) 
- (added) libcxx/test/libcxx/numerics/simd/implementation_defined_conversions.pass.cpp (+42) 
- (added) libcxx/test/std/numerics/simd/simd.class/aliases.compile.pass.cpp (+47) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.binary/add.pass.cpp (+44) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.binary/bitand.pass.cpp (+54) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.binary/bitor.pass.cpp (+54) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.binary/bitshift_left.pass.cpp (+54) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.binary/bitshift_right.pass.cpp (+56) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.binary/divide.pass.cpp (+44) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.binary/modulo.pass.cpp (+53) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.binary/multiply.pass.cpp (+46) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.binary/subtract.pass.cpp (+44) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.binary/xor.pass.cpp (+54) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.cassign/add.pass.cpp (+46) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.cassign/bitand.pass.cpp (+55) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.cassign/bitor.pass.cpp (+55) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.cassign/bitshift_left.pass.cpp (+55) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.cassign/bitshift_right.pass.cpp (+57) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.cassign/divide.pass.cpp (+46) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.cassign/modulo.pass.cpp (+55) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.cassign/multiply.pass.cpp (+46) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.cassign/subtract.pass.cpp (+46) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.cassign/xor.pass.cpp (+54) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.comparison/equality.pass.cpp (+66) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.comparison/ordering.pass.cpp (+77) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.ctor/broadcast.pass.cpp (+91) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.ctor/range.mask.pass.cpp (+46) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.ctor/range.pass.cpp (+46) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.unary/identity.pass.cpp (+43) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.unary/invert.pass.cpp (+53) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.unary/negation.pass.cpp (+44) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.unary/not.pass.cpp (+45) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.unary/postdec.pass.cpp (+46) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.unary/postinc.pass.cpp (+46) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.unary/predec.pass.cpp (+45) 
- (added) libcxx/test/std/numerics/simd/simd.class/simd.unary/preinc.pass.cpp (+45) 
- (added) libcxx/test/std/numerics/simd/simd.class/subscript.assert.pass.cpp (+34) 
- (added) libcxx/test/std/numerics/simd/simd.class/traits.compile.pass.cpp (+39) 
- (added) libcxx/test/std/numerics/simd/simd.flags.compile.pass.cpp (+52) 
- (added) libcxx/test/std/numerics/simd/simd.mask.class/simd.mask.ctor/broadcast.pass.cpp (+44) 
- (added) libcxx/test/std/numerics/simd/simd.mask.class/subscript.assert.pass.cpp (+34) 
- (added) libcxx/test/std/numerics/simd/simd.mask.class/traits.compile.pass.cpp (+37) 
- (added) libcxx/test/std/numerics/simd/simd.mask.reductions.pass.cpp (+248) 
- (added) libcxx/test/std/numerics/simd/utils.h (+47) 
- (modified) libcxx/test/support/type_algorithms.h (+15-16) 


``````````diff
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 255a0474c0f6b..f6fcfa3fa8ed2 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -714,6 +714,10 @@ set(files
   __ranges/view_interface.h
   __ranges/views.h
   __ranges/zip_view.h
+  __simd/abi.h
+  __simd/basic_simd.h
+  __simd/basic_simd_mask.h
+  __simd/simd_flags.h
   __split_buffer
   __std_mbstate_t.h
   __stop_token/atomic_unique_lock.h
@@ -863,6 +867,7 @@ set(files
   __type_traits/maybe_const.h
   __type_traits/nat.h
   __type_traits/negation.h
+  __type_traits/pack_utils.h
   __type_traits/promote.h
   __type_traits/rank.h
   __type_traits/remove_all_extents.h
@@ -875,6 +880,7 @@ set(files
   __type_traits/remove_reference.h
   __type_traits/remove_volatile.h
   __type_traits/result_of.h
+  __type_traits/standard_types.h
   __type_traits/strip_signature.h
   __type_traits/type_identity.h
   __type_traits/type_list.h
@@ -1029,6 +1035,7 @@ set(files
   semaphore
   set
   shared_mutex
+  simd
   source_location
   span
   sstream
diff --git a/libcxx/include/__simd/abi.h b/libcxx/include/__simd/abi.h
new file mode 100644
index 0000000000000..7f54b02a05de8
--- /dev/null
+++ b/libcxx/include/__simd/abi.h
@@ -0,0 +1,165 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 _LIBCPP___SIMD_ABI_H
+#define _LIBCPP___SIMD_ABI_H
+
+#include <__concepts/convertible_to.h>
+#include <__concepts/equality_comparable.h>
+#include <__config>
+#include <__cstddef/size_t.h>
+#include <__type_traits/standard_types.h>
+#include <__utility/integer_sequence.h>
+#include <cstdint>
+
+#if _LIBCPP_STD_VER >= 26
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+namespace datapar {
+
+template <class _Tp>
+inline constexpr bool __is_vectorizable_type_v = __is_standard_integer_type_v<_Tp> || __is_character_type_v<_Tp>;
+
+template <>
+inline constexpr bool __is_vectorizable_type_v<float> = true;
+
+template <>
+inline constexpr bool __is_vectorizable_type_v<double> = true;
+
+template <class _From, class _To>
+concept __value_preserving_convertible = requires(_From __from) { _To{__from}; };
+
+template <class _Tp>
+concept __constexpr_wrapper_like =
+    convertible_to<_Tp, decltype(_Tp::value)> && equality_comparable_with<_Tp, decltype(_Tp::value)> &&
+    bool_constant<_Tp() == _Tp::value>::value &&
+    bool_constant<static_cast<decltype(_Tp::value)>(_Tp()) == _Tp::value>::value;
+
+// [simd.expos]
+using __simd_size_type = int;
+
+template <class _Tp>
+struct __deduce_abi;
+
+template <class _Tp, __simd_size_type _Np>
+  requires __is_vectorizable_type_v<_Tp> && (_Np <= 64)
+using __deduce_abi_t = __deduce_abi<_Tp>::template __apply<_Np>;
+
+template <class _Tp>
+using __native_abi = __deduce_abi<_Tp>::template __apply<4>;
+
+template <class _Tp, class _Abi>
+inline constexpr __simd_size_type __simd_size_v = 0;
+
+template <size_t>
+struct __integer_from_impl;
+
+template <>
+struct __integer_from_impl<1> {
+  using type = uint8_t;
+};
+
+template <>
+struct __integer_from_impl<2> {
+  using type = uint16_t;
+};
+
+template <>
+struct __integer_from_impl<4> {
+  using type = uint32_t;
+};
+
+template <>
+struct __integer_from_impl<8> {
+  using type = uint64_t;
+};
+
+template <size_t _Bytes>
+using __integer_from = __integer_from_impl<_Bytes>::type;
+
+// ABI Types
+
+template <class _Tp, __simd_size_type _Np>
+struct __vector_size_abi {
+  using _SimdT [[__gnu__::__vector_size__(_Np * sizeof(_Tp))]] = _Tp;
+  using _MaskT [[__gnu__::__vector_size__(_Np * sizeof(_Tp))]] = __integer_from<sizeof(_Tp)>;
+
+  _LIBCPP_ALWAYS_INLINE constexpr _SimdT __select(_MaskT __mask, _SimdT __true, _SimdT __false) {
+    return __mask ? __true : __false;
+  }
+
+#  ifdef _LIBCPP_COMPILER_CLANG_BASED
+  using _BoolVec __attribute__((__ext_vector_type__(_Np))) = bool;
+
+  static constexpr auto __int_size = _Np <= 8 ? 8 : _Np <= 16 ? 16 : _Np <= 32 ? 32 : 64;
+  static_assert(__int_size >= _Np);
+
+  using _IntSizeBoolVec __attribute__((__ext_vector_type__(__int_size))) = bool;
+
+  _LIBCPP_ALWAYS_INLINE static constexpr auto __mask_to_int(_BoolVec __mask) noexcept {
+    return [&]<size_t... _Origs, size_t... _Fillers>(index_sequence<_Origs...>, index_sequence<_Fillers...>)
+               _LIBCPP_ALWAYS_INLINE {
+                 auto __vec = __builtin_convertvector(
+                     __builtin_shufflevector(__mask, _BoolVec{}, _Origs..., ((void)_Fillers, _Np)...), _IntSizeBoolVec);
+                 if constexpr (_Np <= 8)
+                   return __builtin_bit_cast(unsigned char, __vec);
+                 else if constexpr (_Np <= 16)
+                   return __builtin_bit_cast(unsigned short, __vec);
+                 else if constexpr (_Np <= 32)
+                   return __builtin_bit_cast(unsigned int, __vec);
+                 else
+                   return __builtin_bit_cast(unsigned long long, __vec);
+               }(make_index_sequence<_Np>{}, make_index_sequence<__int_size - _Np>{});
+  }
+
+  _LIBCPP_ALWAYS_INLINE static constexpr bool __any_of(_MaskT __mask) noexcept {
+    return __builtin_reduce_or(__builtin_convertvector(__mask, _BoolVec));
+  }
+
+  _LIBCPP_ALWAYS_INLINE static constexpr bool __all_of(_MaskT __mask) noexcept {
+    return __builtin_reduce_and(__builtin_convertvector(__mask, _BoolVec));
+  }
+
+  _LIBCPP_ALWAYS_INLINE static constexpr __simd_size_type __reduce_count(_MaskT __mask) noexcept {
+    return __builtin_reduce_add(__builtin_convertvector(__builtin_convertvector(__mask, _BoolVec), _MaskT));
+  }
+
+  _LIBCPP_ALWAYS_INLINE static constexpr __simd_size_type __reduce_min_index(_MaskT __mask) noexcept {
+    return __builtin_ctzg(__mask_to_int(__builtin_convertvector(__mask, _BoolVec)));
+  }
+
+  _LIBCPP_ALWAYS_INLINE static constexpr __simd_size_type __reduce_max_index(_MaskT __mask) noexcept {
+    return __int_size - 1 - __builtin_clzg(__mask_to_int(__builtin_convertvector(__mask, _BoolVec)));
+  }
+#  else
+  _LIBCPP_ALWAYS_INLINE constexpr bool __any_of(_MaskT __mask) noexcept {
+    for (size_t __i = 0; __i != _Np; ++__i) {
+      if (__mask[__i])
+        return true;
+    }
+    return false;
+  }
+#  endif
+};
+
+template <class _Tp>
+  requires __is_vectorizable_type_v<_Tp>
+struct __deduce_abi<_Tp> {
+  template <__simd_size_type _Np>
+  using __apply = __vector_size_abi<_Tp, _Np>;
+};
+
+template <class _Tp, __simd_size_type _Np>
+inline constexpr __simd_size_type __simd_size_v<_Tp, __vector_size_abi<_Tp, _Np>> = _Np;
+
+} // namespace datapar
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 26
+
+#endif // _LIBCPP___SIMD_ABI_H
diff --git a/libcxx/include/__simd/basic_simd.h b/libcxx/include/__simd/basic_simd.h
new file mode 100644
index 0000000000000..acffa012d9ba1
--- /dev/null
+++ b/libcxx/include/__simd/basic_simd.h
@@ -0,0 +1,350 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 _LIBCPP___SIMD_BASIC_SIMD_H
+#define _LIBCPP___SIMD_BASIC_SIMD_H
+
+#include <__assert>
+#include <__concepts/convertible_to.h>
+#include <__config>
+#include <__memory/assume_aligned.h>
+#include <__ranges/concepts.h>
+#include <__simd/abi.h>
+#include <__simd/basic_simd_mask.h>
+#include <__simd/simd_flags.h>
+#include <__type_traits/is_arithmetic.h>
+#include <__type_traits/pack_utils.h>
+#include <__type_traits/remove_const.h>
+#include <__type_traits/remove_cvref.h>
+#include <__utility/integer_sequence.h>
+
+#if _LIBCPP_STD_VER >= 26
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace datapar {
+
+_LIBCPP_DIAGNOSTIC_PUSH
+_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wpsabi")
+template <class _Tp, class _Abi = __native_abi<_Tp>>
+class basic_simd {
+public:
+  using value_type = _Tp;
+  using mask_type  = basic_simd_mask<sizeof(_Tp), _Abi>;
+  using abi_type   = _Abi;
+
+private:
+  using __data_t = abi_type::_SimdT;
+
+  __data_t __data_;
+
+  _LIBCPP_ALWAYS_INLINE static constexpr __data_t __broadcast(value_type __value) {
+    return [&]<size_t... _Indices>(index_sequence<_Indices...>) _LIBCPP_ALWAYS_INLINE noexcept {
+      return __data_t{((void)_Indices, __value)...};
+    }(make_index_sequence<size()>{});
+  }
+
+  template <class _Up>
+  _LIBCPP_ALWAYS_INLINE static constexpr __data_t __load_from_pointer(const _Up* __ptr) {
+    return [&]<size_t... _Indices>(index_sequence<_Indices...>) _LIBCPP_ALWAYS_INLINE noexcept {
+      return __data_t{__ptr[_Indices]...};
+    }(make_index_sequence<size()>{});
+  }
+
+public:
+  static constexpr integral_constant<__simd_size_type, __simd_size_v<value_type, abi_type>> size{};
+
+  constexpr basic_simd() noexcept = default;
+
+  // [simd.ctor]
+  template <convertible_to<value_type> _Up, class _From = remove_cvref_t<_Up>>
+    requires(__value_preserving_convertible<_From, value_type> ||
+             (!is_arithmetic_v<_From> && !__constexpr_wrapper_like<_From>) ||
+             (__constexpr_wrapper_like<_From> && is_arithmetic_v<remove_const_t<decltype(_From::value)>> &&
+              bool_constant<(static_cast<value_type>(_From::value) == _From::value)>::value))
+  _LIBCPP_HIDE_FROM_ABI constexpr basic_simd(_Up&& __value) noexcept : __data_{__broadcast(__value)} {}
+
+  // TODO: converting constructor
+  // TODO: generator constructor
+  // TODO: flag constructor
+  // TODO: mask flag constructortrue
+
+  template <ranges::contiguous_range _Range, class... _Flags>
+  _LIBCPP_HIDE_FROM_ABI constexpr basic_simd(_Range&& __range, simd_flags<_Flags...> = {}) noexcept
+    requires(ranges::size(__range) == size())
+  {
+    static_assert(__is_vectorizable_type_v<ranges::range_value_t<_Range>>, "Range has to be of a vectorizable type");
+    static_assert(__contains_type_v<__type_list<_Flags...>, __convert_flag> ||
+                      __value_preserving_convertible<ranges::range_value_t<_Range>, value_type>,
+                  "implicit conversion is not value preserving - consider using std::datapar::simd_flag_convert");
+    auto* __ptr = std::assume_aligned<__get_align_for<value_type, _Flags...>>(std::to_address(ranges::begin(__range)));
+    __data_     = __load_from_pointer(__ptr);
+  }
+
+  template <ranges::contiguous_range _Range, class... _Flags>
+  _LIBCPP_HIDE_FROM_ABI constexpr basic_simd(
+      _Range&& __range, const mask_type& __mask, simd_flags<_Flags...> = {}) noexcept
+    requires(ranges::size(__range) == size())
+  {
+    static_assert(__is_vectorizable_type_v<ranges::range_value_t<_Range>>, "Range has to be of a vectorizable type");
+    static_assert(__contains_type_v<__type_list<_Flags...>, __convert_flag> ||
+                      __value_preserving_convertible<ranges::range_value_t<_Range>, value_type>,
+                  "implicit conversion is not value preserving - consider using std::datapar::simd_flag_convert");
+    auto* __ptr = std::assume_aligned<__get_align_for<value_type, _Flags...>>(std::to_address(ranges::begin(__range)));
+    __data_     = abi_type::__select(__mask.__data_, __load_from_pointer(__ptr), __broadcast(0));
+  }
+
+  // libc++ extensions
+  _LIBCPP_ALWAYS_INLINE constexpr explicit basic_simd(__data_t __data) noexcept : __data_(__data) {}
+
+  // [simd.subscr]
+  _LIBCPP_HIDE_FROM_ABI constexpr value_type operator[](__simd_size_type __index) const noexcept {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__index >= 0 && __index < size(), "simd::operator[] out of bounds");
+    return __data_[__index];
+  }
+
+  // [simd.unary]
+
+  _LIBCPP_HIDE_FROM_ABI constexpr basic_simd& operator++() noexcept
+    requires requires(value_type __v) { ++__v; }
+  {
+    __data_ += 1;
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr basic_simd operator++(int) noexcept
+    requires requires(value_type __v) { __v++; }
+  {
+    auto __ret = *this;
+    ++*this;
+    return __ret;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr basic_simd& operator--() noexcept
+    requires requires(value_type __v) { --__v; }
+  {
+    __data_ -= 1;
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr basic_simd operator--(int) noexcept
+    requires requires(value_type __v) { __v--; }
+  {
+    auto __ret = *this;
+    --*this;
+    return __ret;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr mask_type operator!() const noexcept
+    requires requires(value_type __v) { !__v; }
+  {
+    return mask_type(!__data_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr basic_simd operator~() const noexcept
+    requires requires(value_type __v) { ~__v; }
+  {
+    return basic_simd(~__data_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr basic_simd operator+() const noexcept
+    requires requires(value_type __v) { +__v; }
+  {
+    return basic_simd(+__data_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr basic_simd operator-() const noexcept
+    requires requires(value_type __v) { -__v; }
+  {
+    return basic_simd(-__data_);
+  }
+
+  // [simd.binary]
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd operator+(const basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v + __v; }
+  {
+    return basic_simd(__lhs.__data_ + __rhs.__data_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd operator-(const basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v - __v; }
+  {
+    return basic_simd(__lhs.__data_ - __rhs.__data_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd operator*(const basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v * __v; }
+  {
+    return basic_simd(__lhs.__data_ * __rhs.__data_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd operator/(const basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v / __v; }
+  {
+    return basic_simd(__lhs.__data_ / __rhs.__data_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd operator%(const basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v % __v; }
+  {
+    return basic_simd(__lhs.__data_ % __rhs.__data_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd operator&(const basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v & __v; }
+  {
+    return basic_simd(__lhs.__data_ & __rhs.__data_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd operator|(const basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v | __v; }
+  {
+    return basic_simd(__lhs.__data_ | __rhs.__data_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd operator^(const basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v ^ __v; }
+  {
+    return basic_simd(__lhs.__data_ ^ __rhs.__data_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd
+  operator<<(const basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v << __v; }
+  {
+    return basic_simd(__lhs.__data_ << __rhs.__data_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd
+  operator>>(const basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v << __v; }
+  {
+    return basic_simd(__lhs.__data_ >> __rhs.__data_);
+  }
+
+  // [simd.cassign]
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator+=(basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v += __v; }
+  {
+    __lhs.__data_ = __lhs.__data_ + __rhs.__data_;
+    return __lhs;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator-=(basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v -= __v; }
+  {
+    __lhs.__data_ = __lhs.__data_ - __rhs.__data_;
+    return __lhs;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator*=(basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v *= __v; }
+  {
+    __lhs.__data_ = __lhs.__data_ * __rhs.__data_;
+    return __lhs;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator/=(basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v /= __v; }
+  {
+    __lhs.__data_ = __lhs.__data_ / __rhs.__data_;
+    return __lhs;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator%=(basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v %= __v; }
+  {
+    __lhs.__data_ = __lhs.__data_ % __rhs.__data_;
+    return __lhs;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator&=(basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v &= __v; }
+  {
+    __lhs.__data_ = __lhs.__data_ & __rhs.__data_;
+    return __lhs;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator|=(basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v |= __v; }
+  {
+    __lhs.__data_ = __lhs.__data_ | __rhs.__data_;
+    return __lhs;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator^=(basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v ^= __v; }
+  {
+    __lhs.__data_ = __lhs.__data_ ^ __rhs.__data_;
+    return __lhs;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator<<=(basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v <<= __v; }
+  {
+    __lhs.__data_ = __lhs.__data_ << __rhs.__data_;
+    return __lhs;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator>>=(basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v >>= __v; }
+  {
+    __lhs.__data_ = __lhs.__data_ >> __rhs.__data_;
+    return __lhs;
+  }
+
+  // [simd.comparisons]
+  _LIBCPP_HIDE_FROM_ABI friend constexpr mask_type operator==(const basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v == __v; }
+  {
+    return mask_type(__lhs.__data_ == __rhs.__data_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr mask_type operator!=(const basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v != __v; }
+  {
+    return mask_type(!(__lhs.__data_ == __rhs.__data_));
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr mask_type operator<(const basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v < __v; }
+  {
+    return mask_type(__lhs.__data_ < __rhs.__data_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr mask_type operator>=(const basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v >= __v; }
+  {
+    return mask_type(__rhs.__data_ <= __lhs.__data_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr mask_type operator>(const basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v > __v; }
+  {
+    return mask_type(__rhs.__data_ < __lhs.__data_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr mask_type operator<=(const basic_simd& __lhs, const basic_simd& __rhs) noexcept
+    requires requires(value_type __v) { __v <= __v; }
+  {
+    return mask_type(__lhs.__data_ <= __rhs.__data_);
+  }
+};
+_LIBCPP_DIAGNOSTIC_POP
+
+template <class _Tp, __simd_size_type _Np = __simd_size_v<_Tp, __native_abi<_Tp>>>
+using simd = basic_simd<_Tp, __deduce_abi_t<_Tp, _Np>>;
+
+} // namespace datapar
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 26
+
+#endif // _LIBCPP___SIMD_BASIC_SIMD_H
diff --git a/libcxx/include/__simd/basic_simd_mask.h b/libcxx/include/__simd/basic_simd_mask.h
new file mode 100644
index 0000000000000..b2f93d1c9705b
--- /dev/null
+++ b/libcxx/include/__simd/basic_simd_mask.h
@@ -0,0 +1,141 @@
+//===------...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/139919


More information about the libcxx-commits mailing list