[libcxx-commits] [libcxx] ed29f27 - [libcxx] <experimental/simd> Add broadcast constructor of class simd/simd_mask

via libcxx-commits libcxx-commits at lists.llvm.org
Mon Sep 11 20:42:07 PDT 2023


Author: Zhangyin
Date: 2023-09-12T11:41:49+08:00
New Revision: ed29f275bfc0beda9bb1959ecf928bd091b079a9

URL: https://github.com/llvm/llvm-project/commit/ed29f275bfc0beda9bb1959ecf928bd091b079a9
DIFF: https://github.com/llvm/llvm-project/commit/ed29f275bfc0beda9bb1959ecf928bd091b079a9.diff

LOG: [libcxx] <experimental/simd> Add broadcast constructor of class simd/simd_mask

Reviewed By: #libc, philnik

Differential Revision: https://reviews.llvm.org/D156225

Added: 
    libcxx/test/std/experimental/simd/simd.class/simd_ctor_broadcast.pass.cpp
    libcxx/test/std/experimental/simd/simd.mask.class/simd_mask_ctor_broadcast.pass.cpp

Modified: 
    libcxx/docs/Status/ParallelismProjects.csv
    libcxx/include/experimental/__simd/scalar.h
    libcxx/include/experimental/__simd/simd.h
    libcxx/include/experimental/__simd/simd_mask.h
    libcxx/include/experimental/__simd/utility.h
    libcxx/include/experimental/__simd/vec_ext.h
    libcxx/test/std/experimental/simd/test_utils.h

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/ParallelismProjects.csv b/libcxx/docs/Status/ParallelismProjects.csv
index 451ace90d6cdc29..8ce6403c27b4062 100644
--- a/libcxx/docs/Status/ParallelismProjects.csv
+++ b/libcxx/docs/Status/ParallelismProjects.csv
@@ -16,9 +16,11 @@ Section,Description,Dependencies,Assignee,Complete
 | `[parallel.simd.whereexpr] <https://wg21.link/N4808>`_, "Where expression class templates", None, Yin Zhang, |In Progress|
 | `[parallel.simd.class] <https://wg21.link/N4808>`_, "`Class template simd declaration and alias <https://reviews.llvm.org/D144362>`_", [parallel.simd.abi], Yin Zhang, |Complete|
 | `[parallel.simd.class] <https://wg21.link/N4808>`_, "`simd<>::size() <https://reviews.llvm.org/D144363>`_", [parallel.simd.traits] simd_size[_v], Yin Zhang, |Complete|
+| `[parallel.simd.class] <https://wg21.link/N4808>`_, "`simd broadcast constructor <https://reviews.llvm.org/D156225>`_", None, Yin Zhang, |Complete|
 | `[parallel.simd.class] <https://wg21.link/N4808>`_, "Class template simd implementation", None, Yin Zhang, |In Progress|
 | `[parallel.simd.nonmembers] <https://wg21.link/N4808>`_, "simd non-member operations", None, Yin Zhang, |In Progress|
 | `[parallel.simd.mask.class] <https://wg21.link/N4808>`_, "`Class template simd_mask declaration and alias <https://reviews.llvm.org/D144362>`_", [parallel.simd.abi], Yin Zhang, |Complete|
 | `[parallel.simd.mask.class] <https://wg21.link/N4808>`_, "`simd_mask<>::size() <https://reviews.llvm.org/D144363>`_", [parallel.simd.class] simd<>::size(), Yin Zhang, |Complete|
+| `[parallel.simd.mask.class] <https://wg21.link/N4808>`_, "`simd_mask broadcast constructor <https://reviews.llvm.org/D156225>`_", None, Yin Zhang, |Complete|
 | `[parallel.simd.mask.class] <https://wg21.link/N4808>`_, "Class template simd_mask implementation", None, Yin Zhang, |In Progress|
 | `[parallel.simd.mask.nonmembers] <https://wg21.link/N4808>`_, "simd_mask non-member operations", None, Yin Zhang, |In Progress|

diff  --git a/libcxx/include/experimental/__simd/scalar.h b/libcxx/include/experimental/__simd/scalar.h
index 76bd4d041163a2a..dcb32206d0746e9 100644
--- a/libcxx/include/experimental/__simd/scalar.h
+++ b/libcxx/include/experimental/__simd/scalar.h
@@ -44,11 +44,15 @@ template <class _Tp>
 struct __simd_operations<_Tp, simd_abi::__scalar> {
   using _SimdStorage = __simd_storage<_Tp, simd_abi::__scalar>;
   using _MaskStorage = __mask_storage<_Tp, simd_abi::__scalar>;
+
+  static _SimdStorage __broadcast(_Tp __v) noexcept { return {__v}; }
 };
 
 template <class _Tp>
 struct __mask_operations<_Tp, simd_abi::__scalar> {
   using _MaskStorage = __mask_storage<_Tp, simd_abi::__scalar>;
+
+  static _MaskStorage __broadcast(bool __v) noexcept { return {__v}; }
 };
 
 } // namespace parallelism_v2

diff  --git a/libcxx/include/experimental/__simd/simd.h b/libcxx/include/experimental/__simd/simd.h
index 371e8a65d730a01..30856f4b03c9db0 100644
--- a/libcxx/include/experimental/__simd/simd.h
+++ b/libcxx/include/experimental/__simd/simd.h
@@ -10,6 +10,7 @@
 #ifndef _LIBCPP_EXPERIMENTAL___SIMD_SIMD_H
 #define _LIBCPP_EXPERIMENTAL___SIMD_SIMD_H
 
+#include <__type_traits/remove_cvref.h>
 #include <experimental/__simd/abi_tag.h>
 #include <experimental/__simd/declaration.h>
 #include <experimental/__simd/reference.h>
@@ -38,6 +39,14 @@ class simd {
   using abi_type   = _Abi;
 
   static _LIBCPP_HIDE_FROM_ABI constexpr size_t size() noexcept { return simd_size_v<value_type, abi_type>; }
+
+  // broadcast constructor
+  template <class _Up, enable_if_t<__can_broadcast_v<value_type, __remove_cvref_t<_Up>>, int> = 0>
+  _LIBCPP_HIDE_FROM_ABI simd(_Up&& __v) noexcept : __s_(_Impl::__broadcast(static_cast<value_type>(__v))) {}
+
+  // scalar access [simd.subscr]
+  // Add operator[] temporarily to test braodcast. Add test for it in later patch.
+  _LIBCPP_HIDE_FROM_ABI value_type operator[](size_t __i) const { return __s_.__get(__i); }
 };
 
 template <class _Tp>

diff  --git a/libcxx/include/experimental/__simd/simd_mask.h b/libcxx/include/experimental/__simd/simd_mask.h
index 1fe42dca0dfc20f..4862fd42c0d06ac 100644
--- a/libcxx/include/experimental/__simd/simd_mask.h
+++ b/libcxx/include/experimental/__simd/simd_mask.h
@@ -37,6 +37,13 @@ class simd_mask {
   using abi_type   = _Abi;
 
   static _LIBCPP_HIDE_FROM_ABI constexpr size_t size() noexcept { return simd_type::size(); }
+
+  // broadcast constructor
+  _LIBCPP_HIDE_FROM_ABI explicit simd_mask(value_type __v) noexcept : __s_(_Impl::__broadcast(__v)) {}
+
+  // scalar access [simd.mask.subscr]
+  // Add operator[] temporarily to test braodcast. Add test for it in later patch.
+  _LIBCPP_HIDE_FROM_ABI value_type operator[](size_t __i) const { return __s_.__get(__i); }
 };
 
 template <class _Tp>

diff  --git a/libcxx/include/experimental/__simd/utility.h b/libcxx/include/experimental/__simd/utility.h
index 7676ff240f6a7ab..0dba345e05377a3 100644
--- a/libcxx/include/experimental/__simd/utility.h
+++ b/libcxx/include/experimental/__simd/utility.h
@@ -13,8 +13,12 @@
 #include <__type_traits/is_arithmetic.h>
 #include <__type_traits/is_const.h>
 #include <__type_traits/is_constant_evaluated.h>
+#include <__type_traits/is_convertible.h>
 #include <__type_traits/is_same.h>
+#include <__type_traits/is_unsigned.h>
 #include <__type_traits/is_volatile.h>
+#include <__type_traits/void_t.h>
+#include <__utility/declval.h>
 #include <cstdint>
 #include <limits>
 
@@ -26,7 +30,7 @@ _LIBCPP_PUSH_MACROS
 _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL
 inline namespace parallelism_v2 {
 template <class _Tp>
-constexpr bool __is_vectorizable_v =
+inline constexpr bool __is_vectorizable_v =
     is_arithmetic_v<_Tp> && !is_const_v<_Tp> && !is_volatile_v<_Tp> && !is_same_v<_Tp, bool>;
 
 template <class _Tp>
@@ -54,6 +58,19 @@ _LIBCPP_HIDE_FROM_ABI auto constexpr __set_all_bits(bool __v) {
   return __v ? (numeric_limits<decltype(__choose_mask_type<_Tp>())>::max()) : 0;
 }
 
+template <class _From, class _To, class = void>
+inline constexpr bool __is_non_narrowing_convertible_v = false;
+
+template <class _From, class _To>
+inline constexpr bool __is_non_narrowing_convertible_v<_From, _To, std::void_t<decltype(_To{std::declval<_From>()})>> =
+    true;
+
+template <class _Tp, class _Up>
+inline constexpr bool __can_broadcast_v =
+    (__is_vectorizable_v<_Up> && __is_non_narrowing_convertible_v<_Up, _Tp>) ||
+    (!__is_vectorizable_v<_Up> && is_convertible_v<_Up, _Tp>) || is_same_v<_Up, int> ||
+    (is_same_v<_Up, unsigned int> && is_unsigned_v<_Tp>);
+
 } // namespace parallelism_v2
 _LIBCPP_END_NAMESPACE_EXPERIMENTAL
 

diff  --git a/libcxx/include/experimental/__simd/vec_ext.h b/libcxx/include/experimental/__simd/vec_ext.h
index c50f49252124e21..13cc4006b5f5d94 100644
--- a/libcxx/include/experimental/__simd/vec_ext.h
+++ b/libcxx/include/experimental/__simd/vec_ext.h
@@ -48,11 +48,28 @@ template <class _Tp, int _Np>
 struct __simd_operations<_Tp, simd_abi::__vec_ext<_Np>> {
   using _SimdStorage = __simd_storage<_Tp, simd_abi::__vec_ext<_Np>>;
   using _MaskStorage = __mask_storage<_Tp, simd_abi::__vec_ext<_Np>>;
+
+  static _SimdStorage __broadcast(_Tp __v) noexcept {
+    _SimdStorage __result;
+    for (int __i = 0; __i < _Np; ++__i) {
+      __result.__set(__i, __v);
+    }
+    return __result;
+  }
 };
 
 template <class _Tp, int _Np>
 struct __mask_operations<_Tp, simd_abi::__vec_ext<_Np>> {
   using _MaskStorage = __mask_storage<_Tp, simd_abi::__vec_ext<_Np>>;
+
+  static _MaskStorage __broadcast(bool __v) noexcept {
+    _MaskStorage __result;
+    auto __all_bits_v = experimental::__set_all_bits<_Tp>(__v);
+    for (int __i = 0; __i < _Np; ++__i) {
+      __result.__set(__i, __all_bits_v);
+    }
+    return __result;
+  }
 };
 
 } // namespace parallelism_v2

diff  --git a/libcxx/test/std/experimental/simd/simd.class/simd_ctor_broadcast.pass.cpp b/libcxx/test/std/experimental/simd/simd.class/simd_ctor_broadcast.pass.cpp
new file mode 100644
index 000000000000000..e1a668c8b4932f0
--- /dev/null
+++ b/libcxx/test/std/experimental/simd/simd.class/simd_ctor_broadcast.pass.cpp
@@ -0,0 +1,128 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+
+// <experimental/simd>
+//
+// [simd.class]
+// template<class U> simd(U&& value) noexcept;
+
+// GCC returns __int128 unsigned with garbled data in higher 64 bits.
+// This is likely a bug in GCC implementation. Investigation needed.
+// XFAIL: gcc-13
+
+#include "../test_utils.h"
+
+namespace ex = std::experimental::parallelism_v2;
+
+template <class T, class SimdAbi, std::size_t array_size>
+struct BroadCastHelper {
+  const std::array<T, array_size>& expected_value;
+
+  BroadCastHelper(const std::array<T, array_size>& value) : expected_value(value) {}
+
+  template <class U>
+  void operator()() const {
+    if constexpr (is_non_narrowing_convertible_v<U, T>) {
+      ex::simd<T, SimdAbi> simd_broadcast_from_vectorizable_type(static_cast<U>(3));
+      assert_simd_values_equal<array_size>(simd_broadcast_from_vectorizable_type, expected_value);
+    }
+  }
+};
+
+template <class T, std::size_t>
+struct CheckSimdBroadcastCtorFromVectorizedType {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
+    std::array<T, array_size> expected_value;
+    std::fill(expected_value.begin(), expected_value.end(), 3);
+
+    types::for_each(arithmetic_no_bool_types(), BroadCastHelper<T, SimdAbi, array_size>(expected_value));
+  }
+};
+
+template <class T>
+class implicit_type {
+  T val;
+
+public:
+  implicit_type(T v) : val(v) {}
+  operator T() const { return val; }
+};
+
+template <class T, std::size_t>
+struct CheckSimdBroadcastCtor {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
+    std::array<T, array_size> expected_value;
+    std::fill(expected_value.begin(), expected_value.end(), 3);
+
+    implicit_type<T> implicit_convert_to_3(3);
+    ex::simd<T, SimdAbi> simd_broadcast_from_implicit_type(std::move(implicit_convert_to_3));
+    assert_simd_values_equal<array_size>(simd_broadcast_from_implicit_type, expected_value);
+
+    ex::simd<T, SimdAbi> simd_broadcast_from_int(3);
+    assert_simd_values_equal<array_size>(simd_broadcast_from_int, expected_value);
+
+    if constexpr (std::is_unsigned_v<T>) {
+      ex::simd<T, SimdAbi> simd_broadcast_from_uint(3u);
+      assert_simd_values_equal<array_size>(simd_broadcast_from_uint, expected_value);
+    }
+  }
+};
+
+template <class T>
+class no_implicit_type {
+  T val;
+
+public:
+  no_implicit_type(T v) : val(v) {}
+};
+
+template <class U, class T, class SimdAbi = ex::simd_abi::compatible<T>, class = void>
+struct has_broadcast_ctor : std::false_type {};
+
+template <class U, class T, class SimdAbi>
+struct has_broadcast_ctor<U, T, SimdAbi, std::void_t<decltype(ex::simd<T, SimdAbi>(std::declval<U>()))>>
+    : std::true_type {};
+
+template <class T, class SimdAbi>
+struct CheckBroadcastCtorTraitsHelper {
+  template <class U>
+  void operator()() const {
+    if constexpr (std::is_same_v<U, int>)
+      static_assert(has_broadcast_ctor<U, T, SimdAbi>::value);
+    else if constexpr (std::is_same_v<U, unsigned int> && std::is_unsigned_v<T>)
+      static_assert(has_broadcast_ctor<U, T, SimdAbi>::value);
+    else if constexpr (is_non_narrowing_convertible_v<U, T>)
+      static_assert(has_broadcast_ctor<U, T, SimdAbi>::value);
+    else
+      static_assert(!has_broadcast_ctor<U, T, SimdAbi>::value);
+  }
+};
+
+template <class T, std::size_t>
+struct CheckBroadcastCtorTraits {
+  template <class SimdAbi>
+  void operator()() {
+    types::for_each(arithmetic_no_bool_types(), CheckBroadcastCtorTraitsHelper<T, SimdAbi>());
+
+    static_assert(!has_broadcast_ctor<no_implicit_type<T>, T, SimdAbi>::value);
+    static_assert(has_broadcast_ctor<implicit_type<T>, T, SimdAbi>::value);
+  }
+};
+
+int main(int, char**) {
+  test_all_simd_abi<CheckSimdBroadcastCtorFromVectorizedType>();
+  test_all_simd_abi<CheckSimdBroadcastCtor>();
+  test_all_simd_abi<CheckBroadcastCtorTraits>();
+  return 0;
+}

diff  --git a/libcxx/test/std/experimental/simd/simd.mask.class/simd_mask_ctor_broadcast.pass.cpp b/libcxx/test/std/experimental/simd/simd.mask.class/simd_mask_ctor_broadcast.pass.cpp
new file mode 100644
index 000000000000000..967368196d1bf05
--- /dev/null
+++ b/libcxx/test/std/experimental/simd/simd.mask.class/simd_mask_ctor_broadcast.pass.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+
+// <experimental/simd>
+//
+// [simd.mask.class]
+// explicit simd_mask(value_type) noexcept;
+
+// GCC returns __int128 unsigned with garbled data in higher 64 bits.
+// This is likely a bug in GCC implementation. Investigation needed.
+// XFAIL: gcc-13
+
+#include "../test_utils.h"
+#include <experimental/simd>
+
+namespace ex = std::experimental::parallelism_v2;
+
+template <class T, std::size_t>
+struct CheckMaskBroadcastCtor {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr size_t array_size = ex::simd_size_v<T, SimdAbi>;
+    const ex::simd_mask<T, SimdAbi> mask_ctor_from_broadcast(false);
+    const std::array<bool, array_size> expected_value{};
+    assert_simd_mask_values_equal(mask_ctor_from_broadcast, expected_value);
+  }
+};
+
+int main(int, char**) {
+  test_all_simd_abi<CheckMaskBroadcastCtor>();
+  return 0;
+}

diff  --git a/libcxx/test/std/experimental/simd/test_utils.h b/libcxx/test/std/experimental/simd/test_utils.h
index 6b9fa146b5364c1..12f01895ad69c5d 100644
--- a/libcxx/test/std/experimental/simd/test_utils.h
+++ b/libcxx/test/std/experimental/simd/test_utils.h
@@ -9,6 +9,10 @@
 #ifndef TEST_UTIL_H
 #define TEST_UTIL_H
 
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <type_traits>
 #include <utility>
 #include <experimental/simd>
 #include "type_algorithms.h"
@@ -55,4 +59,23 @@ constexpr size_t bit_ceil(size_t val) {
   return pow;
 }
 
+template <class From, class To, class = void>
+inline constexpr bool is_non_narrowing_convertible_v = false;
+
+template <class From, class To>
+inline constexpr bool is_non_narrowing_convertible_v<From, To, std::void_t<decltype(To{std::declval<From>()})>> = true;
+
+template <std::size_t ArraySize, class SimdAbi, class T, class U = T>
+void assert_simd_values_equal(const ex::simd<T, SimdAbi>& origin_simd, const std::array<U, ArraySize>& expected_value) {
+  for (std::size_t i = 0; i < origin_simd.size(); ++i)
+    assert(origin_simd[i] == static_cast<T>(expected_value[i]));
+}
+
+template <std::size_t ArraySize, class T, class SimdAbi>
+void assert_simd_mask_values_equal(const ex::simd_mask<T, SimdAbi>& origin_mask,
+                                   const std::array<bool, ArraySize>& expected_value) {
+  for (std::size_t i = 0; i < origin_mask.size(); ++i)
+    assert(origin_mask[i] == expected_value[i]);
+}
+
 #endif // TEST_UTIL_H


        


More information about the libcxx-commits mailing list