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

Matthias Kretz via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jun 2 12:59:00 PDT 2025


================
@@ -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>;
+};
----------------
mattkretz wrote:

I might be missing another specialization, but this will lead to ABI troubles. Consider `simd<int, 8>`. As defined you'll get the ABI of a `[[__gnu__::__vector_size__(8 * sizeof(int))]]` type. But that changes ABI depending on AVX compiler flags (two XMM registers vs. one YMM register). The intent of ABI tags is to have a different `basic_simd` specialization for `simd<int, 8>` depending on `-mavx2`.

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


More information about the libcxx-commits mailing list