diff --git a/stl/inc/algorithm b/stl/inc/algorithm index a0c9712ed3..60207ef2c6 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -10203,7 +10203,7 @@ _NODISCARD constexpr pair<_Ty, _Ty> minmax(initializer_list<_Ty> _Ilist, _Pr _Pr _STL_ASSERT( _Ilist.size() != 0, "An initializer_list passed to std::minmax must not be empty. (N4971 [alg.min.max]/21)"); #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (_Is_min_max_optimization_safe) { + if constexpr (_Is_min_max_value_optimization_safe) { if (!_STD _Is_constant_evaluated()) { const auto _Result = _STD _Minmax_vectorized(_Ilist.begin(), _Ilist.end()); return {static_cast<_Ty>(_Result._Min), static_cast<_Ty>(_Result._Max)}; @@ -10332,13 +10332,21 @@ namespace ranges { using _Vty = iter_value_t<_It>; #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (is_same_v<_Pj, identity> && _Is_min_max_optimization_safe<_It, _Pr> - && sized_sentinel_for<_Se, _It>) { - if (!_STD is_constant_evaluated()) { - const auto _First_ptr = _STD to_address(_First); - const auto _Last_ptr = _First_ptr + (_Last - _First); - const auto _Result = _STD _Minmax_vectorized(_First_ptr, _Last_ptr); - return {static_cast<_Vty>(_Result._Min), static_cast<_Vty>(_Result._Max)}; + if constexpr (is_same_v<_Pj, identity> && sized_sentinel_for<_Se, _It>) { + if constexpr (_Is_min_max_value_optimization_safe<_It, _Pr>) { + if (!_STD is_constant_evaluated()) { + const auto _First_ptr = _STD to_address(_First); + const auto _Last_ptr = _First_ptr + (_Last - _First); + const auto _Result = _STD _Minmax_vectorized(_First_ptr, _Last_ptr); + return {static_cast<_Vty>(_Result._Min), static_cast<_Vty>(_Result._Max)}; + } + } else if constexpr (_Is_min_max_optimization_safe<_It, _Pr>) { + if (!_STD is_constant_evaluated()) { + const auto _First_ptr = _STD to_address(_First); + const auto _Last_ptr = _First_ptr + (_Last - _First); + const auto _Result = _STD _Minmax_element_vectorized(_First_ptr, _Last_ptr); + return {*static_cast(_Result.first), *static_cast(_Result.second)}; + } } } #endif // _USE_STD_VECTOR_ALGORITHMS diff --git a/stl/inc/xutility b/stl/inc/xutility index 110178e141..f6fe60bae2 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -6801,6 +6801,24 @@ constexpr bool _Is_min_max_optimization_safe = // Activate the vector algorithms #endif // _HAS_CXX20 is_same<_Pr, less<>>, is_same<_Pr, less<_Elem>>>>; // predicate is less +// Unlike the position-based vectorized implementation, the value-based vectorized implementation +// does not always produce the expected results for floating-point types. +// +// Efficient vectorization needs to find the vertical minmax first, and then the horizontal one. +// This alters the order of comparison: index zero element is first compared against +// vector size equal index element and only in the end against index one element. +// With equivalent but distinguishable +0.0 and -0.0 values, the altered comparison order +// will not produce the expected result in some cases (will return +0.0 instead of -0.0 or the reverse). +// +// The result is still acceptable for /fp:fast when +0.0 / -0.0 are not expected to be properly distinguished, +// and the compiler itself takes advantage of it. +template > +constexpr bool _Is_min_max_value_optimization_safe = // Activate the vector algorithms for ranges::min/max? +#ifndef _M_FP_FAST + !is_floating_point_v<_Elem> && +#endif // ^^^ !defined(_M_FP_FAST) ^^^ + _Is_min_max_optimization_safe<_Iter, _Pr, _Elem>; + template constexpr _FwdIt _Max_element_unchecked(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { // find largest element #if _USE_STD_VECTOR_ALGORITHMS @@ -6931,7 +6949,7 @@ _NODISCARD constexpr _Ty(max)(initializer_list<_Ty> _Ilist, _Pr _Pred) { _STL_ASSERT( _Ilist.size() != 0, "An initializer_list passed to std::max must not be empty. (N4971 [alg.min.max]/13)"); #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (_Is_min_max_optimization_safe) { + if constexpr (_Is_min_max_value_optimization_safe) { if (!_Is_constant_evaluated()) { return static_cast<_Ty>(_STD _Max_vectorized(_Ilist.begin(), _Ilist.end())); } @@ -6977,7 +6995,7 @@ namespace ranges { _STL_ASSERT(_First != _Last, "An initializer_list passed to std::ranges::max must not be empty. (N4971 [alg.min.max]/13)"); #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (is_same_v<_Pj, identity> && _Is_min_max_optimization_safe) { + if constexpr (is_same_v<_Pj, identity> && _Is_min_max_value_optimization_safe) { if (!_STD is_constant_evaluated()) { return static_cast<_Ty>(_STD _Max_vectorized(_First, _Last)); } @@ -6996,7 +7014,7 @@ namespace ranges { _STL_ASSERT( _UFirst != _ULast, "A range passed to std::ranges::max must not be empty. (N4971 [alg.min.max]/13)"); #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (is_same_v<_Pj, identity> && _Is_min_max_optimization_safe + if constexpr (is_same_v<_Pj, identity> && _Is_min_max_value_optimization_safe && sized_sentinel_for) { if (!_STD is_constant_evaluated()) { const auto _First_ptr = _STD to_address(_UFirst); @@ -7155,7 +7173,7 @@ _NODISCARD constexpr _Ty(min)(initializer_list<_Ty> _Ilist, _Pr _Pred) { _STL_ASSERT( _Ilist.size() != 0, "An initializer_list passed to std::min must not be empty. (N4971 [alg.min.max]/5)"); #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (_Is_min_max_optimization_safe) { + if constexpr (_Is_min_max_value_optimization_safe) { if (!_Is_constant_evaluated()) { return static_cast<_Ty>(_STD _Min_vectorized(_Ilist.begin(), _Ilist.end())); } @@ -7195,7 +7213,7 @@ namespace ranges { _STL_ASSERT(_First != _Last, "An initializer_list passed to std::ranges::min must not be empty. (N4971 [alg.min.max]/5)"); #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (is_same_v<_Pj, identity> && _Is_min_max_optimization_safe) { + if constexpr (is_same_v<_Pj, identity> && _Is_min_max_value_optimization_safe) { if (!_STD is_constant_evaluated()) { return static_cast<_Ty>(_STD _Min_vectorized(_First, _Last)); } @@ -7214,7 +7232,7 @@ namespace ranges { _STL_ASSERT( _UFirst != _ULast, "A range passed to std::ranges::min must not be empty. (N4971 [alg.min.max]/5)"); #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (is_same_v<_Pj, identity> && _Is_min_max_optimization_safe + if constexpr (is_same_v<_Pj, identity> && _Is_min_max_value_optimization_safe && sized_sentinel_for) { if (!_STD is_constant_evaluated()) { const auto _First_ptr = _STD to_address(_UFirst); diff --git a/stl/src/vector_algorithms.cpp b/stl/src/vector_algorithms.cpp index 44cca16920..8d57d7df20 100644 --- a/stl/src/vector_algorithms.cpp +++ b/stl/src/vector_algorithms.cpp @@ -1415,8 +1415,8 @@ namespace { template static __m128 _H_func(const __m128 _Cur, _Fn _Funct) noexcept { __m128 _H_min_val = _Cur; - _H_min_val = _Funct(_H_min_val, _mm_shuffle_ps(_H_min_val, _H_min_val, _MM_SHUFFLE(1, 0, 3, 2))); - _H_min_val = _Funct(_H_min_val, _mm_shuffle_ps(_H_min_val, _H_min_val, _MM_SHUFFLE(2, 3, 0, 1))); + _H_min_val = _Funct(_mm_shuffle_ps(_H_min_val, _H_min_val, _MM_SHUFFLE(2, 3, 0, 1)), _H_min_val); + _H_min_val = _Funct(_mm_shuffle_ps(_H_min_val, _H_min_val, _MM_SHUFFLE(1, 0, 3, 2)), _H_min_val); return _H_min_val; } @@ -1457,11 +1457,11 @@ namespace { } static __m128 _Min(const __m128 _First, const __m128 _Second, __m128 = _mm_undefined_ps()) noexcept { - return _mm_min_ps(_First, _Second); + return _mm_min_ps(_Second, _First); } static __m128 _Max(const __m128 _First, const __m128 _Second, __m128 = _mm_undefined_ps()) noexcept { - return _mm_max_ps(_First, _Second); + return _mm_max_ps(_Second, _First); } static __m128i _Mask_cast(const __m128 _Mask) noexcept { @@ -1485,9 +1485,9 @@ namespace { template static __m256 _H_func(const __m256 _Cur, _Fn _Funct) noexcept { __m256 _H_min_val = _Cur; - _H_min_val = _Funct(_H_min_val, _mm256_permute2f128_ps(_H_min_val, _mm256_undefined_ps(), 0x01)); - _H_min_val = _Funct(_H_min_val, _mm256_shuffle_ps(_H_min_val, _H_min_val, _MM_SHUFFLE(1, 0, 3, 2))); - _H_min_val = _Funct(_H_min_val, _mm256_shuffle_ps(_H_min_val, _H_min_val, _MM_SHUFFLE(2, 3, 0, 1))); + _H_min_val = _Funct(_mm256_shuffle_ps(_H_min_val, _H_min_val, _MM_SHUFFLE(2, 3, 0, 1)), _H_min_val); + _H_min_val = _Funct(_mm256_shuffle_ps(_H_min_val, _H_min_val, _MM_SHUFFLE(1, 0, 3, 2)), _H_min_val); + _H_min_val = _Funct(_mm256_permute2f128_ps(_H_min_val, _mm256_undefined_ps(), 0x01), _H_min_val); return _H_min_val; } @@ -1528,11 +1528,11 @@ namespace { } static __m256 _Min(const __m256 _First, const __m256 _Second, __m256 = _mm256_undefined_ps()) noexcept { - return _mm256_min_ps(_First, _Second); + return _mm256_min_ps(_Second, _First); } static __m256 _Max(const __m256 _First, const __m256 _Second, __m256 = _mm256_undefined_ps()) noexcept { - return _mm256_max_ps(_First, _Second); + return _mm256_max_ps(_Second, _First); } static __m256i _Mask_cast(const __m256 _Mask) noexcept { @@ -1575,7 +1575,7 @@ namespace { template static __m128d _H_func(const __m128d _Cur, _Fn _Funct) noexcept { __m128d _H_min_val = _Cur; - _H_min_val = _Funct(_H_min_val, _mm_shuffle_pd(_H_min_val, _H_min_val, 1)); + _H_min_val = _Funct(_mm_shuffle_pd(_H_min_val, _H_min_val, 1), _H_min_val); return _H_min_val; } @@ -1615,11 +1615,11 @@ namespace { } static __m128d _Min(const __m128d _First, const __m128d _Second, __m128d = _mm_undefined_pd()) noexcept { - return _mm_min_pd(_First, _Second); + return _mm_min_pd(_Second, _First); } static __m128d _Max(const __m128d _First, const __m128d _Second, __m128d = _mm_undefined_pd()) noexcept { - return _mm_max_pd(_First, _Second); + return _mm_max_pd(_Second, _First); } static __m128i _Mask_cast(const __m128d _Mask) noexcept { @@ -1643,8 +1643,8 @@ namespace { template static __m256d _H_func(const __m256d _Cur, _Fn _Funct) noexcept { __m256d _H_min_val = _Cur; - _H_min_val = _Funct(_H_min_val, _mm256_permute4x64_pd(_H_min_val, _MM_SHUFFLE(1, 0, 3, 2))); - _H_min_val = _Funct(_H_min_val, _mm256_shuffle_pd(_H_min_val, _H_min_val, 0b0101)); + _H_min_val = _Funct(_mm256_shuffle_pd(_H_min_val, _H_min_val, 0b0101), _H_min_val); + _H_min_val = _Funct(_mm256_permute4x64_pd(_H_min_val, _MM_SHUFFLE(1, 0, 3, 2)), _H_min_val); return _H_min_val; } @@ -1685,11 +1685,11 @@ namespace { } static __m256d _Min(const __m256d _First, const __m256d _Second, __m256d = _mm256_undefined_pd()) noexcept { - return _mm256_min_pd(_First, _Second); + return _mm256_min_pd(_Second, _First); } static __m256d _Max(const __m256d _First, const __m256d _Second, __m256d = _mm256_undefined_pd()) noexcept { - return _mm256_max_pd(_First, _Second); + return _mm256_max_pd(_Second, _First); } static __m256i _Mask_cast(const __m256d _Mask) noexcept { diff --git a/tests/std/include/test_min_max_element_support.hpp b/tests/std/include/test_min_max_element_support.hpp index a717c7ef85..621c76fe96 100644 --- a/tests/std/include/test_min_max_element_support.hpp +++ b/tests/std/include/test_min_max_element_support.hpp @@ -5,7 +5,9 @@ #include #include +#include #include +#include #include #include @@ -116,6 +118,17 @@ void test_case_min_max_element(const std::vector& input) { assert(*expected_max == actual_max_value); assert(*expected_minmax.first == actual_minmax_value.min); assert(*expected_minmax.second == actual_minmax_value.max); + +#ifndef _M_FP_FAST + // With /fp:fast mode the compiler does not try to produce the code that correctly + // distinguishes +0.0 and -0.0, so the algorithms are not expected to either. + if constexpr (std::is_floating_point_v) { + assert(std::signbit(*expected_min) == std::signbit(actual_min_value)); + assert(std::signbit(*expected_max) == std::signbit(actual_max_value)); + assert(std::signbit(*expected_minmax.first) == std::signbit(actual_minmax_value.min)); + assert(std::signbit(*expected_minmax.second) == std::signbit(actual_minmax_value.max)); + } +#endif // !defined(_M_FP_FAST) } #endif // _HAS_CXX20 } diff --git a/tests/std/include/test_vector_algorithms_support.hpp b/tests/std/include/test_vector_algorithms_support.hpp new file mode 100644 index 0000000000..5cdffd9ffe --- /dev/null +++ b/tests/std/include/test_vector_algorithms_support.hpp @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +inline void initialize_randomness(std::mt19937_64& gen) { + constexpr std::size_t n = std::mt19937_64::state_size; + constexpr std::size_t w = std::mt19937_64::word_size; + static_assert(w % 32 == 0, "w should be evenly divisible by 32"); + constexpr std::size_t k = w / 32; + + std::vector vec(n * k); + + std::random_device rd; + std::generate(vec.begin(), vec.end(), std::ref(rd)); + + std::printf("This is a randomized test.\n"); + std::printf("DO NOT IGNORE/RERUN ANY FAILURES.\n"); + std::printf("You must report them to the STL maintainers.\n\n"); + + std::printf("Seed vector: "); + for (const auto& e : vec) { + std::printf("%u,", e); + } + std::printf("\n"); + + std::seed_seq seq(vec.cbegin(), vec.cend()); + gen.seed(seq); +} + +#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) +extern "C" long __isa_enabled; + +inline void disable_instructions(ISA_AVAILABILITY isa) { + __isa_enabled &= ~(1UL << static_cast(isa)); +} +#endif // (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) + +constexpr std::size_t dataCount = 1024; + +template +void run_randomized_tests_with_different_isa_levels(TestFunc tests) { + std::mt19937_64 gen; + initialize_randomness(gen); + + tests(gen); + +#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) + disable_instructions(__ISA_AVAILABLE_AVX2); + tests(gen); + + disable_instructions(__ISA_AVAILABLE_SSE42); + tests(gen); +#endif // (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) +} diff --git a/tests/std/test.lst b/tests/std/test.lst index f75a8adcd7..7dda49e7f1 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -709,6 +709,7 @@ tests\VSO_0000000_regex_use tests\VSO_0000000_string_view_idl tests\VSO_0000000_type_traits tests\VSO_0000000_vector_algorithms +tests\VSO_0000000_vector_algorithms_floats tests\VSO_0000000_wcfb01_idempotent_container_destructors tests\VSO_0000000_wchar_t_filebuf_xsmeown tests\VSO_0095468_clr_exception_ptr_bad_alloc diff --git a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp index 5a7a152041..1e8e501e50 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp @@ -4,13 +4,12 @@ #include #include #include +#include #include #include -#include #include #include #include -#include #include #include #include @@ -25,49 +24,10 @@ #endif // _HAS_CXX20 #include "test_min_max_element_support.hpp" +#include "test_vector_algorithms_support.hpp" using namespace std; -#pragma warning(disable : 4984) // 'if constexpr' is a C++17 language extension -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wc++17-extensions" // constexpr if is a C++17 extension -#endif // __clang__ - -void initialize_randomness(mt19937_64& gen) { - constexpr size_t n = mt19937_64::state_size; - constexpr size_t w = mt19937_64::word_size; - static_assert(w % 32 == 0, "w should be evenly divisible by 32"); - constexpr size_t k = w / 32; - - vector vec(n * k); - - random_device rd; - generate(vec.begin(), vec.end(), ref(rd)); - - printf("This is a randomized test.\n"); - printf("DO NOT IGNORE/RERUN ANY FAILURES.\n"); - printf("You must report them to the STL maintainers.\n\n"); - - printf("Seed vector: "); - for (const auto& e : vec) { - printf("%u,", e); - } - printf("\n"); - - seed_seq seq(vec.cbegin(), vec.cend()); - gen.seed(seq); -} - -#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) -extern "C" long __isa_enabled; - -void disable_instructions(ISA_AVAILABILITY isa) { - __isa_enabled &= ~(1UL << static_cast(isa)); -} -#endif // (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) - -constexpr size_t dataCount = 1024; - template ptrdiff_t last_known_good_count(FwdIt first, FwdIt last, T v) { ptrdiff_t result = 0; @@ -391,31 +351,6 @@ void test_min_max_element(mt19937_64& gen) { } } -template -void test_min_max_element_floating(mt19937_64& gen) { - normal_distribution dis(-100000.0, 100000.0); - - constexpr auto input_of_input_size = dataCount / 2; - vector input_of_input(input_of_input_size); - input_of_input[0] = -numeric_limits::infinity(); - input_of_input[1] = +numeric_limits::infinity(); - input_of_input[2] = -0.0; - input_of_input[3] = +0.0; - for (size_t i = 4; i < input_of_input_size; ++i) { - input_of_input[i] = dis(gen); - } - - uniform_int_distribution idx_dis(0, input_of_input_size - 1); - - vector input; - input.reserve(dataCount); - test_case_min_max_element(input); - for (size_t attempts = 0; attempts < dataCount; ++attempts) { - input.push_back(input_of_input[idx_dis(gen)]); - test_case_min_max_element(input); - } -} - void test_min_max_element_pointers(mt19937_64& gen) { const short arr[20]{}; @@ -901,10 +836,6 @@ void test_vector_algorithms(mt19937_64& gen) { test_min_max_element(gen); test_min_max_element(gen); - test_min_max_element_floating(gen); - test_min_max_element_floating(gen); - test_min_max_element_floating(gen); - test_min_max_element_pointers(gen); test_min_max_element_special_cases(); // SSE2 vectors @@ -1161,24 +1092,9 @@ int main() { #if _HAS_CXX20 assert(test_constexpr()); #endif // _HAS_CXX20 - - mt19937_64 gen; - initialize_randomness(gen); - - test_vector_algorithms(gen); - test_various_containers(); - test_bitset(gen); -#ifndef _M_CEE_PURE -#if defined(_M_IX86) || defined(_M_X64) - disable_instructions(__ISA_AVAILABLE_AVX2); - test_vector_algorithms(gen); - test_various_containers(); - test_bitset(gen); - - disable_instructions(__ISA_AVAILABLE_SSE42); - test_vector_algorithms(gen); - test_various_containers(); - test_bitset(gen); -#endif // defined(_M_IX86) || defined(_M_X64) -#endif // _M_CEE_PURE + run_randomized_tests_with_different_isa_levels([](mt19937_64& gen) { + test_vector_algorithms(gen); + test_various_containers(); + test_bitset(gen); + }); } diff --git a/tests/std/tests/VSO_0000000_vector_algorithms_floats/env.lst b/tests/std/tests/VSO_0000000_vector_algorithms_floats/env.lst new file mode 100644 index 0000000000..b8b3805e45 --- /dev/null +++ b/tests/std/tests/VSO_0000000_vector_algorithms_floats/env.lst @@ -0,0 +1,57 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\prefix.lst +RUNALL_CROSSLIST +# Copied from ..\usual_matrix.lst, /fp options excluded, /clr and /clr:pure lines dropped +PM_CL="/EHsc /MD /D_ITERATOR_DEBUG_LEVEL=0 /std:c++14 /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MD /std:c++14 /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MD /D_ITERATOR_DEBUG_LEVEL=0 /std:c++17 /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MD /std:c++17 /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MD /D_ITERATOR_DEBUG_LEVEL=0 /std:c++20 /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MD /std:c++20 /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MD /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive- /w14640 /Zc:threadSafeInit- /Zc:noexceptTypes-" +ASAN PM_CL="/EHsc /MD /std:c++latest /permissive- /w14640 /Zc:threadSafeInit- /Zc:noexceptTypes- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MD /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /Zc:char8_t- /w14640 /Zc:threadSafeInit- /Zc:preprocessor" +ASAN PM_CL="/EHsc /MD /std:c++latest /permissive- /Zc:char8_t- /Zc:preprocessor /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MDd /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /Zc:wchar_t- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MDd /std:c++latest /permissive- /Zc:wchar_t- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MDd /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MDd /std:c++latest /permissive- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MDd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++14 /w14640 /Zc:threadSafeInit- /Zc:preprocessor" +ASAN PM_CL="/EHsc /MDd /std:c++14 /w14640 /Zc:threadSafeInit- /Zc:preprocessor -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MDd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++17 /permissive- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MDd /std:c++17 /permissive- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MDd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++20 /permissive- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MDd /std:c++20 /permissive- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MT /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MT /std:c++latest /permissive- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MT /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /analyze:only /analyze:autolog- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MT /std:c++latest /permissive- /analyze:only /analyze:autolog- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MT /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive- /w14640 /Zc:threadSafeInit-" +# No corresponding ASAN config, since the above differs from another config only in IDL +PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MTd /std:c++latest /permissive- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MTd /std:c++latest /permissive- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MTd /std:c++latest /permissive /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive- /analyze:only /analyze:autolog- /w14640 /Zc:threadSafeInit-" +ASAN PM_CL="/EHsc /MTd /std:c++latest /permissive- /analyze:only /analyze:autolog- /w14640 /Zc:threadSafeInit- -fsanitize=address /Zi" PM_LINK="/debug" +PM_CL="/BE /c /EHsc /MD /std:c++14 /w14640 /Zc:threadSafeInit-" +PM_CL="/BE /c /EHsc /MDd /std:c++17 /permissive- /w14640 /Zc:threadSafeInit-" +PM_CL="/BE /c /EHsc /MT /std:c++20 /permissive- /w14640 /Zc:threadSafeInit-" +PM_CL="/BE /c /EHsc /MTd /std:c++latest /permissive- /w14640 /Zc:threadSafeInit-" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MD /std:c++14 /w14640 /Zc:threadSafeInit- --start-no-unused-arguments" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MDd /std:c++17 /w14640 /Zc:threadSafeInit- --start-no-unused-arguments" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MT /std:c++20 /permissive- /w14640 /Zc:threadSafeInit- --start-no-unused-arguments" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MTd /std:c++latest /permissive- /w14640 /Zc:threadSafeInit- --start-no-unused-arguments" +# TRANSITION, GH-3568 +# PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MT /std:c++latest /permissive- /w14640 /Zc:threadSafeInit- -fsanitize=undefined -fno-sanitize-recover=undefined --start-no-unused-arguments" +RUNALL_CROSSLIST +* PM_CL="/fp:strict" +* PM_CL="/fp:precise" +* PM_CL="/fp:fast" +RUNALL_CROSSLIST +* PM_CL="" # Test default setting +* PM_CL="/D_USE_STD_VECTOR_ALGORITHMS=0" # Test escape hatch, see GH-1751 diff --git a/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp new file mode 100644 index 0000000000..c43d6a2a5b --- /dev/null +++ b/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +#include "test_min_max_element_support.hpp" +#include "test_vector_algorithms_support.hpp" + +using namespace std; + +template +void test_min_max_element_floating_with_values(mt19937_64& gen, const vector& input_of_input) { + uniform_int_distribution idx_dis(0, input_of_input.size() - 1); + + vector input; + input.reserve(dataCount); + test_case_min_max_element(input); + for (size_t attempts = 0; attempts < dataCount; ++attempts) { + input.push_back(input_of_input[idx_dis(gen)]); + test_case_min_max_element(input); + } +} + +template +void test_min_max_element_floating_any(mt19937_64& gen) { + normal_distribution dis(-100000.0, 100000.0); + + constexpr auto input_of_input_size = dataCount / 2; + vector input_of_input(input_of_input_size); + input_of_input[0] = -numeric_limits::infinity(); + input_of_input[1] = +numeric_limits::infinity(); + input_of_input[2] = -0.0; + input_of_input[3] = +0.0; + for (size_t i = 4; i < input_of_input_size; ++i) { + input_of_input[i] = dis(gen); + } + + test_min_max_element_floating_with_values(gen, input_of_input); +} + +template +void test_min_max_element_floating_zero(mt19937_64& gen) { + test_min_max_element_floating_with_values(gen, {-0.0, +0.0}); + test_min_max_element_floating_with_values(gen, {-0.0, +0.0, +1.0}); + test_min_max_element_floating_with_values(gen, {-0.0, +0.0, -1.0}); +} + +template +void test_min_max_element_floating_zero_predef() { + for (size_t len = 2; len != 16; ++len) { + for (size_t pos = 0; pos != len; ++pos) { + vector v(len, +0.0); + v[pos] = -0.0; + test_case_min_max_element(v); + + for (size_t i = 0; i != pos; ++i) { + v[i] = +1.0; + } + + test_case_min_max_element(v); + + for (size_t i = 0; i != pos; ++i) { + v[i] = -1.0; + } + + test_case_min_max_element(v); + + for (size_t i = 0; i != pos; ++i) { + v[i] = +0.0; + } + + for (size_t i = pos + 1; i != len; ++i) { + v[i] = +1.0; + } + + test_case_min_max_element(v); + + for (size_t i = pos + 1; i != len; ++i) { + v[i] = -1.0; + } + } + } +} + +template +void test_min_max_element_floating(mt19937_64& gen) { + test_min_max_element_floating_any(gen); + test_min_max_element_floating_zero(gen); + test_min_max_element_floating_zero_predef(); +} + +void test_vector_algorithms(mt19937_64& gen) { + test_min_max_element_floating(gen); + test_min_max_element_floating(gen); +} + +int main() { + run_randomized_tests_with_different_isa_levels(test_vector_algorithms); +}