Skip to content

Commit c3eab8e

Browse files
committed
[libc++] <experimental/simd> Add compound assignment operators for simd reference
1 parent 5c663aa commit c3eab8e

File tree

4 files changed

+135
-5
lines changed

4 files changed

+135
-5
lines changed

libcxx/docs/Status/ParallelismProjects.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Section,Description,Dependencies,Assignee,Complete
1616
| `[parallel.simd.whereexpr] <https://wg21.link/N4808>`_, "Where expression class templates", None, Yin Zhang, |In Progress|
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|
19+
| `[parallel.simd.reference] <https://wg21.link/N4808>`_, "`Element references compound assignment operators <https://github.com/llvm/llvm-project/pull/86761>`_", None, Yin Zhang, |Complete|
1920
| `[parallel.simd.class] <https://wg21.link/N4808>`_, "`Class template simd declaration and alias <https://reviews.llvm.org/D144362>`_", [parallel.simd.abi], Yin Zhang, |Complete|
2021
| `[parallel.simd.class] <https://wg21.link/N4808>`_, "`simd<>::size() <https://reviews.llvm.org/D144363>`_", [parallel.simd.traits] simd_size[_v], Yin Zhang, |Complete|
2122
| `[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: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212

1313
#include <__type_traits/is_assignable.h>
1414
#include <__type_traits/is_same.h>
15+
#include <__type_traits/is_void.h>
16+
#include <__type_traits/void_t.h>
17+
#include <__utility/declval.h>
1518
#include <__utility/forward.h>
1619
#include <cstddef>
1720
#include <experimental/__config>
@@ -55,6 +58,26 @@ class __simd_reference {
5558
__set(static_cast<value_type>(std::forward<_Up>(__v)));
5659
return {__s_, __idx_};
5760
}
61+
62+
# define _LIBCXX_SIMD_REFERENCE_OP_(__op) \
63+
template < \
64+
class _Up, \
65+
enable_if_t<is_void_v<void_t<decltype(std::declval<value_type&>() __op## = std::declval<_Up>())>>, int> = 0> \
66+
__simd_reference _LIBCPP_HIDE_FROM_ABI operator __op##=(_Up&& __v) && noexcept { \
67+
__set(__get() __op static_cast<value_type>(std::forward<_Up>(__v))); \
68+
return {__s_, __idx_}; \
69+
}
70+
_LIBCXX_SIMD_REFERENCE_OP_(+)
71+
_LIBCXX_SIMD_REFERENCE_OP_(-)
72+
_LIBCXX_SIMD_REFERENCE_OP_(*)
73+
_LIBCXX_SIMD_REFERENCE_OP_(/)
74+
_LIBCXX_SIMD_REFERENCE_OP_(%)
75+
_LIBCXX_SIMD_REFERENCE_OP_(&)
76+
_LIBCXX_SIMD_REFERENCE_OP_(|)
77+
_LIBCXX_SIMD_REFERENCE_OP_(^)
78+
_LIBCXX_SIMD_REFERENCE_OP_(<<)
79+
_LIBCXX_SIMD_REFERENCE_OP_(>>)
80+
# undef _LIBCXX_SIMD_REFERENCE_OP_
5881
};
5982

6083
} // namespace parallelism_v2
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
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+
#define LIBCXX_SIMD_REFERENCE_OP_(op, name) \
31+
template <class T, class SimdAbi> \
32+
struct SimdReferenceOperatorHelper##name { \
33+
template <class U> \
34+
void operator()() const { \
35+
ex::simd<T, SimdAbi> origin_simd([](T i) { return i; }); \
36+
for (size_t i = 0; i < origin_simd.size(); ++i) { \
37+
static_assert(noexcept(origin_simd[i] op## = static_cast<U>(2))); \
38+
origin_simd[i] op## = static_cast<U>(2); \
39+
assert((T)origin_simd[i] == (T)(static_cast<T>(i) op static_cast<T>(std::forward<U>(2)))); \
40+
} \
41+
} \
42+
};
43+
LIBCXX_SIMD_REFERENCE_OP_(+, Plus)
44+
LIBCXX_SIMD_REFERENCE_OP_(-, Minus)
45+
LIBCXX_SIMD_REFERENCE_OP_(*, Multiplies)
46+
LIBCXX_SIMD_REFERENCE_OP_(/, Divides)
47+
LIBCXX_SIMD_REFERENCE_OP_(%, Modulus)
48+
LIBCXX_SIMD_REFERENCE_OP_(&, BitAnd)
49+
LIBCXX_SIMD_REFERENCE_OP_(|, BitOr)
50+
LIBCXX_SIMD_REFERENCE_OP_(^, BitXor)
51+
LIBCXX_SIMD_REFERENCE_OP_(<<, ShiftLeft)
52+
LIBCXX_SIMD_REFERENCE_OP_(>>, ShiftRight)
53+
#undef LIBCXX_SIMD_REFERENCE_OP_
54+
55+
#define LIBCXX_SIMD_MASK_REFERENCE_OP_(op, name) \
56+
template <class T, class SimdAbi> \
57+
struct MaskReferenceOperatorHelper##name { \
58+
template <class U> \
59+
void operator()() const { \
60+
ex::simd<T, SimdAbi> origin_simd_mask(true); \
61+
for (size_t i = 0; i < origin_simd_mask.size(); ++i) { \
62+
static_assert(noexcept(origin_simd_mask[i] op## = static_cast<U>(i % 2))); \
63+
origin_simd_mask[i] op## = static_cast<U>(i % 2); \
64+
assert((bool)origin_simd_mask[i] == (bool)(true op static_cast<bool>(std::forward<U>(i % 2)))); \
65+
} \
66+
} \
67+
};
68+
LIBCXX_SIMD_MASK_REFERENCE_OP_(&, BitAnd)
69+
LIBCXX_SIMD_MASK_REFERENCE_OP_(|, BitOr)
70+
LIBCXX_SIMD_MASK_REFERENCE_OP_(^, BitXor)
71+
#undef LIBCXX_SIMD_MASK_REFERENCE_OP_
72+
73+
template <class T, std::size_t>
74+
struct CheckReferenceArithOperators {
75+
template <class SimdAbi>
76+
void operator()() {
77+
types::for_each(simd_test_types(), SimdReferenceOperatorHelperPlus<T, SimdAbi>());
78+
types::for_each(simd_test_types(), SimdReferenceOperatorHelperMinus<T, SimdAbi>());
79+
types::for_each(simd_test_types(), SimdReferenceOperatorHelperMultiplies<T, SimdAbi>());
80+
types::for_each(simd_test_types(), SimdReferenceOperatorHelperDivides<T, SimdAbi>());
81+
}
82+
};
83+
84+
template <class T, std::size_t>
85+
struct CheckReferenceIntOperators {
86+
template <class SimdAbi>
87+
void operator()() {
88+
types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelperModulus<T, SimdAbi>());
89+
types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelperBitAnd<T, SimdAbi>());
90+
types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelperBitOr<T, SimdAbi>());
91+
types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelperBitXor<T, SimdAbi>());
92+
types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelperShiftLeft<T, SimdAbi>());
93+
types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelperShiftRight<T, SimdAbi>());
94+
95+
types::for_each(simd_test_integer_types(), MaskReferenceOperatorHelperBitAnd<T, SimdAbi>());
96+
types::for_each(simd_test_integer_types(), MaskReferenceOperatorHelperBitOr<T, SimdAbi>());
97+
types::for_each(simd_test_integer_types(), MaskReferenceOperatorHelperBitXor<T, SimdAbi>());
98+
}
99+
};
100+
101+
int main(int, char**) {
102+
test_all_simd_abi<CheckReferenceArithOperators>();
103+
types::for_each(types::integer_types(), TestAllSimdAbiFunctor<CheckReferenceIntOperators>());
104+
return 0;
105+
}

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)