Skip to content

Commit 85f7198

Browse files
committed
[libc++] <experimental/simd> Add compound assignment operators for simd reference
1 parent 7231776 commit 85f7198

File tree

5 files changed

+298
-5
lines changed

5 files changed

+298
-5
lines changed

libcxx/docs/Status/ParallelismProjects.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Section,Description,Dependencies,Assignee,Complete
1717
| `[parallel.simd.reference] <https://wg21.link/N4808>`_, "`Element references operator value_type() <https://github.com/llvm/llvm-project/pull/68960>`_", None, Yin Zhang, |Complete|
1818
| `[parallel.simd.reference] <https://wg21.link/N4808>`_, "`Element references operator= <https://github.com/llvm/llvm-project/pull/70020>`_", None, Yin Zhang, |Complete|
1919
| `[parallel.simd.reference] <https://wg21.link/N4808>`_, "`Element references swap functions <https://github.com/llvm/llvm-project/pull/86478>`_", None, Yin Zhang, |Complete|
20+
| `[parallel.simd.reference] <https://wg21.link/N4808>`_, "`Element references compound assignment operators <https://github.com/llvm/llvm-project/pull/86761>`_", None, Yin Zhang, |Complete|
2021
| `[parallel.simd.class] <https://wg21.link/N4808>`_, "`Class template simd declaration and alias <https://reviews.llvm.org/D144362>`_", [parallel.simd.abi], Yin Zhang, |Complete|
2122
| `[parallel.simd.class] <https://wg21.link/N4808>`_, "`simd<>::size() <https://reviews.llvm.org/D144363>`_", [parallel.simd.traits] simd_size[_v], Yin Zhang, |Complete|
2223
| `[parallel.simd.class] <https://wg21.link/N4808>`_, "`simd default constructor <https://github.com/llvm/llvm-project/pull/70424>`_", None, Yin Zhang, |Complete|

libcxx/include/experimental/__simd/reference.h

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <__type_traits/is_assignable.h>
1414
#include <__type_traits/is_same.h>
15+
#include <__utility/declval.h>
1516
#include <__utility/forward.h>
1617
#include <__utility/move.h>
1718
#include <cstddef>
@@ -71,6 +72,86 @@ class __simd_reference {
7172

7273
template <class _Tp1, class _Storage1, class _Vp1>
7374
friend void swap(__simd_reference<_Tp1, _Storage1, _Vp1>&& __a, _Vp1& __b) noexcept;
75+
76+
template <
77+
class _Up,
78+
enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() + std::declval<_Up>())&&>, int> = 0>
79+
_LIBCPP_HIDE_FROM_ABI __simd_reference operator+=(_Up&& __v) && noexcept {
80+
__set(__get() + static_cast<value_type>(std::forward<_Up>(__v)));
81+
return {__s_, __idx_};
82+
}
83+
84+
template <
85+
class _Up,
86+
enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() - std::declval<_Up>())&&>, int> = 0>
87+
_LIBCPP_HIDE_FROM_ABI __simd_reference operator-=(_Up&& __v) && noexcept {
88+
__set(__get() - static_cast<value_type>(std::forward<_Up>(__v)));
89+
return {__s_, __idx_};
90+
}
91+
92+
template <
93+
class _Up,
94+
enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() * std::declval<_Up>())&&>, int> = 0>
95+
_LIBCPP_HIDE_FROM_ABI __simd_reference operator*=(_Up&& __v) && noexcept {
96+
__set(__get() * static_cast<value_type>(std::forward<_Up>(__v)));
97+
return {__s_, __idx_};
98+
}
99+
100+
template <
101+
class _Up,
102+
enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() / std::declval<_Up>())&&>, int> = 0>
103+
_LIBCPP_HIDE_FROM_ABI __simd_reference operator/=(_Up&& __v) && noexcept {
104+
__set(__get() / static_cast<value_type>(std::forward<_Up>(__v)));
105+
return {__s_, __idx_};
106+
}
107+
108+
template <
109+
class _Up,
110+
enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() % std::declval<_Up>())&&>, int> = 0>
111+
_LIBCPP_HIDE_FROM_ABI __simd_reference operator%=(_Up&& __v) && noexcept {
112+
__set(__get() % static_cast<value_type>(std::forward<_Up>(__v)));
113+
return {__s_, __idx_};
114+
}
115+
116+
template <
117+
class _Up,
118+
enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() & std::declval<_Up>())&&>, int> = 0>
119+
_LIBCPP_HIDE_FROM_ABI __simd_reference operator&=(_Up&& __v) && noexcept {
120+
__set(__get() & static_cast<value_type>(std::forward<_Up>(__v)));
121+
return {__s_, __idx_};
122+
}
123+
124+
template <
125+
class _Up,
126+
enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() | std::declval<_Up>())&&>, int> = 0>
127+
_LIBCPP_HIDE_FROM_ABI __simd_reference operator|=(_Up&& __v) && noexcept {
128+
__set(__get() | static_cast<value_type>(std::forward<_Up>(__v)));
129+
return {__s_, __idx_};
130+
}
131+
132+
template <
133+
class _Up,
134+
enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() ^ std::declval<_Up>())&&>, int> = 0>
135+
_LIBCPP_HIDE_FROM_ABI __simd_reference operator^=(_Up&& __v) && noexcept {
136+
__set(__get() ^ static_cast<value_type>(std::forward<_Up>(__v)));
137+
return {__s_, __idx_};
138+
}
139+
140+
template <class _Up,
141+
enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() << std::declval<_Up>())&&>,
142+
int> = 0>
143+
_LIBCPP_HIDE_FROM_ABI __simd_reference operator<<=(_Up&& __v) && noexcept {
144+
__set(__get() << static_cast<value_type>(std::forward<_Up>(__v)));
145+
return {__s_, __idx_};
146+
}
147+
148+
template <class _Up,
149+
enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() >> std::declval<_Up>())&&>,
150+
int> = 0>
151+
_LIBCPP_HIDE_FROM_ABI __simd_reference operator>>=(_Up&& __v) && noexcept {
152+
__set(__get() >> static_cast<value_type>(std::forward<_Up>(__v)));
153+
return {__s_, __idx_};
154+
}
74155
};
75156

76157
template <class _Tp, class _Storage, class _Vp>
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14
10+
11+
// <experimental/simd>
12+
//
13+
// [simd.reference]
14+
// template<class U> reference+=(U&& x) && noexcept;
15+
// template<class U> reference-=(U&& x) && noexcept;
16+
// template<class U> reference*=(U&& x) && noexcept;
17+
// template<class U> reference/=(U&& x) && noexcept;
18+
// template<class U> reference%=(U&& x) && noexcept;
19+
20+
#include "../test_utils.h"
21+
#include <experimental/simd>
22+
23+
namespace ex = std::experimental::parallelism_v2;
24+
25+
struct PlusAssign {
26+
template <typename T, typename U>
27+
void operator()(T&& lhs, const U& rhs) const noexcept {
28+
std::forward<T>(lhs) += rhs;
29+
}
30+
};
31+
32+
struct MinusAssign {
33+
template <typename T, typename U>
34+
void operator()(T&& lhs, const U& rhs) const noexcept {
35+
std::forward<T>(lhs) -= rhs;
36+
}
37+
};
38+
39+
struct MultipliesAssign {
40+
template <typename T, typename U>
41+
void operator()(T&& lhs, const U& rhs) const noexcept {
42+
std::forward<T>(lhs) *= rhs;
43+
}
44+
};
45+
46+
struct DividesAssign {
47+
template <typename T, typename U>
48+
void operator()(T&& lhs, const U& rhs) const noexcept {
49+
std::forward<T>(lhs) /= rhs;
50+
}
51+
};
52+
53+
struct ModulusAssign {
54+
template <typename T, typename U>
55+
void operator()(T&& lhs, const U& rhs) const noexcept {
56+
std::forward<T>(lhs) %= rhs;
57+
}
58+
};
59+
60+
template <typename T, typename SimdAbi, typename Op, typename OpAssign>
61+
struct SimdReferenceOperatorHelper {
62+
template <class U>
63+
void operator()() const {
64+
ex::simd<T, SimdAbi> origin_simd(static_cast<T>(3));
65+
static_assert(noexcept(OpAssign{}(origin_simd[0], static_cast<U>(2))));
66+
OpAssign{}(origin_simd[0], static_cast<U>(2));
67+
assert((T)origin_simd[0] == (T)Op{}(static_cast<T>(3), static_cast<T>(std::forward<U>(2))));
68+
}
69+
};
70+
71+
template <class T, std::size_t>
72+
struct CheckReferenceArithOperators {
73+
template <class SimdAbi>
74+
void operator()() {
75+
types::for_each(simd_test_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::plus<>, PlusAssign>());
76+
types::for_each(simd_test_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::minus<>, MinusAssign>());
77+
types::for_each(simd_test_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::multiplies<>, MultipliesAssign>());
78+
types::for_each(simd_test_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::divides<>, DividesAssign>());
79+
}
80+
};
81+
82+
template <class T, std::size_t>
83+
struct CheckReferenceModOperators {
84+
template <class SimdAbi>
85+
void operator()() {
86+
types::for_each(
87+
simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::modulus<>, ModulusAssign>());
88+
}
89+
};
90+
91+
int main(int, char**) {
92+
test_all_simd_abi<CheckReferenceArithOperators>();
93+
types::for_each(types::integer_types(), TestAllSimdAbiFunctor<CheckReferenceModOperators>());
94+
return 0;
95+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14
10+
11+
// <experimental/simd>
12+
//
13+
// [simd.reference]
14+
// template<class U> reference|=(U&& x) && noexcept;
15+
// template<class U> reference&=(U&& x) && noexcept;
16+
// template<class U> reference^=(U&& x) && noexcept;
17+
// template<class U> reference<<=(U&& x) && noexcept;
18+
// template<class U> reference>>=(U&& x) && noexcept;
19+
20+
#include "../test_utils.h"
21+
#include <experimental/simd>
22+
23+
namespace ex = std::experimental::parallelism_v2;
24+
25+
struct AndAssign {
26+
template <typename T, typename U>
27+
void operator()(T&& lhs, const U& rhs) const noexcept {
28+
std::forward<T>(lhs) &= rhs;
29+
}
30+
};
31+
32+
struct OrAssign {
33+
template <typename T, typename U>
34+
void operator()(T&& lhs, const U& rhs) const noexcept {
35+
std::forward<T>(lhs) |= rhs;
36+
}
37+
};
38+
39+
struct XorAssign {
40+
template <typename T, typename U>
41+
void operator()(T&& lhs, const U& rhs) const noexcept {
42+
std::forward<T>(lhs) ^= rhs;
43+
}
44+
};
45+
46+
struct LeftShiftAssign {
47+
template <typename T, typename U>
48+
void operator()(T&& lhs, const U& rhs) const noexcept {
49+
std::forward<T>(lhs) <<= rhs;
50+
}
51+
};
52+
53+
struct RightShiftAssign {
54+
template <typename T, typename U>
55+
void operator()(T&& lhs, const U& rhs) const noexcept {
56+
std::forward<T>(lhs) >>= rhs;
57+
}
58+
};
59+
60+
struct LeftShift {
61+
template <typename T, typename U>
62+
T operator()(const T& lhs, const U& rhs) const noexcept {
63+
return lhs << rhs;
64+
}
65+
};
66+
67+
struct RightShift {
68+
template <typename T, typename U>
69+
T operator()(const T& lhs, const U& rhs) const noexcept {
70+
return lhs >> rhs;
71+
}
72+
};
73+
74+
template <typename T, typename SimdAbi, typename Op, typename OpAssign>
75+
struct SimdReferenceOperatorHelper {
76+
template <class U>
77+
void operator()() const {
78+
ex::simd<T, SimdAbi> origin_simd(static_cast<T>(3));
79+
static_assert(noexcept(OpAssign{}(origin_simd[0], static_cast<U>(2))));
80+
OpAssign{}(origin_simd[0], static_cast<U>(2));
81+
assert((T)origin_simd[0] == (T)Op{}(static_cast<T>(3), static_cast<T>(std::forward<U>(2))));
82+
}
83+
};
84+
85+
template <typename T, typename SimdAbi, typename Op, typename OpAssign>
86+
struct MaskReferenceOperatorHelper {
87+
template <class U>
88+
void operator()() const {
89+
ex::simd_mask<T, SimdAbi> origin_mask(true);
90+
static_assert(noexcept(OpAssign{}(origin_mask[0], static_cast<U>(false))));
91+
OpAssign{}(origin_mask[0], static_cast<U>(false));
92+
assert((bool)origin_mask[0] == (bool)Op{}(true, static_cast<bool>(std::forward<U>(false))));
93+
}
94+
};
95+
96+
template <class T, std::size_t>
97+
struct CheckReferenceBitwiseOperators {
98+
template <class SimdAbi>
99+
void operator()() {
100+
types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::bit_and<>, AndAssign>());
101+
types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::bit_or<>, OrAssign>());
102+
types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::bit_xor<>, XorAssign>());
103+
types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, LeftShift, LeftShiftAssign>());
104+
types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, RightShift, RightShiftAssign>());
105+
106+
types::for_each(simd_test_integer_types(), MaskReferenceOperatorHelper<T, SimdAbi, std::bit_and<>, AndAssign>());
107+
types::for_each(simd_test_integer_types(), MaskReferenceOperatorHelper<T, SimdAbi, std::bit_or<>, OrAssign>());
108+
types::for_each(simd_test_integer_types(), MaskReferenceOperatorHelper<T, SimdAbi, std::bit_xor<>, XorAssign>());
109+
}
110+
};
111+
112+
int main(int, char**) {
113+
types::for_each(types::integer_types(), TestAllSimdAbiFunctor<CheckReferenceBitwiseOperators>());
114+
return 0;
115+
}

libcxx/test/std/experimental/simd/test_utils.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,16 @@ using arithmetic_no_bool_types = types::concatenate_t<types::integer_types, type
5050

5151
// For interfaces with vectorizable type template parameters, we only use some common or boundary types
5252
// as template parameters for testing to ensure that the compilation time of a single test does not exceed.
53-
using simd_test_types =
53+
using simd_test_integer_types =
5454
types::type_list<char,
5555
unsigned,
56-
int,
56+
int
5757
#ifndef TEST_HAS_NO_INT128
58-
__int128_t,
58+
,
59+
__int128_t
5960
#endif
60-
float,
61-
double>;
61+
>;
62+
using simd_test_types = types::concatenate_t<simd_test_integer_types, types::type_list<float, double>>;
6263

6364
template <template <class T, std::size_t N> class Func>
6465
void test_all_simd_abi() {

0 commit comments

Comments
 (0)