Skip to content

Commit 7665eb8

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

File tree

4 files changed

+257
-5
lines changed

4 files changed

+257
-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: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
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+
// template<class U> reference|=(U&& x) && noexcept;
20+
// template<class U> reference&=(U&& x) && noexcept;
21+
// template<class U> reference^=(U&& x) && noexcept;
22+
// template<class U> reference<<=(U&& x) && noexcept;
23+
// template<class U> reference>>=(U&& x) && noexcept;
24+
25+
#include "../test_utils.h"
26+
#include <experimental/simd>
27+
28+
namespace ex = std::experimental::parallelism_v2;
29+
30+
struct PlusAssign {
31+
template <typename T, typename U>
32+
void operator()(T&& lhs, const U& rhs) const noexcept {
33+
std::forward<T>(lhs) += rhs;
34+
}
35+
};
36+
37+
struct MinusAssign {
38+
template <typename T, typename U>
39+
void operator()(T&& lhs, const U& rhs) const noexcept {
40+
std::forward<T>(lhs) -= rhs;
41+
}
42+
};
43+
44+
struct MultipliesAssign {
45+
template <typename T, typename U>
46+
void operator()(T&& lhs, const U& rhs) const noexcept {
47+
std::forward<T>(lhs) *= rhs;
48+
}
49+
};
50+
51+
struct DividesAssign {
52+
template <typename T, typename U>
53+
void operator()(T&& lhs, const U& rhs) const noexcept {
54+
std::forward<T>(lhs) /= rhs;
55+
}
56+
};
57+
58+
struct ModulusAssign {
59+
template <typename T, typename U>
60+
void operator()(T&& lhs, const U& rhs) const noexcept {
61+
std::forward<T>(lhs) %= rhs;
62+
}
63+
};
64+
65+
struct AndAssign {
66+
template <typename T, typename U>
67+
void operator()(T&& lhs, const U& rhs) const noexcept {
68+
std::forward<T>(lhs) &= rhs;
69+
}
70+
};
71+
72+
struct OrAssign {
73+
template <typename T, typename U>
74+
void operator()(T&& lhs, const U& rhs) const noexcept {
75+
std::forward<T>(lhs) |= rhs;
76+
}
77+
};
78+
79+
struct XorAssign {
80+
template <typename T, typename U>
81+
void operator()(T&& lhs, const U& rhs) const noexcept {
82+
std::forward<T>(lhs) ^= rhs;
83+
}
84+
};
85+
86+
struct LeftShiftAssign {
87+
template <typename T, typename U>
88+
void operator()(T&& lhs, const U& rhs) const noexcept {
89+
std::forward<T>(lhs) <<= rhs;
90+
}
91+
};
92+
93+
struct RightShiftAssign {
94+
template <typename T, typename U>
95+
void operator()(T&& lhs, const U& rhs) const noexcept {
96+
std::forward<T>(lhs) >>= rhs;
97+
}
98+
};
99+
100+
struct LeftShift {
101+
template <typename T, typename U>
102+
T operator()(const T& lhs, const U& rhs) const noexcept {
103+
return lhs << rhs;
104+
}
105+
};
106+
107+
struct RightShift {
108+
template <typename T, typename U>
109+
T operator()(const T& lhs, const U& rhs) const noexcept {
110+
return lhs >> rhs;
111+
}
112+
};
113+
114+
template <typename T, typename SimdAbi, typename Op, typename OpAssign>
115+
struct SimdReferenceOperatorHelper {
116+
template <class U>
117+
void operator()() const {
118+
ex::simd<T, SimdAbi> origin_simd(static_cast<T>(3));
119+
static_assert(noexcept(OpAssign{}(origin_simd[0], static_cast<U>(2))));
120+
OpAssign{}(origin_simd[0], static_cast<U>(2));
121+
assert((T)origin_simd[0] == (T)Op{}(static_cast<T>(3), static_cast<T>(std::forward<U>(2))));
122+
}
123+
};
124+
125+
template <typename T, typename SimdAbi, typename Op, typename OpAssign>
126+
struct MaskReferenceOperatorHelper {
127+
template <class U>
128+
void operator()() const {
129+
ex::simd_mask<T, SimdAbi> origin_mask(true);
130+
static_assert(noexcept(OpAssign{}(origin_mask[0], static_cast<U>(false))));
131+
OpAssign{}(origin_mask[0], static_cast<U>(false));
132+
assert((bool)origin_mask[0] == (bool)Op{}(true, static_cast<bool>(std::forward<U>(false))));
133+
}
134+
};
135+
136+
template <class T, std::size_t>
137+
struct CheckReferenceArithOperators {
138+
template <class SimdAbi>
139+
void operator()() {
140+
types::for_each(simd_test_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::plus<>, PlusAssign>());
141+
types::for_each(simd_test_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::minus<>, MinusAssign>());
142+
types::for_each(simd_test_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::multiplies<>, MultipliesAssign>());
143+
types::for_each(simd_test_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::divides<>, DividesAssign>());
144+
}
145+
};
146+
147+
template <class T, std::size_t>
148+
struct CheckReferenceIntOperators {
149+
template <class SimdAbi>
150+
void operator()() {
151+
types::for_each(
152+
simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::modulus<>, ModulusAssign>());
153+
types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::bit_and<>, AndAssign>());
154+
types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::bit_or<>, OrAssign>());
155+
types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::bit_xor<>, XorAssign>());
156+
types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, LeftShift, LeftShiftAssign>());
157+
types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, RightShift, RightShiftAssign>());
158+
159+
types::for_each(simd_test_integer_types(), MaskReferenceOperatorHelper<T, SimdAbi, std::bit_and<>, AndAssign>());
160+
types::for_each(simd_test_integer_types(), MaskReferenceOperatorHelper<T, SimdAbi, std::bit_or<>, OrAssign>());
161+
types::for_each(simd_test_integer_types(), MaskReferenceOperatorHelper<T, SimdAbi, std::bit_xor<>, XorAssign>());
162+
}
163+
};
164+
165+
int main(int, char**) {
166+
test_all_simd_abi<CheckReferenceArithOperators>();
167+
types::for_each(types::integer_types(), TestAllSimdAbiFunctor<CheckReferenceIntOperators>());
168+
return 0;
169+
}

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)