Skip to content

[libc++] <experimental/simd> Add swap functions of simd reference #86478

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libcxx/docs/Status/ParallelismProjects.csv
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Section,Description,Dependencies,Assignee,Complete
| `[parallel.simd.whereexpr] <https://wg21.link/N4808>`_, "Where expression class templates", None, Yin Zhang, |In Progress|
| `[parallel.simd.reference] <https://wg21.link/N4808>`_, "`Element references operator value_type() <https://github.com/llvm/llvm-project/pull/68960>`_", None, Yin Zhang, |Complete|
| `[parallel.simd.reference] <https://wg21.link/N4808>`_, "`Element references operator= <https://github.com/llvm/llvm-project/pull/70020>`_", None, Yin Zhang, |Complete|
| `[parallel.simd.reference] <https://wg21.link/N4808>`_, "`Element references swap functions <https://github.com/llvm/llvm-project/pull/86478>`_", None, Yin Zhang, |Complete|
| `[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 default constructor <https://github.com/llvm/llvm-project/pull/70424>`_", None, Yin Zhang, |Complete|
Expand Down
41 changes: 41 additions & 0 deletions libcxx/include/experimental/__simd/reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@
#include <__type_traits/is_assignable.h>
#include <__type_traits/is_same.h>
#include <__utility/forward.h>
#include <__utility/move.h>
#include <cstddef>
#include <experimental/__config>
#include <experimental/__simd/utility.h>

_LIBCPP_PUSH_MACROS
#include <__undef_macros>

#if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)

_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL
Expand Down Expand Up @@ -55,10 +59,47 @@ class __simd_reference {
__set(static_cast<value_type>(std::forward<_Up>(__v)));
return {__s_, __idx_};
}

// Note: This approach might not fully align with the specification,
// which might be a wording defect. (https://wg21.link/N4808 section 9.6.3)
template <class _Tp1, class _Storage1, class _Vp1>
friend void
swap(__simd_reference<_Tp1, _Storage1, _Vp1>&& __a, __simd_reference<_Tp1, _Storage1, _Vp1>&& __b) noexcept;

template <class _Tp1, class _Storage1, class _Vp1>
friend void swap(_Vp1& __a, __simd_reference<_Tp1, _Storage1, _Vp1>&& __b) noexcept;

template <class _Tp1, class _Storage1, class _Vp1>
friend void swap(__simd_reference<_Tp1, _Storage1, _Vp1>&& __a, _Vp1& __b) noexcept;
};

template <class _Tp, class _Storage, class _Vp>
_LIBCPP_HIDE_FROM_ABI void
swap(__simd_reference<_Tp, _Storage, _Vp>&& __a, __simd_reference<_Tp, _Storage, _Vp>&& __b) noexcept {
_Vp __tmp(std::move(__a));
std::move(__a) = std::move(__b);
std::move(__b) = std::move(__tmp);
}

template <class _Tp, class _Storage, class _Vp>
_LIBCPP_HIDE_FROM_ABI void swap(_Vp& __a, __simd_reference<_Tp, _Storage, _Vp>&& __b) noexcept {
_Vp __tmp(std::move(__a));
__a = std::move(__b);
std::move(__b) = std::move(__tmp);
}

template <class _Tp, class _Storage, class _Vp>
_LIBCPP_HIDE_FROM_ABI void swap(__simd_reference<_Tp, _Storage, _Vp>&& __a, _Vp& __b) noexcept {
_Vp __tmp(std::move(__a));
std::move(__a) = std::move(__b);
__b = std::move(__tmp);
}

} // namespace parallelism_v2
_LIBCPP_END_NAMESPACE_EXPERIMENTAL

#endif // _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)

_LIBCPP_POP_MACROS

#endif // _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H
1 change: 1 addition & 0 deletions libcxx/include/experimental/simd
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ inline namespace parallelism_v2 {
#include <experimental/__config>
#include <experimental/__simd/aligned_tag.h>
#include <experimental/__simd/declaration.h>
#include <experimental/__simd/reference.h>
#include <experimental/__simd/scalar.h>
#include <experimental/__simd/simd.h>
#include <experimental/__simd/simd_mask.h>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//===----------------------------------------------------------------------===//
//
// 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>
//
// Note: To ensure the swap functions can be called directly in the std::experimental namespace,
// the implementation approach might not fully align with the specification.
//
// [simd.reference]
// friend void swap(reference&& a, reference&& b) noexcept;
// friend void swap(value_type& a, reference&& b) noexcept;
// friend void swap(reference&& a, value_type& b) noexcept;

#include "../test_utils.h"
#include <experimental/simd>

namespace ex = std::experimental::parallelism_v2;

template <class T, std::size_t>
struct CheckSimdRefSwap {
template <class SimdAbi>
void operator()() {
ex::simd<T, SimdAbi> origin_simd_1(1);
ex::simd<T, SimdAbi> origin_simd_2(2);
T value = 3;

static_assert(noexcept(ex::swap(std::move(origin_simd_1[0]), std::move(origin_simd_2[0]))));
ex::swap(std::move(origin_simd_1[0]), std::move(origin_simd_2[0]));
assert((origin_simd_1[0] == 2) && (origin_simd_2[0] == 1));

static_assert(noexcept(ex::swap(std::move(origin_simd_1[0]), value)));
ex::swap(std::move(origin_simd_1[0]), value);
assert((origin_simd_1[0] == 3) && (value == 2));

static_assert(noexcept(ex::swap(value, std::move(origin_simd_2[0]))));
ex::swap(value, std::move(origin_simd_2[0]));
assert((value == 1) && (origin_simd_2[0] == 2));
}
};

template <class T, std::size_t>
struct CheckMaskRefSwap {
template <class SimdAbi>
void operator()() {
ex::simd_mask<T, SimdAbi> origin_mask_1(true);
ex::simd_mask<T, SimdAbi> origin_mask_2(false);
bool value = true;

static_assert(noexcept(ex::swap(std::move(origin_mask_1[0]), std::move(origin_mask_2[0]))));
ex::swap(std::move(origin_mask_1[0]), std::move(origin_mask_2[0]));
assert((origin_mask_1[0] == false) && (origin_mask_2[0] == true));

static_assert(noexcept(ex::swap(std::move(origin_mask_1[0]), value)));
ex::swap(std::move(origin_mask_1[0]), value);
assert((origin_mask_1[0] == true) && (value == false));

static_assert(noexcept(ex::swap(value, std::move(origin_mask_2[0]))));
ex::swap(value, std::move(origin_mask_2[0]));
assert((value == true) && (origin_mask_2[0] == false));
}
};

int main(int, char**) {
test_all_simd_abi<CheckSimdRefSwap>();
test_all_simd_abi<CheckMaskRefSwap>();
return 0;
}
Loading