Scalarize `swap` and `ranges::swap` for arrays (#2700)

This commit is contained in:
Stephan T. Lavavej 2022-05-05 02:44:14 -07:00 коммит произвёл GitHub
Родитель 8999b68330
Коммит 9ccb781ce7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 62 добавлений и 133 удалений

Просмотреть файл

@ -151,22 +151,6 @@ namespace ranges {
constexpr void operator()(_Ty1 (&__t)[_Size], _Ty2 (&__u)[_Size]) const
noexcept(noexcept((*this)(__t[0], __u[0])))
requires requires { (*this)(__t[0], __u[0]); } {
#if _USE_STD_VECTOR_ALGORITHMS
if constexpr (is_same_v<_Ty1, _Ty2> && _Is_trivially_swappable_v<_Ty1>) {
const auto _First1 = __t;
const auto _First2 = __u;
if (_First1 == _First2) {
return;
}
if (!_STD is_constant_evaluated()) {
__std_swap_ranges_trivially_swappable_noalias(_First1, _First1 + _Size, _First2);
return;
}
}
#endif // _USE_STD_VECTOR_ALGORITHMS
for (size_t __i = 0; __i < _Size; ++__i) {
(*this)(__t[__i], __u[__i]);
}

Просмотреть файл

@ -18,39 +18,6 @@ _STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new
// Note: Defining _USE_STD_VECTOR_ALGORITHMS to 0 may be necessary to use "core" headers
// without linking to the STL's separately compiled code.
#if defined(_CRTBLD) && defined(CRTDLL2)
// TRANSITION, ABI: The vector algorithms are compiled into the import lib, so we disable their usage when building
// the DLL. (We could additionally link them into the DLL - not as exports, just for internal usage - but we
// haven't chosen to do that yet.) When we can break ABI and export the vector algorithms from the DLL,
// this preprocessor case should be removed.
#ifndef _USE_STD_VECTOR_ALGORITHMS
#define _USE_STD_VECTOR_ALGORITHMS 0
#elif _USE_STD_VECTOR_ALGORITHMS
#error Vector algorithms are not supported when building msvcp140.dll, but _USE_STD_VECTOR_ALGORITHMS is set.
#endif // _USE_STD_VECTOR_ALGORITHMS
#elif (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) && !defined(_M_HYBRID) && !defined(_M_ARM64EC)
#ifndef _USE_STD_VECTOR_ALGORITHMS
#define _USE_STD_VECTOR_ALGORITHMS 1
#endif // _USE_STD_VECTOR_ALGORITHMS
#else // ^^^ arch supports vector algorithms / no support for vector algorithms vvv
#ifndef _USE_STD_VECTOR_ALGORITHMS
#define _USE_STD_VECTOR_ALGORITHMS 0
#elif _USE_STD_VECTOR_ALGORITHMS
#error Vector algorithms are not supported on this architecture, but _USE_STD_VECTOR_ALGORITHMS is set.
#endif // _USE_STD_VECTOR_ALGORITHMS
#endif // ^^^ no support for vector algorithms ^^^
#if _USE_STD_VECTOR_ALGORITHMS
_EXTERN_C
// See the important comment about the "noalias" attribute in <xutility>.
__declspec(noalias) void __cdecl __std_swap_ranges_trivially_swappable_noalias(
void* _First1, void* _Last1, void* _First2) noexcept;
_END_EXTERN_C
#endif // _USE_STD_VECTOR_ALGORITHMS
_STD_BEGIN
template <class _Ty, _Ty... _Vals>
struct integer_sequence { // sequence of integer parameters

Просмотреть файл

@ -80,29 +80,14 @@ _CONSTEXPR20 void iter_swap(_FwdIt1 _Left, _FwdIt2 _Right) { // swap *_Left and
template <class _Ty, size_t _Size, enable_if_t<_Is_swappable<_Ty>::value, int> _Enabled>
_CONSTEXPR20 void swap(_Ty (&_Left)[_Size], _Ty (&_Right)[_Size]) noexcept(_Is_nothrow_swappable<_Ty>::value) {
_Ty* _First1 = _Left;
_Ty* _Last1 = _First1 + _Size;
_Ty* _First2 = _Right;
if (_First1 == _First2) {
return;
}
#if _USE_STD_VECTOR_ALGORITHMS
if constexpr (_Is_trivially_swappable_v<_Ty>) {
#if _HAS_CXX20
if (!_STD is_constant_evaluated())
#endif // _HAS_CXX20
{
__std_swap_ranges_trivially_swappable_noalias(_First1, _Last1, _First2);
return;
if (&_Left != &_Right) {
_Ty* _First1 = _Left;
_Ty* _Last1 = _First1 + _Size;
_Ty* _First2 = _Right;
for (; _First1 != _Last1; ++_First1, ++_First2) {
_STD iter_swap(_First1, _First2);
}
}
#endif // _USE_STD_VECTOR_ALGORITHMS
for (; _First1 != _Last1; ++_First1, ++_First2) {
_STD iter_swap(_First1, _First2);
}
}
#if _HAS_CXX17

Просмотреть файл

@ -21,6 +21,28 @@ _STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new
#if defined(_CRTBLD) && defined(CRTDLL2)
// TRANSITION, ABI: The vector algorithms are compiled into the import lib, so we disable their usage when building
// the DLL. (We could additionally link them into the DLL - not as exports, just for internal usage - but we
// haven't chosen to do that yet.) When we can break ABI and export the vector algorithms from the DLL,
// this preprocessor case should be removed.
#ifndef _USE_STD_VECTOR_ALGORITHMS
#define _USE_STD_VECTOR_ALGORITHMS 0
#elif _USE_STD_VECTOR_ALGORITHMS
#error Vector algorithms are not supported when building msvcp140.dll, but _USE_STD_VECTOR_ALGORITHMS is set.
#endif // _USE_STD_VECTOR_ALGORITHMS
#elif (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) && !defined(_M_HYBRID) && !defined(_M_ARM64EC)
#ifndef _USE_STD_VECTOR_ALGORITHMS
#define _USE_STD_VECTOR_ALGORITHMS 1
#endif // _USE_STD_VECTOR_ALGORITHMS
#else // ^^^ arch supports vector algorithms / no support for vector algorithms vvv
#ifndef _USE_STD_VECTOR_ALGORITHMS
#define _USE_STD_VECTOR_ALGORITHMS 0
#elif _USE_STD_VECTOR_ALGORITHMS
#error Vector algorithms are not supported on this architecture, but _USE_STD_VECTOR_ALGORITHMS is set.
#endif // _USE_STD_VECTOR_ALGORITHMS
#endif // ^^^ no support for vector algorithms ^^^
#ifdef __CUDACC__
#define _CONSTEXPR_BIT_CAST inline
#else // ^^^ workaround ^^^ / vvv no workaround vvv
@ -40,6 +62,8 @@ __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_1(void* _Firs
__declspec(noalias) void __cdecl __std_reverse_trivially_swappable_2(void* _First, void* _Last) noexcept;
__declspec(noalias) void __cdecl __std_reverse_trivially_swappable_4(void* _First, void* _Last) noexcept;
__declspec(noalias) void __cdecl __std_reverse_trivially_swappable_8(void* _First, void* _Last) noexcept;
__declspec(noalias) void __cdecl __std_swap_ranges_trivially_swappable_noalias(
void* _First1, void* _Last1, void* _First2) noexcept;
__declspec(noalias) size_t
__stdcall __std_count_trivial_1(const void* _First, const void* _Last, uint8_t _Val) noexcept;

Просмотреть файл

@ -826,6 +826,7 @@ void test_buffer_resizing() {
}
void test_gh_2618() {
// GH-2618 <xloctime>: get_time does not return correct year in tm.tm_year if year is 1
auto TestTimeGetYear = [](const char* input, const int expected_y, const int expected_Y,
const int expected_get_year) {
{

Просмотреть файл

@ -1,18 +0,0 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#define _CORE_HEADERS_ONLY
#include <__msvc_all_public_headers.hpp>
#ifdef _YVALS
#error Core headers should not include <yvals.h>.
#endif
#include <chrono>
#ifndef _YVALS
#error Non-core headers like <chrono> should include <yvals.h>.
#endif
int main() {} // COMPILE-ONLY

Просмотреть файл

@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#define _CORE_HEADERS_ONLY
#include <__msvc_all_public_headers.hpp>
#ifdef _YVALS
#error Core headers should not include <yvals.h>.
#endif
void test_gh_2699() {
// GH-2699 Vectorized swap emits error LNK2019:
// unresolved external symbol ___std_swap_ranges_trivially_swappable_noalias
int cats[]{10, 20, 30};
int dogs[]{40, 50, 60};
std::swap(cats, dogs);
assert(cats[1] == 50);
assert(dogs[1] == 20);
#ifdef __cpp_lib_ranges
std::ranges::swap(cats, dogs);
assert(cats[1] == 20);
assert(dogs[1] == 50);
#endif // __cpp_lib_ranges
}
int main() {
test_gh_2699();
}

Просмотреть файл

@ -4,7 +4,6 @@
#include <algorithm>
#include <assert.h>
#include <cstddef>
#include <cstdint>
#include <deque>
#include <isa_availability.h>
#include <list>
@ -12,10 +11,6 @@
#include <type_traits>
#include <vector>
#ifdef __cpp_lib_concepts
#include <concepts>
#endif // __cpp_lib_concepts
using namespace std;
#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE)
@ -172,31 +167,6 @@ void test_swap_ranges(mt19937_64& gen) {
}
}
// GH-2683 "std::swap of arrays, why is there no specialization for trivial types"
template <class T, size_t N>
void test_swap_arrays(mt19937_64& gen) {
const auto fn = [&]() { return static_cast<T>(gen()); };
T left[N];
T right[N];
generate(begin(left), end(left), fn);
generate(begin(right), end(right), fn);
const vector<T> origLeft(begin(left), end(left));
const vector<T> origRight(begin(right), end(right));
swap(left, right);
assert(equal(begin(left), end(left), origRight.begin(), origRight.end()));
assert(equal(begin(right), end(right), origLeft.begin(), origLeft.end()));
#ifdef __cpp_lib_concepts
ranges::swap(left, right);
assert(equal(begin(left), end(left), origLeft.begin(), origLeft.end()));
assert(equal(begin(right), end(right), origRight.begin(), origRight.end()));
#endif // __cpp_lib_concepts
}
void test_vector_algorithms() {
mt19937_64 gen(1729);
@ -251,21 +221,6 @@ void test_vector_algorithms() {
test_swap_ranges<int>(gen);
test_swap_ranges<unsigned int>(gen);
test_swap_ranges<unsigned long long>(gen);
test_swap_arrays<uint8_t, 1>(gen);
test_swap_arrays<uint16_t, 1>(gen);
test_swap_arrays<uint32_t, 1>(gen);
test_swap_arrays<uint64_t, 1>(gen);
test_swap_arrays<uint8_t, 47>(gen);
test_swap_arrays<uint16_t, 47>(gen);
test_swap_arrays<uint32_t, 47>(gen);
test_swap_arrays<uint64_t, 47>(gen);
test_swap_arrays<uint8_t, 512>(gen);
test_swap_arrays<uint16_t, 512>(gen);
test_swap_arrays<uint32_t, 512>(gen);
test_swap_arrays<uint64_t, 512>(gen);
}
template <typename Container1, typename Container2>