timshen updated this revision to Diff 129009.
timshen added a comment.

Rebased.


https://reviews.llvm.org/D41412

Files:
  libcxx/include/experimental/simd
  libcxx/test/std/experimental/simd/simd.horizontal/concat.pass.cpp
  libcxx/test/std/experimental/simd/simd.horizontal/split.pass.cpp

Index: libcxx/test/std/experimental/simd/simd.horizontal/split.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.horizontal/split.pass.cpp
@@ -0,0 +1,125 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/simd>
+//
+// template <size_t... Sizes, class T, class Abi>
+// tuple<simd<T, abi_for_size_t<Sizes>>...> split(const simd<T, Abi>&);
+//
+// template <size_t... Sizes, class T, class Abi>
+// tuple<simd_mask<T, abi_for_size_t<Sizes>>...> split(const simd_mask<T, Abi>&);
+//
+// template <class V, class Abi>
+// array<V, simd_size_v<typename V::value_type, Abi> / V::size()> split(
+//     const simd<typename V::value_type, Abi>&);
+//
+// template <class V, class Abi>
+// array<V, simd_size_v<typename V::value_type, Abi> / V::size()> split(
+//     const simd_mask<typename V::value_type, Abi>&);
+//
+// template <size_t n, class T, class A>
+// array<simd<T, rebind_abi_t<T, simd_size_v<T, A> / n, A>>, n> split_by(
+//     const simd<T, A>& x);
+//
+// template <size_t n, class T, class A>
+// array<simd_mask<T, rebind_abi_t<T, simd_size_v<T, A> / n, A>>, n> split_by(
+//     const simd_mask<T, A>& x);
+
+#include <experimental/simd>
+#include <cassert>
+#include <cstdint>
+
+using namespace std::experimental::parallelism_v2;
+
+void test_split() {
+  auto t = split<1, 2, 3>(fixed_size_simd<int, 6>([](int i) { return i; }));
+  static_assert(std::tuple_size<decltype(t)>::value == 3, "");
+
+  assert(std::get<0>(t).size() == 1);
+  assert(std::get<0>(t)[0] == 0);
+
+  assert(std::get<1>(t).size() == 2);
+  assert(std::get<1>(t)[0] == 1);
+  assert(std::get<1>(t)[1] == 2);
+
+  assert(std::get<2>(t).size() == 3);
+  assert(std::get<2>(t)[0] == 3);
+  assert(std::get<2>(t)[1] == 4);
+  assert(std::get<2>(t)[2] == 5);
+}
+
+void test_split_array() {
+  {
+    auto arr = split_by<2>(fixed_size_simd<int, 6>([](int i) { return i; }));
+    static_assert(arr.size() == 2, "");
+
+    assert(arr[0].size() == 3);
+    assert(arr[0][0] == 0);
+    assert(arr[0][1] == 1);
+    assert(arr[0][2] == 2);
+
+    assert(arr[1].size() == 3);
+    assert(arr[1][0] == 3);
+    assert(arr[1][1] == 4);
+    assert(arr[1][2] == 5);
+  }
+  {
+    auto arr = split<fixed_size_simd<int, 3>>(
+        fixed_size_simd<int, 6>([](int i) { return i; }));
+    static_assert(arr.size() == 2, "");
+
+    assert(arr[0].size() == 3);
+    assert(arr[0][0] == 0);
+    assert(arr[0][1] == 1);
+    assert(arr[0][2] == 2);
+
+    assert(arr[1].size() == 3);
+    assert(arr[1][0] == 3);
+    assert(arr[1][1] == 4);
+    assert(arr[1][2] == 5);
+  }
+}
+
+void compile_split_propagate_abi() {
+  using compatible_simd_half =
+      simd<int,
+           rebind_abi_t<int, simd<int>::size() / 2, simd_abi::compatible<int>>>;
+  using native_simd_half =
+      simd<int, rebind_abi_t<int, native_simd<int>::size() / 2,
+                             simd_abi::native<int>>>;
+
+  static_assert(
+      std::is_same<
+          decltype(
+              split<simd<int>::size() / 2, simd<int>::size() / 2>(simd<int>())),
+          std::tuple<compatible_simd_half, compatible_simd_half>>::value,
+      "");
+
+  static_assert(
+      std::is_same<decltype(
+                       split<native_simd<int>::size() / 2,
+                             native_simd<int>::size() / 2>(native_simd<int>())),
+                   std::tuple<native_simd_half, native_simd_half>>::value,
+      "");
+
+  static_assert(std::is_same<decltype(split_by<2>(simd<int>())),
+                             std::array<compatible_simd_half, 2>>::value,
+                "");
+
+  static_assert(std::is_same<decltype(split_by<2>(native_simd<int>())),
+                             std::array<native_simd_half, 2>>::value,
+                "");
+}
+
+int main() {
+  test_split();
+  test_split_array();
+}
Index: libcxx/test/std/experimental/simd/simd.horizontal/concat.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.horizontal/concat.pass.cpp
@@ -0,0 +1,80 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/simd>
+//
+// template <class T, class... Abis>
+// simd<T, abi_for_size_t<T, (simd_size_v<T, Abis> + ...)>>
+// concat(const simd<T, Abis>&...);
+//
+// template <class T, class Abi, size_t N>
+// simd<T, rebind_abi_t<T, N * simd_size_v<T, Abi>, Abi>>
+// concat(const std::array<simd<T, Abi>, N>& __v);
+//
+// template <class T, class... Abis>
+// simd_mask<T, abi_for_size_t<T, (simd_size_v<T, Abis> + ...)>>
+// concat(const simd_mask<T, Abis>&...);
+//
+// template <class T, class Abi, size_t N>
+// simd_mask<T, rebind_abi_t<T, N * simd_size_v<T, Abi>, Abi>>
+// concat(const std::array<simd_mask<T, Abi>, N>&);
+
+#include <experimental/simd>
+#include <cassert>
+#include <cstdint>
+
+using namespace std::experimental::parallelism_v2;
+
+void test_concat() {
+  auto v = concat(fixed_size_simd<int, 1>([](int i) { return i; }),
+                  fixed_size_simd<int, 2>([](int i) { return i + 1; }),
+                  fixed_size_simd<int, 3>([](int i) { return i + 3; }));
+  static_assert(v.size() == 6, "");
+  assert(v[0] == 0);
+  assert(v[1] == 1);
+  assert(v[2] == 2);
+  assert(v[3] == 3);
+  assert(v[4] == 4);
+  assert(v[5] == 5);
+}
+
+void test_concat_array() {
+  std::array<fixed_size_simd<int, 2>, 2> arr;
+  arr[0] = fixed_size_simd<int, 2>([](int) { return 0; });
+  arr[1] = fixed_size_simd<int, 2>([](int) { return 1; });
+
+  auto v = concat(arr);
+  static_assert(v.size() == 4, "");
+  assert(v[0] == 0);
+  assert(v[1] == 0);
+  assert(v[2] == 1);
+  assert(v[3] == 1);
+}
+
+void compile_split_propagate_abi() {
+  static_assert(std::is_same<typename decltype(
+                                 concat(simd<int>(), simd<int>()))::abi_type,
+                             rebind_abi_t<int, simd<int>::size() * 2,
+                                          simd_abi::compatible<int>>>::value,
+                "");
+
+  static_assert(
+      std::is_same<typename decltype(concat(native_simd<int>(),
+                                            native_simd<int>()))::abi_type,
+                   rebind_abi_t<int, native_simd<int>::size() * 2,
+                                simd_abi::native<int>>>::value,
+      "");
+}
+
+int main() {
+  test_concat();
+  test_concat_array();
+}
Index: libcxx/include/experimental/simd
===================================================================
--- libcxx/include/experimental/simd
+++ libcxx/include/experimental/simd
@@ -968,12 +968,24 @@
 _LIBCPP_INLINE_VAR constexpr bool is_simd_flag_type_v =
     is_simd_flag_type<_Tp>::value;
 #endif
-template <class _Tp, size_t _Np>
+
+// NOTE: _Abis... is the extension proposed by P0820, allowing the APIs to
+// propagate _StorageKind during transforming input type(s) to the output type.
+template <class _Tp, size_t _Np, class... _Abis>
 struct abi_for_size {
   using type = simd_abi::fixed_size<_Np>;
 };
-template <class _Tp, size_t _Np>
-using abi_for_size_t = typename abi_for_size<_Tp, _Np>::type;
+
+template <class _Tp, size_t _Np, _StorageKind __kind, int... __old_size>
+struct abi_for_size<_Tp, _Np, __simd_abi<__kind, __old_size>...> {
+  using type = __simd_abi<__kind, _Np>;
+};
+
+template <class _Tp, size_t _Np, class... _Abis>
+using abi_for_size_t = typename abi_for_size<_Tp, _Np, _Abis...>::type;
+
+template <class _Tp, size_t _Np, class... _Abis>
+using rebind_abi_t = abi_for_size_t<_Tp, _Np, _Abis...>;
 
 template <class _Tp, class _Abi = simd_abi::compatible<_Tp>>
 struct simd_size;
@@ -1080,32 +1092,137 @@
 template <class _Tp, size_t _Np>
 simd_mask<_Tp> to_compatible(const fixed_size_simd_mask<_Tp, _Np>&) noexcept;
 
+template <class _TupleType, class _Tp, size_t... __indicies>
+_TupleType __split_tuple_impl(_Tp** __buffers,
+                              std::index_sequence<__indicies...>) {
+  return _TupleType(typename std::tuple_element<__indicies, _TupleType>::type(
+      __buffers[__indicies], element_aligned_tag())...);
+}
+
 template <size_t... __sizes, class _Tp, class _Abi>
-tuple<simd<_Tp, abi_for_size_t<_Tp, __sizes>>...> split(const simd<_Tp, _Abi>&);
+typename std::enable_if<
+    __variadic_sum<size_t>(__sizes...) == simd<_Tp, _Abi>::size(),
+    tuple<simd<_Tp, rebind_abi_t<_Tp, __sizes, _Abi>>...>>::type
+split(const simd<_Tp, _Abi>& __v) {
+  _Tp __buffer[__v.size()];
+  __v.copy_to(__buffer, element_aligned_tag());
+
+  _Tp* __buffers[sizeof...(__sizes)];
+  {
+    size_t __offsets[] = {__sizes...};
+    size_t __cur_offset = 0;
+    for (size_t __i = 0; __i < sizeof...(__sizes); __i++) {
+      __buffers[__i] = __buffer + __cur_offset;
+      __cur_offset += __offsets[__i];
+    }
+  }
+
+  return __split_tuple_impl<
+      tuple<simd<_Tp, rebind_abi_t<_Tp, __sizes, _Abi>>...>>(
+      __buffers, std::make_index_sequence<sizeof...(__sizes)>());
+}
 
 template <size_t... __sizes, class _Tp, class _Abi>
-tuple<simd_mask<_Tp, abi_for_size_t<_Tp, __sizes>>...>
+tuple<simd_mask<_Tp, rebind_abi_t<_Tp, __sizes, _Abi>>...>
 split(const simd_mask<_Tp, _Abi>&);
 
+// NOTE: P0820 extension
+template <size_t __array_size, class _Tp, class _Abi>
+typename std::enable_if<
+    simd_size<_Tp, _Abi>::value % __array_size == 0,
+    array<simd<_Tp, rebind_abi_t<
+                        _Tp, simd_size<_Tp, _Abi>::value / __array_size, _Abi>>,
+          __array_size>>::type
+split_by(const simd<_Tp, _Abi>& __v) {
+  array<simd<_Tp, rebind_abi_t<_Tp, simd_size<_Tp, _Abi>::value / __array_size,
+                               _Abi>>,
+        __array_size>
+      __ret;
+  constexpr size_t __element_size = simd_size<_Tp, _Abi>::value / __array_size;
+  for (size_t __i = 0; __i < __v.size(); __i++) {
+    __ret[__i / __element_size][__i % __element_size] = __v[__i];
+  }
+  return __ret;
+}
+
 template <class _SimdType, class _Abi>
-array<_SimdType, simd_size<typename _SimdType::value_type, _Abi>::value /
-                     _SimdType::size()>
-split(const simd<typename _SimdType::value_type, _Abi>&);
+typename std::enable_if<
+    is_simd<_SimdType>::value &&
+        simd_size<typename _SimdType::value_type, _Abi>::value %
+                _SimdType::size() ==
+            0,
+    array<_SimdType, simd_size<typename _SimdType::value_type, _Abi>::value /
+                         _SimdType::size()>>::type
+split(const simd<typename _SimdType::value_type, _Abi>& __v) {
+  return split_by<simd_size<typename _SimdType::value_type, _Abi>::value /
+                  _SimdType::size()>(__v);
+}
+
+template <size_t __array_size, class _Tp, class _Abi>
+array<
+    simd_mask<_Tp, rebind_abi_t<_Tp, simd_size<_Tp, _Abi>::value / __array_size,
+                                _Abi>>,
+    __array_size>
+split_by(const simd_mask<_Tp, _Abi>& x);
 
 template <class _SimdType, class _Abi>
 array<_SimdType, simd_size<typename _SimdType::value_type, _Abi>::value /
                      _SimdType::size()>
 split(const simd_mask<typename _SimdType::value_type, _Abi>&);
 
+template <class _TupleType, class _Tp, size_t... __indicies>
+void __concat_tuple_impl(_TupleType __vs, _Tp** __buffers,
+                         std::index_sequence<__indicies...>) {
+  int __unused[] = {(std::get<__indicies>(__vs).copy_to(__buffers[__indicies],
+                                                        element_aligned_tag()),
+                     0)...};
+  (void)__unused;
+}
+
 template <class _Tp, class... _Abis>
-simd<_Tp, abi_for_size_t<_Tp, __variadic_sum(simd_size<_Tp, _Abis>::value...)>>
-concat(const simd<_Tp, _Abis>&...);
+simd<_Tp,
+     rebind_abi_t<_Tp, __variadic_sum<size_t>(simd_size<_Tp, _Abis>::value...),
+                  _Abis...>>
+concat(const simd<_Tp, _Abis>&... __vs) {
+  constexpr auto __size =
+      __variadic_sum<size_t>(simd_size<_Tp, _Abis>::value...);
+  _Tp __buffer[__size];
+  _Tp* __buffers[__size];
+  {
+    size_t __offsets[] = {simd_size<_Tp, _Abis>::value...};
+    size_t __cur_offset = 0;
+    for (size_t __i = 0; __i < __size; __i++) {
+      __buffers[__i] = __buffer + __cur_offset;
+      __cur_offset += __offsets[__i];
+    }
+  }
+  __concat_tuple_impl(std::forward_as_tuple(__vs...), __buffers,
+                      std::make_index_sequence<sizeof...(_Abis)>());
+  return simd<_Tp, rebind_abi_t<_Tp, __size, _Abis...>>(__buffer,
+                                                        element_aligned_tag());
+}
+
+template <class _Tp, class _Abi, size_t _Np>
+simd<_Tp, rebind_abi_t<_Tp, _Np * simd<_Tp, _Abi>::size(), _Abi>>
+concat(const std::array<simd<_Tp, _Abi>, _Np>& __arr) {
+  simd<_Tp, rebind_abi_t<_Tp, _Np * simd<_Tp, _Abi>::size(), _Abi>> __v;
+  for (size_t __i = 0; __i < __v.size(); __i++) {
+    __v[__i] =
+        __arr[__i / simd<_Tp, _Abi>::size()][__i % simd<_Tp, _Abi>::size()];
+  }
+  return __v;
+}
 
 template <class _Tp, class... _Abis>
-simd_mask<_Tp,
-          abi_for_size_t<_Tp, __variadic_sum(simd_size<_Tp, _Abis>::value...)>>
+simd_mask<_Tp, rebind_abi_t<
+                   _Tp, __variadic_sum<size_t>(simd_size<_Tp, _Abis>::value...),
+                   _Abis...>>
 concat(const simd_mask<_Tp, _Abis>&...);
 
+template <class _Tp, class _Abi, size_t _Np>
+simd_mask<_Tp, rebind_abi_t<_Tp, _Np, _Abi>>
+concat(const std::array<simd_mask<_Tp, _Abi>, _Np>&);
+
 // reductions [simd.mask.reductions]
 template <class _Tp, class _Abi>
 bool all_of(const simd_mask<_Tp, _Abi>&) noexcept;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to