Skip to content

Commit 6ec1ddf

Browse files
authored
[libc++] <experimental/simd> Add swap functions of simd reference (#86478)
1 parent 95f983f commit 6ec1ddf

File tree

4 files changed

+117
-0
lines changed

4 files changed

+117
-0
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 swap functions <https://github.com/llvm/llvm-project/pull/86478>`_", 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: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@
1313
#include <__type_traits/is_assignable.h>
1414
#include <__type_traits/is_same.h>
1515
#include <__utility/forward.h>
16+
#include <__utility/move.h>
1617
#include <cstddef>
1718
#include <experimental/__config>
1819
#include <experimental/__simd/utility.h>
1920

21+
_LIBCPP_PUSH_MACROS
22+
#include <__undef_macros>
23+
2024
#if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
2125

2226
_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL
@@ -55,10 +59,47 @@ class __simd_reference {
5559
__set(static_cast<value_type>(std::forward<_Up>(__v)));
5660
return {__s_, __idx_};
5761
}
62+
63+
// Note: This approach might not fully align with the specification,
64+
// which might be a wording defect. (https://wg21.link/N4808 section 9.6.3)
65+
template <class _Tp1, class _Storage1, class _Vp1>
66+
friend void
67+
swap(__simd_reference<_Tp1, _Storage1, _Vp1>&& __a, __simd_reference<_Tp1, _Storage1, _Vp1>&& __b) noexcept;
68+
69+
template <class _Tp1, class _Storage1, class _Vp1>
70+
friend void swap(_Vp1& __a, __simd_reference<_Tp1, _Storage1, _Vp1>&& __b) noexcept;
71+
72+
template <class _Tp1, class _Storage1, class _Vp1>
73+
friend void swap(__simd_reference<_Tp1, _Storage1, _Vp1>&& __a, _Vp1& __b) noexcept;
5874
};
5975

76+
template <class _Tp, class _Storage, class _Vp>
77+
_LIBCPP_HIDE_FROM_ABI void
78+
swap(__simd_reference<_Tp, _Storage, _Vp>&& __a, __simd_reference<_Tp, _Storage, _Vp>&& __b) noexcept {
79+
_Vp __tmp(std::move(__a));
80+
std::move(__a) = std::move(__b);
81+
std::move(__b) = std::move(__tmp);
82+
}
83+
84+
template <class _Tp, class _Storage, class _Vp>
85+
_LIBCPP_HIDE_FROM_ABI void swap(_Vp& __a, __simd_reference<_Tp, _Storage, _Vp>&& __b) noexcept {
86+
_Vp __tmp(std::move(__a));
87+
__a = std::move(__b);
88+
std::move(__b) = std::move(__tmp);
89+
}
90+
91+
template <class _Tp, class _Storage, class _Vp>
92+
_LIBCPP_HIDE_FROM_ABI void swap(__simd_reference<_Tp, _Storage, _Vp>&& __a, _Vp& __b) noexcept {
93+
_Vp __tmp(std::move(__a));
94+
std::move(__a) = std::move(__b);
95+
__b = std::move(__tmp);
96+
}
97+
6098
} // namespace parallelism_v2
6199
_LIBCPP_END_NAMESPACE_EXPERIMENTAL
62100

63101
#endif // _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
102+
103+
_LIBCPP_POP_MACROS
104+
64105
#endif // _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H

libcxx/include/experimental/simd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ inline namespace parallelism_v2 {
7878
#include <experimental/__config>
7979
#include <experimental/__simd/aligned_tag.h>
8080
#include <experimental/__simd/declaration.h>
81+
#include <experimental/__simd/reference.h>
8182
#include <experimental/__simd/scalar.h>
8283
#include <experimental/__simd/simd.h>
8384
#include <experimental/__simd/simd_mask.h>
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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+
// Note: To ensure the swap functions can be called directly in the std::experimental namespace,
14+
// the implementation approach might not fully align with the specification.
15+
//
16+
// [simd.reference]
17+
// friend void swap(reference&& a, reference&& b) noexcept;
18+
// friend void swap(value_type& a, reference&& b) noexcept;
19+
// friend void swap(reference&& a, value_type& b) noexcept;
20+
21+
#include "../test_utils.h"
22+
#include <experimental/simd>
23+
24+
namespace ex = std::experimental::parallelism_v2;
25+
26+
template <class T, std::size_t>
27+
struct CheckSimdRefSwap {
28+
template <class SimdAbi>
29+
void operator()() {
30+
ex::simd<T, SimdAbi> origin_simd_1(1);
31+
ex::simd<T, SimdAbi> origin_simd_2(2);
32+
T value = 3;
33+
34+
static_assert(noexcept(ex::swap(std::move(origin_simd_1[0]), std::move(origin_simd_2[0]))));
35+
ex::swap(std::move(origin_simd_1[0]), std::move(origin_simd_2[0]));
36+
assert((origin_simd_1[0] == 2) && (origin_simd_2[0] == 1));
37+
38+
static_assert(noexcept(ex::swap(std::move(origin_simd_1[0]), value)));
39+
ex::swap(std::move(origin_simd_1[0]), value);
40+
assert((origin_simd_1[0] == 3) && (value == 2));
41+
42+
static_assert(noexcept(ex::swap(value, std::move(origin_simd_2[0]))));
43+
ex::swap(value, std::move(origin_simd_2[0]));
44+
assert((value == 1) && (origin_simd_2[0] == 2));
45+
}
46+
};
47+
48+
template <class T, std::size_t>
49+
struct CheckMaskRefSwap {
50+
template <class SimdAbi>
51+
void operator()() {
52+
ex::simd_mask<T, SimdAbi> origin_mask_1(true);
53+
ex::simd_mask<T, SimdAbi> origin_mask_2(false);
54+
bool value = true;
55+
56+
static_assert(noexcept(ex::swap(std::move(origin_mask_1[0]), std::move(origin_mask_2[0]))));
57+
ex::swap(std::move(origin_mask_1[0]), std::move(origin_mask_2[0]));
58+
assert((origin_mask_1[0] == false) && (origin_mask_2[0] == true));
59+
60+
static_assert(noexcept(ex::swap(std::move(origin_mask_1[0]), value)));
61+
ex::swap(std::move(origin_mask_1[0]), value);
62+
assert((origin_mask_1[0] == true) && (value == false));
63+
64+
static_assert(noexcept(ex::swap(value, std::move(origin_mask_2[0]))));
65+
ex::swap(value, std::move(origin_mask_2[0]));
66+
assert((value == true) && (origin_mask_2[0] == false));
67+
}
68+
};
69+
70+
int main(int, char**) {
71+
test_all_simd_abi<CheckSimdRefSwap>();
72+
test_all_simd_abi<CheckMaskRefSwap>();
73+
return 0;
74+
}

0 commit comments

Comments
 (0)