[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