From 0ee8d7e370b504a3dc92eb28267e2f812ca379b6 Mon Sep 17 00:00:00 2001 From: jtlap Date: Sun, 1 Sep 2024 09:55:28 +0200 Subject: [PATCH 01/25] is_denormal --- .../regular/impl/simd/x86/is_denormal.hpp | 67 +++++++++++++++++++ .../eve/module/core/regular/is_denormal.hpp | 4 ++ 2 files changed, 71 insertions(+) create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_denormal.hpp diff --git a/include/eve/module/core/regular/impl/simd/x86/is_denormal.hpp b/include/eve/module/core/regular/impl/simd/x86/is_denormal.hpp new file mode 100644 index 0000000000..a521bf858b --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_denormal.hpp @@ -0,0 +1,67 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include + +namespace eve::detail +{ + template + EVE_FORCEINLINE logical> is_denormal_(EVE_REQUIRES(avx512_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = to_integer(fpclass::denorm); + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16 )return s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return s_t {_mm_fpclass_ps_mask(a, f)}; + + } + +// ----------------------------------------------------------------------------------------------- +// masked implementation + template + EVE_FORCEINLINE auto is_denormal_(EVE_REQUIRES(avx512_), + C const& cx, + O const& o, + wide const& v) noexcept + requires x86_abi> + { + constexpr auto c = categorize>(); + + if constexpr( C::has_alternative || C::is_complete || abi_t::is_wide_logical ) + { + return is_denormal.behavior(cpu_{}, o, v, v); + } + else + { + auto m = expand_mask(cx, as> {}).storage().value; + constexpr auto f = to_integer(fpclass::denorm); + + if constexpr( c == category::float32x16 ) return mask16 {_mm512_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x8 ) return mask8 {_mm512_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x8 ) return mask8 {_mm256_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x4 ) return mask8 {_mm256_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x4 ) return mask8 {_mm_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x2 ) return mask8 {_mm_mask_fpclass_pd_mask(m, v, f)}; + } + } +} diff --git a/include/eve/module/core/regular/is_denormal.hpp b/include/eve/module/core/regular/is_denormal.hpp index 70e03d4956..d2fd16c368 100644 --- a/include/eve/module/core/regular/is_denormal.hpp +++ b/include/eve/module/core/regular/is_denormal.hpp @@ -94,3 +94,7 @@ namespace eve } } } + +#if defined(EVE_INCLUDE_X86_HEADER) +# include +#endif From 7a4102c5d55956b39119f59bc558aa5f2496d30d Mon Sep 17 00:00:00 2001 From: jtlap Date: Sun, 1 Sep 2024 10:38:54 +0200 Subject: [PATCH 02/25] fpclass flags --- include/eve/detail/function/simd/x86/flags.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/eve/detail/function/simd/x86/flags.hpp b/include/eve/detail/function/simd/x86/flags.hpp index 69b3caa551..5fff3d38af 100644 --- a/include/eve/detail/function/simd/x86/flags.hpp +++ b/include/eve/detail/function/simd/x86/flags.hpp @@ -28,6 +28,11 @@ namespace eve::detail return static_cast(a) | static_cast(b); } + EVE_FORCEINLINE constexpr std::int32_t to_integer(fpclass a) noexcept + { + return static_cast(a); + } + enum class range_ctrl { min = 0b00 , max = 0b01 , absolute_min= 0b10 From 2266f74c0b8bd7b814ea564f0fb889e64ec686d9 Mon Sep 17 00:00:00 2001 From: jtlap Date: Sun, 1 Sep 2024 15:10:38 +0200 Subject: [PATCH 03/25] eqpz --- include/eve/module/core/regular/core.hpp | 1 + .../core/regular/impl/simd/x86/is_eqpz.hpp | 66 +++++++++++++ include/eve/module/core/regular/is_eqpz.hpp | 93 +++++++++++++++++++ test/doc/core/is_eqpz.cpp | 16 ++++ test/random/module/core/is_eqpz.cpp | 21 +++++ test/random/module/core/is_eqpz.hpp | 21 +++++ test/unit/module/core/is_eqpz.cpp | 38 ++++++++ 7 files changed, 256 insertions(+) create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_eqpz.hpp create mode 100644 include/eve/module/core/regular/is_eqpz.hpp create mode 100644 test/doc/core/is_eqpz.cpp create mode 100644 test/random/module/core/is_eqpz.cpp create mode 100644 test/random/module/core/is_eqpz.hpp create mode 100644 test/unit/module/core/is_eqpz.cpp diff --git a/include/eve/module/core/regular/core.hpp b/include/eve/module/core/regular/core.hpp index 2f842d38f4..c9027f773c 100644 --- a/include/eve/module/core/regular/core.hpp +++ b/include/eve/module/core/regular/core.hpp @@ -92,6 +92,7 @@ #include #include #include +#include #include #include #include diff --git a/include/eve/module/core/regular/impl/simd/x86/is_eqpz.hpp b/include/eve/module/core/regular/impl/simd/x86/is_eqpz.hpp new file mode 100644 index 0000000000..92bd20d7b9 --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_eqpz.hpp @@ -0,0 +1,66 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace eve::detail +{ + template + EVE_FORCEINLINE logical> is_eqpz_(EVE_REQUIRES(avx512_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = to_integer(fpclass::poszero); + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16 )return s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return s_t {_mm_fpclass_ps_mask(a, f)}; + + } + +// ----------------------------------------------------------------------------------------------- +// masked implementation + template + EVE_FORCEINLINE auto is_eqpz_(EVE_REQUIRES(avx512_), + C const& cx, + O const& o, + wide const& v) noexcept + requires x86_abi> + { + constexpr auto c = categorize>(); + + if constexpr( C::has_alternative || C::is_complete || abi_t::is_wide_logical ) + { + return is_eqpz.behavior(cpu_{}, o, v, v); + } + else + { + auto m = expand_mask(cx, as> {}).storage().value; + constexpr auto f = to_integer(fpclass::poszero); + + if constexpr( c == category::float32x16 ) return mask16 {_mm512_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x8 ) return mask8 {_mm512_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x8 ) return mask8 {_mm256_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x4 ) return mask8 {_mm256_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x4 ) return mask8 {_mm_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x2 ) return mask8 {_mm_mask_fpclass_pd_mask(m, v, f)}; + } + } +} diff --git a/include/eve/module/core/regular/is_eqpz.hpp b/include/eve/module/core/regular/is_eqpz.hpp new file mode 100644 index 0000000000..ed6cbe843c --- /dev/null +++ b/include/eve/module/core/regular/is_eqpz.hpp @@ -0,0 +1,93 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +namespace eve +{ + template + struct is_eqpz_t : elementwise_callable + { + template + EVE_FORCEINLINE constexpr as_logical_t + operator()(T t) const noexcept + { + return EVE_DISPATCH_CALL(t); + } + + EVE_CALLABLE_OBJECT(is_eqpz_t, is_eqpz_); + }; + +//================================================================================================ +//! @addtogroup core_predicates +//! @{ +//! @var is_eqpz +//! @brief `elementwise callable` returning a logical true if and only if the element value +//! is a floating zero with signbit unset. +//! +//! @groupheader{Header file} +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace eve +//! { +//! // Regular overload +//! constexpr auto is_eqpz(value auto x) noexcept; // 1 +//! +//! // Lanes masking +//! constexpr auto is_eqpz[conditional_expr auto c](value auto x) noexcept; // 2 +//! constexpr auto is_eqpz[logical_value auto m](value auto x) noexcept; // 2 +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `x`: [floating argument](@ref eve::floting_value). +//! * `c`: [Conditional expression](@ref conditional_expr) masking the operation. +//! * `m`: [Logical value](@ref logical) masking the operation. +//! +//! **Return value** +//! +//! 1. returns [elementwise](@ref glossary_elementwise) true if and only +//! if the element value is zero with sign bit unset. +//! 2. [The operation is performed conditionnaly](@ref conditional). +//! +//! @groupheader{Example} +//! @godbolt{doc/core/is_eqpz.cpp} +//================================================================================================ + inline constexpr auto is_eqpz = functor; +//================================================================================================ +//! @} +//================================================================================================ + + namespace detail + { + template + EVE_FORCEINLINE constexpr as_logical_t + is_eqpz_(EVE_REQUIRES(cpu_), O const &, T const& a) noexcept + { + return bit_cast(is_eqz(bit_cast(a, as>())),as>()) ; + } + } +} + +#if defined(EVE_INCLUDE_X86_HEADER) +# include +#endif diff --git a/test/doc/core/is_eqpz.cpp b/test/doc/core/is_eqpz.cpp new file mode 100644 index 0000000000..375fd52c1a --- /dev/null +++ b/test/doc/core/is_eqpz.cpp @@ -0,0 +1,16 @@ +// revision 0 +#include +#include + +int main() +{ + eve::wide wf0{0.0, 1.0, 2.0, 3.0, -1.0, -2.0, -3.0, -0.0}; + eve::wide wi0{0, 1, 2, 3, -1, -2, -3, -4}; + eve::wide wu0{0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u}; + + std::cout << "<- wf0 = " << wf0 << "\n"; + + std::cout << "-> is_eqpz(wf0) = " << eve::is_eqpz(wf0) << "\n"; + std::cout << "-> is_eqpz[ignore_last(2)](wf0) = " << eve::is_eqpz[eve::ignore_last(2)](wf0) << "\n"; + std::cout << "-> is_eqpz[wf0 != 0](wf0) = " << eve::is_eqpz[wf0 != 0](wf0) << "\n"; +} diff --git a/test/random/module/core/is_eqpz.cpp b/test/random/module/core/is_eqpz.cpp new file mode 100644 index 0000000000..55f9a47d27 --- /dev/null +++ b/test/random/module/core/is_eqpz.cpp @@ -0,0 +1,21 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include +#include "producers.hpp" + +#include + +TTS_CASE_TPL("Random check for eve::is_eqz", eve::test::simd::ieee_reals) +(tts::type) +{ + using e_t = eve::element_type_t; + auto vmin = eve::valmin(eve::as()); + auto vmax = eve::valmax(eve::as()); + auto std_is_eqz = [](auto e) -> eve::logical{ return e == 0 && eve::is_positive(e); }; + EVE_ULP_RANGE_CHECK( T, eve::uniform_prng(vmin, vmax), std_is_eqz, eve::is_eqz ); + }; diff --git a/test/random/module/core/is_eqpz.hpp b/test/random/module/core/is_eqpz.hpp new file mode 100644 index 0000000000..55f9a47d27 --- /dev/null +++ b/test/random/module/core/is_eqpz.hpp @@ -0,0 +1,21 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include +#include "producers.hpp" + +#include + +TTS_CASE_TPL("Random check for eve::is_eqz", eve::test::simd::ieee_reals) +(tts::type) +{ + using e_t = eve::element_type_t; + auto vmin = eve::valmin(eve::as()); + auto vmax = eve::valmax(eve::as()); + auto std_is_eqz = [](auto e) -> eve::logical{ return e == 0 && eve::is_positive(e); }; + EVE_ULP_RANGE_CHECK( T, eve::uniform_prng(vmin, vmax), std_is_eqz, eve::is_eqz ); + }; diff --git a/test/unit/module/core/is_eqpz.cpp b/test/unit/module/core/is_eqpz.cpp new file mode 100644 index 0000000000..e3b38c6918 --- /dev/null +++ b/test/unit/module/core/is_eqpz.cpp @@ -0,0 +1,38 @@ +//================================================================================================== +/** + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#include "test.hpp" + +#include + +//================================================================================================== +// Types tests +//================================================================================================== +TTS_CASE_TPL("Check return types of eve::is_eqpz(simd)", eve::test::simd::ieee_reals) +(tts::type) +{ + using eve::logical; + using v_t = eve::element_type_t; + TTS_EXPR_IS(eve::is_eqpz(T()), logical); + TTS_EXPR_IS(eve::is_eqpz(v_t()), logical); +}; + +//================================================================================================== +// Tests for eve::is_eqpz +//================================================================================================== + +TTS_CASE_WITH("Check behavior of eve::is_eqpz(simd)", + eve::test::simd::ieee_reals, + tts::generate(tts::ramp(0), tts::logicals(0, 3))) +(T const& a0, M const& t) +{ + using eve::detail::map; + using v_t = eve::element_type_t; + + TTS_EQUAL(eve::is_eqpz(a0), map([](auto e) -> eve::logical { return e == 0 && eve::is_positive(e); }, a0)); + TTS_EQUAL(eve::is_eqpz[t](a0), eve::if_else(t, eve::is_eqpz(a0), eve::false_(eve::as(a0)))); +}; From 01fd4e8f40864b73c3eea094e17922228c62c170 Mon Sep 17 00:00:00 2001 From: jtlap Date: Sun, 1 Sep 2024 15:24:07 +0200 Subject: [PATCH 04/25] is_eqz --- .../core/regular/impl/simd/x86/is_eqz.hpp | 76 +++++++++++++++++++ include/eve/module/core/regular/is_eqz.hpp | 4 + test/doc/core/is_eqz.cpp | 4 +- 3 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_eqz.hpp diff --git a/include/eve/module/core/regular/impl/simd/x86/is_eqz.hpp b/include/eve/module/core/regular/impl/simd/x86/is_eqz.hpp new file mode 100644 index 0000000000..a568301cff --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_eqz.hpp @@ -0,0 +1,76 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace eve::detail +{ + // Generate better code on x86 than just comparing to 0 + template + EVE_FORCEINLINE constexpr auto + is_ltz_(EVE_REQUIRES(sse2_), O const &, wide const& v) noexcept + requires(sizeof(T) < 8 && x86_abi> && abi_t::is_wide_logical) + { + using l_t = as_logical_t>; + constexpr auto shift = 8 * sizeof(T) - 1; + return bit_cast(v >> shift, as {}); + } + + template + EVE_FORCEINLINE logical> is_ltz_(EVE_REQUIRES(avx512_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = fpclass::poszero | fpclass::negzero; + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16) return s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return s_t {_mm_fpclass_ps_mask(a, f)}; + } + + +// ----------------------------------------------------------------------------------------------- +// masked implementation + template + EVE_FORCEINLINE auto is_ltz_(EVE_REQUIRES(avx512_), + C const& cx, + O const& o, + wide const& v) noexcept + requires x86_abi> + { + constexpr auto c = categorize>(); + + if constexpr( C::has_alternative || C::is_complete || abi_t::is_wide_logical ) + { + return is_eqz.behavior(cpu_{}, o, v, v); + } + else + { + auto m = expand_mask(cx, as> {}).storage().value; + constexpr auto f = fpclass::poszero | fpclass::negzero; + + if constexpr( c == category::float32x16 ) return mask16 {_mm512_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x8 ) return mask8 {_mm512_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x8 ) return mask8 {_mm256_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x4 ) return mask8 {_mm256_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x4 ) return mask8 {_mm_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x2 ) return mask8 {_mm_mask_fpclass_pd_mask(m, v, f)}; + } + } +} diff --git a/include/eve/module/core/regular/is_eqz.hpp b/include/eve/module/core/regular/is_eqz.hpp index a8a493feb9..9e51a191cd 100644 --- a/include/eve/module/core/regular/is_eqz.hpp +++ b/include/eve/module/core/regular/is_eqz.hpp @@ -87,3 +87,7 @@ namespace eve } } } + +#if defined(EVE_INCLUDE_X86_HEADER) +# include +#endif diff --git a/test/doc/core/is_eqz.cpp b/test/doc/core/is_eqz.cpp index 18a53a58b1..0a49354526 100644 --- a/test/doc/core/is_eqz.cpp +++ b/test/doc/core/is_eqz.cpp @@ -4,14 +4,14 @@ int main() { - eve::wide wf0{0.0, 1.0, 2.0, 3.0, -1.0, -2.0, -3.0, -4.0}; + eve::wide wf0{0.0, 1.0, 2.0, 3.0, -1.0, -2.0, -3.0, -0.0}; eve::wide wi0{0, 1, 2, 3, -1, -2, -3, -4}; eve::wide wu0{0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u}; std::cout << "<- wf0 = " << wf0 << "\n"; std::cout << "<- wi0 = " << wi0 << "\n"; std::cout << "<- wu0 = " << wu0 << "\n"; - + std::cout << "-> is_eqz(wf0) = " << eve::is_eqz(wf0) << "\n"; std::cout << "-> is_eqz[ignore_last(2)](wf0) = " << eve::is_eqz[eve::ignore_last(2)](wf0) << "\n"; std::cout << "-> is_eqz[wf0 != 0](wf0) = " << eve::is_eqz[wf0 != 0](wf0) << "\n"; From 44e881e63346eccb5d3b8abd3e0ed25224aff15f Mon Sep 17 00:00:00 2001 From: jtlap Date: Sun, 1 Sep 2024 17:37:41 +0200 Subject: [PATCH 05/25] is_eqmz --- include/eve/module/core/regular/core.hpp | 3 +- .../core/regular/impl/simd/x86/is_eqmz.hpp | 66 +++++++++++++ include/eve/module/core/regular/is_eqmz.hpp | 94 +++++++++++++++++++ test/doc/core/is_eqmz.cpp | 16 ++++ .../module/core/{is_eqpz.hpp => is_eqmz.cpp} | 6 +- test/unit/module/core/is_eqmz.cpp | 38 ++++++++ 6 files changed, 219 insertions(+), 4 deletions(-) create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_eqmz.hpp create mode 100644 include/eve/module/core/regular/is_eqmz.hpp create mode 100644 test/doc/core/is_eqmz.cpp rename test/random/module/core/{is_eqpz.hpp => is_eqmz.cpp} (75%) create mode 100644 test/unit/module/core/is_eqmz.cpp diff --git a/include/eve/module/core/regular/core.hpp b/include/eve/module/core/regular/core.hpp index c9027f773c..e161ce6ddb 100644 --- a/include/eve/module/core/regular/core.hpp +++ b/include/eve/module/core/regular/core.hpp @@ -91,8 +91,9 @@ #include #include #include -#include +#include #include +#include #include #include #include diff --git a/include/eve/module/core/regular/impl/simd/x86/is_eqmz.hpp b/include/eve/module/core/regular/impl/simd/x86/is_eqmz.hpp new file mode 100644 index 0000000000..655c41902f --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_eqmz.hpp @@ -0,0 +1,66 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace eve::detail +{ + template + EVE_FORCEINLINE logical> is_eqmz_(EVE_REQUIRES(avx512_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = to_integer(fpclass::negzero); + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16 )return s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return s_t {_mm_fpclass_ps_mask(a, f)}; + + } + +// ----------------------------------------------------------------------------------------------- +// masked implementation + template + EVE_FORCEINLINE auto is_eqmz_(EVE_REQUIRES(avx512_), + C const& cx, + O const& o, + wide const& v) noexcept + requires x86_abi> + { + constexpr auto c = categorize>(); + + if constexpr( C::has_alternative || C::is_complete || abi_t::is_wide_logical ) + { + return is_eqmz.behavior(cpu_{}, o, v, v); + } + else + { + auto m = expand_mask(cx, as> {}).storage().value; + constexpr auto f = to_integer(fpclass::negzero); + + if constexpr( c == category::float32x16 ) return mask16 {_mm512_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x8 ) return mask8 {_mm512_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x8 ) return mask8 {_mm256_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x4 ) return mask8 {_mm256_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x4 ) return mask8 {_mm_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x2 ) return mask8 {_mm_mask_fpclass_pd_mask(m, v, f)}; + } + } +} diff --git a/include/eve/module/core/regular/is_eqmz.hpp b/include/eve/module/core/regular/is_eqmz.hpp new file mode 100644 index 0000000000..34005d39c6 --- /dev/null +++ b/include/eve/module/core/regular/is_eqmz.hpp @@ -0,0 +1,94 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once +#include +#include +#include +#include +#include +#include +#include + +namespace eve +{ + template + struct is_eqmz_t : elementwise_callable + { + template + EVE_FORCEINLINE constexpr as_logical_t + operator()(T t) const noexcept + { + return EVE_DISPATCH_CALL(t); + } + + EVE_CALLABLE_OBJECT(is_eqmz_t, is_eqmz_); + }; + +//================================================================================================ +//! @addtogroup core_predicates +//! @{ +//! @var is_eqmz +//! @brief `elementwise callable` returning a logical true if and only if the element +//! value is a floating zero with sign bit set. +//! +//! @groupheader{Header file} +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace eve +//! { +//! // Regular overload +//! constexpr auto is_eqmz(value auto x) noexcept; // 1 +//! +//! // Lanes masking +//! constexpr auto is_eqmz[conditional_expr auto c](value auto x) noexcept; // 2 +//! constexpr auto is_eqmz[logical_value auto m](value auto x) noexcept; // 2 +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `x`: [floating argument](@ref eve::floating_value). +//! * `c`: [Conditional expression](@ref conditional_expr) masking the operation. +//! * `m`: [Logical value](@ref logical) masking the operation. +//! +//! **Return value** +//! +//! 1. returns [elementwise](@ref glossary_elementwise) true if and only +//! if the element value is a floating zero with sign bit set (`mzero`). +//! 2. [The operation is performed conditionnaly](@ref conditional). +//! +//! @note This function is not defined for integral typed entries to avoid misuse. +//! +//! @groupheader{Example} +//! @godbolt{doc/core/is_eqmz.cpp} +//================================================================================================ + inline constexpr auto is_eqmz = functor; +//================================================================================================ +//! @} +//================================================================================================ + + namespace detail + { + template + EVE_FORCEINLINE constexpr as_logical_t + is_eqmz_(EVE_REQUIRES(cpu_), O const &, T const& a) noexcept + { + return logical_andnot(is_eqz(a), is_eqpz(a)); + } + } +} + +#if defined(EVE_INCLUDE_X86_HEADER) +# include +#endif diff --git a/test/doc/core/is_eqmz.cpp b/test/doc/core/is_eqmz.cpp new file mode 100644 index 0000000000..cd18556d50 --- /dev/null +++ b/test/doc/core/is_eqmz.cpp @@ -0,0 +1,16 @@ +// revision 0 +#include +#include + +int main() +{ + eve::wide wf0{0.0, 1.0, 2.0, 3.0, -1.0, -2.0, -3.0, -0.0}; + eve::wide wi0{0, 1, 2, 3, -1, -2, -3, -4}; + eve::wide wu0{0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u}; + + std::cout << "<- wf0 = " << wf0 << "\n"; + + std::cout << "-> is_eqmz(wf0) = " << eve::is_eqmz(wf0) << "\n"; + std::cout << "-> is_eqmz[ignore_last(2)](wf0) = " << eve::is_eqmz[eve::ignore_last(2)](wf0) << "\n"; + std::cout << "-> is_eqmz[wf0 != 0](wf0) = " << eve::is_eqmz[wf0 != 0](wf0) << "\n"; +} diff --git a/test/random/module/core/is_eqpz.hpp b/test/random/module/core/is_eqmz.cpp similarity index 75% rename from test/random/module/core/is_eqpz.hpp rename to test/random/module/core/is_eqmz.cpp index 55f9a47d27..6b384bff4a 100644 --- a/test/random/module/core/is_eqpz.hpp +++ b/test/random/module/core/is_eqmz.cpp @@ -10,12 +10,12 @@ #include -TTS_CASE_TPL("Random check for eve::is_eqz", eve::test::simd::ieee_reals) +TTS_CASE_TPL("Random check for eve::is_eqmz", eve::test::simd::ieee_reals) (tts::type) { using e_t = eve::element_type_t; auto vmin = eve::valmin(eve::as()); auto vmax = eve::valmax(eve::as()); - auto std_is_eqz = [](auto e) -> eve::logical{ return e == 0 && eve::is_positive(e); }; - EVE_ULP_RANGE_CHECK( T, eve::uniform_prng(vmin, vmax), std_is_eqz, eve::is_eqz ); + auto std_is_eqmz = [](auto e) -> eve::logical{ return e == 0 && eve::is_negative(e); }; + EVE_ULP_RANGE_CHECK( T, eve::uniform_prng(vmin, vmax), std_is_eqmz, eve::is_eqmz ); }; diff --git a/test/unit/module/core/is_eqmz.cpp b/test/unit/module/core/is_eqmz.cpp new file mode 100644 index 0000000000..8939a1d4d8 --- /dev/null +++ b/test/unit/module/core/is_eqmz.cpp @@ -0,0 +1,38 @@ +//================================================================================================== +/** + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#include "test.hpp" + +#include + +//================================================================================================== +// Types tests +//================================================================================================== +TTS_CASE_TPL("Check return types of eve::is_eqmz(simd)", eve::test::simd::ieee_reals) +(tts::type) +{ + using eve::logical; + using v_t = eve::element_type_t; + TTS_EXPR_IS(eve::is_eqmz(T()), logical); + TTS_EXPR_IS(eve::is_eqmz(v_t()), logical); +}; + +//================================================================================================== +// Tests for eve::is_eqmz +//================================================================================================== + +TTS_CASE_WITH("Check behavior of eve::is_eqmz(simd)", + eve::test::simd::ieee_reals, + tts::generate(tts::ramp(0), tts::logicals(0, 3))) +(T const& a0, M const& t) +{ + using eve::detail::map; + using v_t = eve::element_type_t; + + TTS_EQUAL(eve::is_eqmz(a0), map([](auto e) -> eve::logical { return e == 0 && eve::is_negative(e); }, a0)); + TTS_EQUAL(eve::is_eqmz[t](a0), eve::if_else(t, eve::is_eqmz(a0), eve::false_(eve::as(a0)))); +}; From a26b628e1abadf91139bd5da1aa542af5e0a9ac1 Mon Sep 17 00:00:00 2001 From: jtlap Date: Sun, 1 Sep 2024 17:50:26 +0200 Subject: [PATCH 06/25] typos in is_eqz --- include/eve/module/core/regular/impl/simd/x86/is_eqz.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/eve/module/core/regular/impl/simd/x86/is_eqz.hpp b/include/eve/module/core/regular/impl/simd/x86/is_eqz.hpp index a568301cff..53b79046a0 100644 --- a/include/eve/module/core/regular/impl/simd/x86/is_eqz.hpp +++ b/include/eve/module/core/regular/impl/simd/x86/is_eqz.hpp @@ -16,7 +16,7 @@ namespace eve::detail // Generate better code on x86 than just comparing to 0 template EVE_FORCEINLINE constexpr auto - is_ltz_(EVE_REQUIRES(sse2_), O const &, wide const& v) noexcept + is_eqz_(EVE_REQUIRES(sse2_), O const &, wide const& v) noexcept requires(sizeof(T) < 8 && x86_abi> && abi_t::is_wide_logical) { using l_t = as_logical_t>; @@ -25,7 +25,7 @@ namespace eve::detail } template - EVE_FORCEINLINE logical> is_ltz_(EVE_REQUIRES(avx512_), + EVE_FORCEINLINE logical> is_eqz_(EVE_REQUIRES(avx512_), O const &, wide const &a) noexcept requires x86_abi> @@ -48,7 +48,7 @@ namespace eve::detail // ----------------------------------------------------------------------------------------------- // masked implementation template - EVE_FORCEINLINE auto is_ltz_(EVE_REQUIRES(avx512_), + EVE_FORCEINLINE auto is_eqz_(EVE_REQUIRES(avx512_), C const& cx, O const& o, wide const& v) noexcept From b62aec22e8a24c73105fe7c9510a85cc014ee3ff Mon Sep 17 00:00:00 2001 From: jtlap Date: Sun, 1 Sep 2024 21:08:18 +0200 Subject: [PATCH 07/25] is_eqz --- .../eve/module/core/regular/impl/simd/x86/is_eqz.hpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/include/eve/module/core/regular/impl/simd/x86/is_eqz.hpp b/include/eve/module/core/regular/impl/simd/x86/is_eqz.hpp index 53b79046a0..236c0b4e9d 100644 --- a/include/eve/module/core/regular/impl/simd/x86/is_eqz.hpp +++ b/include/eve/module/core/regular/impl/simd/x86/is_eqz.hpp @@ -13,16 +13,6 @@ namespace eve::detail { - // Generate better code on x86 than just comparing to 0 - template - EVE_FORCEINLINE constexpr auto - is_eqz_(EVE_REQUIRES(sse2_), O const &, wide const& v) noexcept - requires(sizeof(T) < 8 && x86_abi> && abi_t::is_wide_logical) - { - using l_t = as_logical_t>; - constexpr auto shift = 8 * sizeof(T) - 1; - return bit_cast(v >> shift, as {}); - } template EVE_FORCEINLINE logical> is_eqz_(EVE_REQUIRES(avx512_), From 897f03f999b307ca7dba00ce35b64692823e0ae3 Mon Sep 17 00:00:00 2001 From: jtlap Date: Mon, 2 Sep 2024 08:58:01 +0200 Subject: [PATCH 08/25] is_finite --- .../core/regular/impl/simd/x86/is_finite.hpp | 36 +++++++++++++++++++ include/eve/module/core/regular/is_finite.hpp | 4 +++ test/random/module/core/is_finite.cpp | 25 +++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_finite.hpp create mode 100644 test/random/module/core/is_finite.cpp diff --git a/include/eve/module/core/regular/impl/simd/x86/is_finite.hpp b/include/eve/module/core/regular/impl/simd/x86/is_finite.hpp new file mode 100644 index 0000000000..d171961b2c --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_finite.hpp @@ -0,0 +1,36 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace eve::detail +{ + template + EVE_FORCEINLINE logical> is_finite_(EVE_REQUIRES(avx512_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = fpclass::qnan | fpclass::snan | fpclass::neginf | fpclass::posinf; + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return ~s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return ~s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return ~s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16) return ~s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return ~s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return ~s_t {_mm_fpclass_ps_mask(a, f)}; + } +} diff --git a/include/eve/module/core/regular/is_finite.hpp b/include/eve/module/core/regular/is_finite.hpp index c61b76fc7d..2aa203affe 100644 --- a/include/eve/module/core/regular/is_finite.hpp +++ b/include/eve/module/core/regular/is_finite.hpp @@ -88,3 +88,7 @@ namespace eve } } } + +#if defined(EVE_INCLUDE_X86_HEADER) +# include +#endif diff --git a/test/random/module/core/is_finite.cpp b/test/random/module/core/is_finite.cpp new file mode 100644 index 0000000000..aadb7f26b1 --- /dev/null +++ b/test/random/module/core/is_finite.cpp @@ -0,0 +1,25 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include +#include "producers.hpp" + +#include + +TTS_CASE_TPL("Random check for eve::is_finite", eve::test::simd::all_types) +(tts::type) +{ + using e_t = eve::element_type_t; + auto vmin = eve::valmin(eve::as()); + auto vmax = eve::valmax(eve::as()); + auto std_is_finite = [](auto e) -> eve::logical { + if constexpr(eve::floating_value) + return std::isfinite(e); + else return eve::true_(eve::as(e)); + }; + EVE_ULP_RANGE_CHECK( T, eve::uniform_prng(vmin, vmax), std_is_finite, eve::is_finite ); +}; From 82eb7d0b42a325e1188a4c0bef91fff3a57f81fc Mon Sep 17 00:00:00 2001 From: jtlap Date: Mon, 2 Sep 2024 09:04:45 +0200 Subject: [PATCH 09/25] is_gez --- .../core/regular/impl/simd/x86/is_gez.hpp | 46 +++++++++++++++++++ include/eve/module/core/regular/is_gez.hpp | 4 ++ 2 files changed, 50 insertions(+) create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_gez.hpp diff --git a/include/eve/module/core/regular/impl/simd/x86/is_gez.hpp b/include/eve/module/core/regular/impl/simd/x86/is_gez.hpp new file mode 100644 index 0000000000..fb14824279 --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_gez.hpp @@ -0,0 +1,46 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace eve::detail +{ + // Generate better code on x86 than just comparing to 0 + template + EVE_FORCEINLINE constexpr auto + is_gez_(EVE_REQUIRES(sse2_), O const &, wide const& v) noexcept + requires(sizeof(T) < 8 && x86_abi> && abi_t::is_wide_logical) + { + using l_t = as_logical_t>; + constexpr auto shift = 8 * sizeof(T) - 1; + return bit_cast(v >> shift, as {}); + } + + template + EVE_FORCEINLINE logical> is_gez_(EVE_REQUIRES(avx512_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = fpclass::neg | fpclass::qnan | fpclass::snan; + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return ~s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return ~s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return ~s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16) return ~s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return ~s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return ~s_t {_mm_fpclass_ps_mask(a, f)}; + } +} diff --git a/include/eve/module/core/regular/is_gez.hpp b/include/eve/module/core/regular/is_gez.hpp index 9bf27c332e..ec4feaa68e 100644 --- a/include/eve/module/core/regular/is_gez.hpp +++ b/include/eve/module/core/regular/is_gez.hpp @@ -86,3 +86,7 @@ namespace eve } } } + +#if defined(EVE_INCLUDE_X86_HEADER) +# include +#endif From 97d3705d932133f26474173354913c87435db2f1 Mon Sep 17 00:00:00 2001 From: jtlap Date: Mon, 2 Sep 2024 11:13:59 +0200 Subject: [PATCH 10/25] is_gez x86 --- .../eve/module/core/regular/impl/simd/x86/is_gez.hpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/include/eve/module/core/regular/impl/simd/x86/is_gez.hpp b/include/eve/module/core/regular/impl/simd/x86/is_gez.hpp index fb14824279..a8c2de0d07 100644 --- a/include/eve/module/core/regular/impl/simd/x86/is_gez.hpp +++ b/include/eve/module/core/regular/impl/simd/x86/is_gez.hpp @@ -13,16 +13,6 @@ namespace eve::detail { - // Generate better code on x86 than just comparing to 0 - template - EVE_FORCEINLINE constexpr auto - is_gez_(EVE_REQUIRES(sse2_), O const &, wide const& v) noexcept - requires(sizeof(T) < 8 && x86_abi> && abi_t::is_wide_logical) - { - using l_t = as_logical_t>; - constexpr auto shift = 8 * sizeof(T) - 1; - return bit_cast(v >> shift, as {}); - } template EVE_FORCEINLINE logical> is_gez_(EVE_REQUIRES(avx512_), From 795e71b70eb789e9440acdb95db463aeed6a568d Mon Sep 17 00:00:00 2001 From: jtlap Date: Mon, 2 Sep 2024 11:30:40 +0200 Subject: [PATCH 11/25] is_gtz --- .../core/regular/impl/simd/x86/is_gtz.hpp | 46 +++++++++++++++++++ include/eve/module/core/regular/is_gtz.hpp | 4 ++ test/random/module/core/is_gtz.cpp | 6 +-- 3 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_gtz.hpp diff --git a/include/eve/module/core/regular/impl/simd/x86/is_gtz.hpp b/include/eve/module/core/regular/impl/simd/x86/is_gtz.hpp new file mode 100644 index 0000000000..66a633790a --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_gtz.hpp @@ -0,0 +1,46 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace eve::detail +{ + // Generate better code on x86 than just comparing to 0 + template + EVE_FORCEINLINE constexpr auto + is_gtz_(EVE_REQUIRES(sse2_), O const &, wide const& v) noexcept + requires(sizeof(T) < 8 && x86_abi> && abi_t::is_wide_logical) + { + using l_t = as_logical_t>; + constexpr auto shift = 8 * sizeof(T) - 1; + return bit_cast(v >> shift, as {}); + } + + template + EVE_FORCEINLINE logical> is_gtz_(EVE_REQUIRES(avx512_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = fpclass::neg | fpclass::negzero | fpclass::poszero | fpclass::qnan | fpclass::snan; + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return ~s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return ~s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return ~s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16) return ~s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return ~s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return ~s_t {_mm_fpclass_ps_mask(a, f)}; + } +} diff --git a/include/eve/module/core/regular/is_gtz.hpp b/include/eve/module/core/regular/is_gtz.hpp index 1ea518e863..8212ffe20a 100644 --- a/include/eve/module/core/regular/is_gtz.hpp +++ b/include/eve/module/core/regular/is_gtz.hpp @@ -88,3 +88,7 @@ namespace eve } } } + +#if defined(EVE_INCLUDE_X86_HEADER) +# include +#endif diff --git a/test/random/module/core/is_gtz.cpp b/test/random/module/core/is_gtz.cpp index d186197e07..f33fb96f9b 100644 --- a/test/random/module/core/is_gtz.cpp +++ b/test/random/module/core/is_gtz.cpp @@ -10,12 +10,12 @@ #include -TTS_CASE_TPL("Random check for eve::is_ltz", eve::test::simd::all_types) +TTS_CASE_TPL("Random check for eve::is_gtz", eve::test::simd::all_types) (tts::type) { using e_t = eve::element_type_t; auto vmin = eve::valmin(eve::as()); auto vmax = eve::valmax(eve::as()); - auto std_is_ltz = [](auto e) -> eve::logical{ return e < 0; }; - EVE_ULP_RANGE_CHECK( T, eve::uniform_prng(vmin, vmax), std_is_ltz, eve::is_ltz ); + auto std_is_gtz = [](auto e) -> eve::logical{ return e > 0; }; + EVE_ULP_RANGE_CHECK( T, eve::uniform_prng(vmin, vmax), std_is_gtz, eve::is_gtz ); }; From 249242bf0a32b91929d56d1a3f9066b2efcf7cfd Mon Sep 17 00:00:00 2001 From: jtlap Date: Mon, 2 Sep 2024 11:45:17 +0200 Subject: [PATCH 12/25] is_gtz --- .../eve/module/core/regular/impl/simd/x86/is_gtz.hpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/include/eve/module/core/regular/impl/simd/x86/is_gtz.hpp b/include/eve/module/core/regular/impl/simd/x86/is_gtz.hpp index 66a633790a..cc43da0346 100644 --- a/include/eve/module/core/regular/impl/simd/x86/is_gtz.hpp +++ b/include/eve/module/core/regular/impl/simd/x86/is_gtz.hpp @@ -13,17 +13,6 @@ namespace eve::detail { - // Generate better code on x86 than just comparing to 0 - template - EVE_FORCEINLINE constexpr auto - is_gtz_(EVE_REQUIRES(sse2_), O const &, wide const& v) noexcept - requires(sizeof(T) < 8 && x86_abi> && abi_t::is_wide_logical) - { - using l_t = as_logical_t>; - constexpr auto shift = 8 * sizeof(T) - 1; - return bit_cast(v >> shift, as {}); - } - template EVE_FORCEINLINE logical> is_gtz_(EVE_REQUIRES(avx512_), O const &, From 97cd402c9ff24b63b4fb94c6ec74f25e56f8d18d Mon Sep 17 00:00:00 2001 From: jtlap Date: Mon, 2 Sep 2024 11:35:14 +0200 Subject: [PATCH 13/25] is_infinite --- .../regular/impl/simd/x86/is_infinite.hpp | 66 +++++++++++++++++++ .../eve/module/core/regular/is_infinite.hpp | 4 ++ 2 files changed, 70 insertions(+) create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_infinite.hpp diff --git a/include/eve/module/core/regular/impl/simd/x86/is_infinite.hpp b/include/eve/module/core/regular/impl/simd/x86/is_infinite.hpp new file mode 100644 index 0000000000..8f55bdb7d9 --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_infinite.hpp @@ -0,0 +1,66 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace eve::detail +{ + template + EVE_FORCEINLINE logical> is_infinite_(EVE_REQUIRES(avx512_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = fpclass::neginf|fpclass::posinf; + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16 )return s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return s_t {_mm_fpclass_ps_mask(a, f)}; + + } + +// ----------------------------------------------------------------------------------------------- +// masked implementation + template + EVE_FORCEINLINE auto is_infinite_(EVE_REQUIRES(avx512_), + C const& cx, + O const& o, + wide const& v) noexcept + requires x86_abi> + { + constexpr auto c = categorize>(); + + if constexpr( C::has_alternative || C::is_complete || abi_t::is_wide_logical ) + { + return is_infinite.behavior(cpu_{}, o, v, v); + } + else + { + auto m = expand_mask(cx, as> {}).storage().value; + constexpr auto f = fpclass::neginf|fpclass::posinf; + + if constexpr( c == category::float32x16 ) return mask16 {_mm512_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x8 ) return mask8 {_mm512_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x8 ) return mask8 {_mm256_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x4 ) return mask8 {_mm256_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x4 ) return mask8 {_mm_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x2 ) return mask8 {_mm_mask_fpclass_pd_mask(m, v, f)}; + } + } +} diff --git a/include/eve/module/core/regular/is_infinite.hpp b/include/eve/module/core/regular/is_infinite.hpp index bdfcbf45fa..ffc99a73f9 100644 --- a/include/eve/module/core/regular/is_infinite.hpp +++ b/include/eve/module/core/regular/is_infinite.hpp @@ -88,3 +88,7 @@ namespace eve } } } + +#if defined(EVE_INCLUDE_X86_HEADER) +# include +#endif From 62ac2949507d32d03f9525fc13a2f656bd135d3e Mon Sep 17 00:00:00 2001 From: jtlap Date: Mon, 2 Sep 2024 13:37:04 +0200 Subject: [PATCH 14/25] is_gtz --- .../core/regular/impl/simd/x86/is_gtz.hpp | 6 +++--- test/doc/math/pow.cpp | 17 +++++++++-------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/eve/module/core/regular/impl/simd/x86/is_gtz.hpp b/include/eve/module/core/regular/impl/simd/x86/is_gtz.hpp index cc43da0346..254128b674 100644 --- a/include/eve/module/core/regular/impl/simd/x86/is_gtz.hpp +++ b/include/eve/module/core/regular/impl/simd/x86/is_gtz.hpp @@ -21,7 +21,7 @@ namespace eve::detail { using l_t = logical>; constexpr auto c = categorize>(); - constexpr auto f = fpclass::neg | fpclass::negzero | fpclass::poszero | fpclass::qnan | fpclass::snan; + constexpr auto f = fpclass::neg | fpclass::negzero | fpclass::poszero | fpclass::neginf | fpclass::qnan | fpclass::snan; using s_t = typename l_t::storage_type; @@ -30,6 +30,6 @@ namespace eve::detail else if constexpr( c == category::float64x2 ) return ~s_t {_mm_fpclass_pd_mask(a, f)}; else if constexpr( c == category::float32x16) return ~s_t {_mm512_fpclass_ps_mask(a, f)}; else if constexpr( c == category::float32x8 ) return ~s_t {_mm256_fpclass_ps_mask(a, f)}; - else if constexpr( c == category::float32x4 ) return ~s_t {_mm_fpclass_ps_mask(a, f)}; - } + else if constexpr( c == category::float32x4 ) return ~s_t {_mm_fpclass_ps_mask(a, f)}; + } } diff --git a/test/doc/math/pow.cpp b/test/doc/math/pow.cpp index de0f6bec5b..70b247ca5a 100644 --- a/test/doc/math/pow.cpp +++ b/test/doc/math/pow.cpp @@ -1,18 +1,19 @@ // revision 1 #include #include +#include int main() { - eve::wide pf = {2.0f, 3.0f, -4.0f, 2.0f, 2.0f, + eve::wide qf = {0.0f, 3.0f, -4.0f, 2.0f, 2.0f, eve::inf(eve::as()), eve::minf(eve::as()), eve::nan(eve::as())}; - eve::wide qf = {4.0f, 1.0f, -1.0f, 0.5f, 0.0f, 2.0f, -3.0f, 2.5f}; + eve::wide pf = {4.0f, 1.0f, -1.0f, 0.5f, 0.0f, 0.0f, -0.0f, 2.5f}; - std::cout << "<- pf = " << pf << "\n"; - std::cout << "<- qf = " << qf << "\n"; + std::cout << "<- pf = " << pf << "\n"; + std::cout << "<- qf = " << qf << "\n"; - std::cout << "-> pow(pf, qf) = " << eve::pow(pf, qf) << "\n"; - std::cout << "-> pow[ignore_last(2)](pf, qf)= " << eve::pow[eve::ignore_last(2)](pf, qf) << "\n"; - std::cout << "-> pow[qf > 0.0f](pf, qf) = " << eve::pow[qf > 0.0f](pf, qf) << "\n"; - std::cout << "-> pow[raw](pf, qf) = " << eve::pow[eve::raw](pf, qf) << "\n"; + std::cout << "-> pow(pf, qf) = " << eve::pow(pf, qf) << "\n"; + std::cout << "-> pow[ignore_last(2)](pf, qf)= " << eve::pow[eve::ignore_last(2)](pf, qf) << "\n"; + std::cout << "-> pow[qf > 0.0f](pf, qf) = " << eve::pow[qf > 0.0f](pf, qf) << "\n"; + std::cout << "-> pow[raw](pf, qf) = " << eve::pow[eve::raw](pf, qf) << "\n"; } From 5095c29103539bc603be253177beee0944e86b43 Mon Sep 17 00:00:00 2001 From: jtlap Date: Mon, 2 Sep 2024 15:49:08 +0200 Subject: [PATCH 15/25] is_gez, is_ltz is_lez --- .../core/regular/impl/simd/x86/is_gez.hpp | 2 +- .../core/regular/impl/simd/x86/is_lez.hpp | 66 +++++++++++++++++++ .../core/regular/impl/simd/x86/is_ltz.hpp | 50 ++++++++++++++ test/doc/core/is_gez.cpp | 4 +- 4 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_lez.hpp diff --git a/include/eve/module/core/regular/impl/simd/x86/is_gez.hpp b/include/eve/module/core/regular/impl/simd/x86/is_gez.hpp index a8c2de0d07..8585c1e464 100644 --- a/include/eve/module/core/regular/impl/simd/x86/is_gez.hpp +++ b/include/eve/module/core/regular/impl/simd/x86/is_gez.hpp @@ -22,7 +22,7 @@ namespace eve::detail { using l_t = logical>; constexpr auto c = categorize>(); - constexpr auto f = fpclass::neg | fpclass::qnan | fpclass::snan; + constexpr auto f = fpclass::neg | fpclass::qnan| fpclass::neginf | fpclass::snan; using s_t = typename l_t::storage_type; diff --git a/include/eve/module/core/regular/impl/simd/x86/is_lez.hpp b/include/eve/module/core/regular/impl/simd/x86/is_lez.hpp new file mode 100644 index 0000000000..fb6781ecd4 --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_lez.hpp @@ -0,0 +1,66 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace eve::detail +{ + template + EVE_FORCEINLINE logical> is_lez_(EVE_REQUIRES(avx512_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = fpclass::neg | fpclass::negzero | fpclass::poszero | fpclass::neginf; + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16) return s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return s_t {_mm_fpclass_ps_mask(a, f)}; + } + + +// ----------------------------------------------------------------------------------------------- +// masked implementation + template + EVE_FORCEINLINE auto is_lez_(EVE_REQUIRES(avx512_), + C const& cx, + O const& o, + wide const& v) noexcept + requires x86_abi> + { + constexpr auto c = categorize>(); + + if constexpr( C::has_alternative || C::is_complete || abi_t::is_wide_logical ) + { + return is_lez.behavior(cpu_{}, o, v, v); + } + else + { + auto m = expand_mask(cx, as> {}).storage().value; + constexpr auto f = fpclass::neg | fpclass::negzero | fpclass::poszero | fpclass::neginf; + + + if constexpr( c == category::float32x16 ) return mask16 {_mm512_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x8 ) return mask8 {_mm512_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x8 ) return mask8 {_mm256_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x4 ) return mask8 {_mm256_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x4 ) return mask8 {_mm_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x2 ) return mask8 {_mm_mask_fpclass_pd_mask(m, v, f)}; + } + } +} diff --git a/include/eve/module/core/regular/impl/simd/x86/is_ltz.hpp b/include/eve/module/core/regular/impl/simd/x86/is_ltz.hpp index acbf7a0f21..be89d49e34 100644 --- a/include/eve/module/core/regular/impl/simd/x86/is_ltz.hpp +++ b/include/eve/module/core/regular/impl/simd/x86/is_ltz.hpp @@ -23,4 +23,54 @@ namespace eve::detail constexpr auto shift = 8 * sizeof(T) - 1; return bit_cast(v >> shift, as {}); } + + template + EVE_FORCEINLINE logical> is_ltz_(EVE_REQUIRES(avx512_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = fpclass::neg | fpclass::neginf; + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16) return s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return s_t {_mm_fpclass_ps_mask(a, f)}; + } + + +// ----------------------------------------------------------------------------------------------- +// masked implementation + template + EVE_FORCEINLINE auto is_ltz_(EVE_REQUIRES(avx512_), + C const& cx, + O const& o, + wide const& v) noexcept + requires x86_abi> + { + constexpr auto c = categorize>(); + + if constexpr( C::has_alternative || C::is_complete || abi_t::is_wide_logical ) + { + return is_ltz.behavior(cpu_{}, o, v, v); + } + else + { + auto m = expand_mask(cx, as> {}).storage().value; + constexpr auto f = fpclass::neg | fpclass::neginf; + + if constexpr( c == category::float32x16 ) return mask16 {_mm512_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x8 ) return mask8 {_mm512_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x8 ) return mask8 {_mm256_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x4 ) return mask8 {_mm256_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x4 ) return mask8 {_mm_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x2 ) return mask8 {_mm_mask_fpclass_pd_mask(m, v, f)}; + } + } } diff --git a/test/doc/core/is_gez.cpp b/test/doc/core/is_gez.cpp index e120b48944..33290ddc5c 100644 --- a/test/doc/core/is_gez.cpp +++ b/test/doc/core/is_gez.cpp @@ -4,14 +4,14 @@ int main() { - eve::wide wf0{0.0, 1.0, 2.0, 3.0, -1.0, -2.0, -3.0, -4.0}; + eve::wide wf0{0.0, 1.0, 2.0, 3.0, -1.0, -2.0, -3.0, eve::minf(eve::as())}; eve::wide wi0{0, 1, 2, 3, -1, -2, -3, -4}; eve::wide wu0{0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u}; std::cout << "<- wf0 = " << wf0 << "\n"; std::cout << "<- wi0 = " << wi0 << "\n"; std::cout << "<- wu0 = " << wu0 << "\n"; - + std::cout << "-> is_gez(wf0) = " << eve::is_gez(wf0) << "\n"; std::cout << "-> is_gez[ignore_last(2)](wf0) = " << eve::is_gez[eve::ignore_last(2)](wf0) << "\n"; std::cout << "-> is_gez[wf0 != 0](wf0) = " << eve::is_gez[wf0 != 0](wf0) << "\n"; From d6861a1dec503e3f2e8e303d34f36280f4b2408f Mon Sep 17 00:00:00 2001 From: jtlap Date: Mon, 2 Sep 2024 17:03:42 +0200 Subject: [PATCH 16/25] is_gez, is_ngtz is_ngez is_minf --- include/eve/module/core/regular/core.hpp | 1 + .../core/regular/impl/simd/x86/is_minf.hpp | 66 +++++++++++++ .../core/regular/impl/simd/x86/is_ngez.hpp | 65 +++++++++++++ .../core/regular/impl/simd/x86/is_ngtz.hpp | 65 +++++++++++++ include/eve/module/core/regular/is_minf.hpp | 94 +++++++++++++++++++ include/eve/module/core/regular/is_ngez.hpp | 4 + test/doc/core/is_minf.cpp | 24 +++++ test/random/module/core/is_minf.cpp | 21 +++++ test/unit/module/core/is_minf.cpp | 69 ++++++++++++++ 9 files changed, 409 insertions(+) create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_minf.hpp create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_ngez.hpp create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_ngtz.hpp create mode 100644 include/eve/module/core/regular/is_minf.hpp create mode 100644 test/doc/core/is_minf.cpp create mode 100644 test/random/module/core/is_minf.cpp create mode 100644 test/unit/module/core/is_minf.cpp diff --git a/include/eve/module/core/regular/core.hpp b/include/eve/module/core/regular/core.hpp index e161ce6ddb..8349471403 100644 --- a/include/eve/module/core/regular/core.hpp +++ b/include/eve/module/core/regular/core.hpp @@ -107,6 +107,7 @@ #include #include #include +#include #include #include #include diff --git a/include/eve/module/core/regular/impl/simd/x86/is_minf.hpp b/include/eve/module/core/regular/impl/simd/x86/is_minf.hpp new file mode 100644 index 0000000000..c5160b74bd --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_minf.hpp @@ -0,0 +1,66 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace eve::detail +{ + template + EVE_FORCEINLINE logical> is_minf_(EVE_REQUIRES(avx512_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = fpclass::neginf; + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16 )return s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return s_t {_mm_fpclass_ps_mask(a, f)}; + + } + +// ----------------------------------------------------------------------------------------------- +// masked implementation + template + EVE_FORCEINLINE auto is_minf_(EVE_REQUIRES(avx512_), + C const& cx, + O const& o, + wide const& v) noexcept + requires x86_abi> + { + constexpr auto c = categorize>(); + + if constexpr( C::has_alternative || C::is_complete || abi_t::is_wide_logical ) + { + return is_minf.behavior(cpu_{}, o, v, v); + } + else + { + auto m = expand_mask(cx, as> {}).storage().value; + constexpr auto f = fpclass::neginf; + + if constexpr( c == category::float32x16 ) return mask16 {_mm512_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x8 ) return mask8 {_mm512_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x8 ) return mask8 {_mm256_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x4 ) return mask8 {_mm256_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x4 ) return mask8 {_mm_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x2 ) return mask8 {_mm_mask_fpclass_pd_mask(m, v, f)}; + } + } +} diff --git a/include/eve/module/core/regular/impl/simd/x86/is_ngez.hpp b/include/eve/module/core/regular/impl/simd/x86/is_ngez.hpp new file mode 100644 index 0000000000..b86bc53433 --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_ngez.hpp @@ -0,0 +1,65 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace eve::detail +{ + template + EVE_FORCEINLINE logical> is_ngez_(EVE_REQUIRES(avx512_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = fpclass::neg | fpclass::neginf | fpclass::qnan | fpclass::snan; + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16) return s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return s_t {_mm_fpclass_ps_mask(a, f)}; + } + + +// ----------------------------------------------------------------------------------------------- +// masked implementation + template + EVE_FORCEINLINE auto is_ngez_(EVE_REQUIRES(avx512_), + C const& cx, + O const& o, + wide const& v) noexcept + requires x86_abi> + { + constexpr auto c = categorize>(); + + if constexpr( C::has_alternative || C::is_complete || abi_t::is_wide_logical ) + { + return is_ngez.behavior(cpu_{}, o, v, v); + } + else + { + auto m = expand_mask(cx, as> {}).storage().value; + constexpr auto f = fpclass::neg | fpclass::neginf | fpclass::qnan | fpclass::snan; + + if constexpr( c == category::float32x16 ) return mask16 {_mm512_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x8 ) return mask8 {_mm512_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x8 ) return mask8 {_mm256_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x4 ) return mask8 {_mm256_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x4 ) return mask8 {_mm_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x2 ) return mask8 {_mm_mask_fpclass_pd_mask(m, v, f)}; + } + } +} diff --git a/include/eve/module/core/regular/impl/simd/x86/is_ngtz.hpp b/include/eve/module/core/regular/impl/simd/x86/is_ngtz.hpp new file mode 100644 index 0000000000..49e756d416 --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_ngtz.hpp @@ -0,0 +1,65 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace eve::detail +{ + template + EVE_FORCEINLINE logical> is_ngtz_(EVE_REQUIRES(avx512_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = fpclass::neg | fpclass::neginf | fpclass::qnan | fpclass::snan | fpclass::poszero | fpclass::negzero; + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16) return s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return s_t {_mm_fpclass_ps_mask(a, f)}; + } + + +// ----------------------------------------------------------------------------------------------- +// masked implementation + template + EVE_FORCEINLINE auto is_ngtz_(EVE_REQUIRES(avx512_), + C const& cx, + O const& o, + wide const& v) noexcept + requires x86_abi> + { + constexpr auto c = categorize>(); + + if constexpr( C::has_alternative || C::is_complete || abi_t::is_wide_logical ) + { + return is_ngtz.behavior(cpu_{}, o, v, v); + } + else + { + auto m = expand_mask(cx, as> {}).storage().value; + constexpr auto f = fpclass::neg | fpclass::neginf | fpclass::qnan | fpclass::snan | fpclass::poszero | fpclass::negzero; + + if constexpr( c == category::float32x16 ) return mask16 {_mm512_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x8 ) return mask8 {_mm512_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x8 ) return mask8 {_mm256_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x4 ) return mask8 {_mm256_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x4 ) return mask8 {_mm_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x2 ) return mask8 {_mm_mask_fpclass_pd_mask(m, v, f)}; + } + } +} diff --git a/include/eve/module/core/regular/is_minf.hpp b/include/eve/module/core/regular/is_minf.hpp new file mode 100644 index 0000000000..8bb57af6c4 --- /dev/null +++ b/include/eve/module/core/regular/is_minf.hpp @@ -0,0 +1,94 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace eve +{ + template + struct is_minf_t : elementwise_callable + { + template + EVE_FORCEINLINE constexpr as_logical_t + operator()(T t) const noexcept + { + return EVE_DISPATCH_CALL(t); + } + + EVE_CALLABLE_OBJECT(is_minf_t, is_minf_); + }; + +//================================================================================================ +//! @addtogroup core_predicates +//! @{ +//! @var is_minf +//! @brief `elementwise callable` returning a logical true if and only if the element is a negative infinite value +//! +//! @groupheader{Header file} +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace eve +//! { +//! // Regular overload +//! constexpr auto is_minf(value auto x) noexcept; // 1 +//! +//! // Lanes masking +//! constexpr auto is_minf[conditional_expr auto c](value auto x) noexcept; // 2 +//! constexpr auto is_minf[logical_value auto m](value auto x) noexcept; // 2 +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `x`: [argument](@ref eve::value). +//! * `c`: [Conditional expression](@ref conditional_expr) masking the operation. +//! * `m`: [Logical value](@ref logical) masking the operation. +//! +//! **Return value** +//! +//! 1. For floating entries returns true if x is equals to `eve::minf(as(x))`, +//! and is always false for integral types. +//! 2. [The operation is performed conditionnaly](@ref conditional). +//! +//! @groupheader{Example} +//! @godbolt{doc/core/is_minf.cpp} +//================================================================================================ + inline constexpr auto is_minf = functor; +//================================================================================================ +//! @} +//================================================================================================ + + namespace detail + { + template + EVE_FORCEINLINE constexpr as_logical_t + is_minf_(EVE_REQUIRES(cpu_), O const &, T const& a) noexcept + { + if constexpr( integral_value ) + return false_(eve::as(a)); + else + return (a == minf(eve::as(a))); + } + } +} + +#if defined(EVE_INCLUDE_X86_HEADER) +# include +#endif diff --git a/include/eve/module/core/regular/is_ngez.hpp b/include/eve/module/core/regular/is_ngez.hpp index 2fe56a1391..920bee5c03 100644 --- a/include/eve/module/core/regular/is_ngez.hpp +++ b/include/eve/module/core/regular/is_ngez.hpp @@ -95,3 +95,7 @@ namespace eve } } } + +#if defined(EVE_INCLUDE_X86_HEADER) +# include +#endif diff --git a/test/doc/core/is_minf.cpp b/test/doc/core/is_minf.cpp new file mode 100644 index 0000000000..494819b573 --- /dev/null +++ b/test/doc/core/is_minf.cpp @@ -0,0 +1,24 @@ +// revision 0 +#include +#include + +int main() +{ + eve::wide wf0{0.0, 1.0, 2.0, eve::minf(eve::as()), -1.0, -2.0, eve::inf(eve::as()), -0.0}; + eve::wide wi0{0, 1, 2, 3, -1, -2, -3, -4}; + eve::wide wu0{0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u}; + + std::cout << "<- wf0 = " << wf0 << "\n"; + std::cout << "<- wi0 = " << wi0 << "\n"; + std::cout << "<- wu0 = " << wu0 << "\n"; + + std::cout << "-> is_minf(wf0) = " << eve::is_minf(wf0) << "\n"; + std::cout << "-> is_minf[ignore_last(2)](wf0) = " << eve::is_minf[eve::ignore_last(2)](wf0) << "\n"; + std::cout << "-> is_minf[wf0 != 0](wf0) = " << eve::is_minf[wf0 != 0](wf0) << "\n"; + std::cout << "-> is_minf(wu0) = " << eve::is_minf(wu0) << "\n"; + std::cout << "-> is_minf[ignore_last(2)](wu0) = " << eve::is_minf[eve::ignore_last(2)](wu0) << "\n"; + std::cout << "-> is_minf[wu0 != 0](wu0) = " << eve::is_minf[wu0 != 0](wu0) << "\n"; + std::cout << "-> is_minf(wi0) = " << eve::is_minf(wi0) << "\n"; + std::cout << "-> is_minf[ignore_last(2)](wi0) = " << eve::is_minf[eve::ignore_last(2)](wi0) << "\n"; + std::cout << "-> is_minf[wi0 != 0](wi0) = " << eve::is_minf[wi0 != 0](wi0) << "\n"; +} diff --git a/test/random/module/core/is_minf.cpp b/test/random/module/core/is_minf.cpp new file mode 100644 index 0000000000..fd941e5cb9 --- /dev/null +++ b/test/random/module/core/is_minf.cpp @@ -0,0 +1,21 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include +#include "producers.hpp" + +#include + +TTS_CASE_TPL("Random check for eve::is_minf", eve::test::simd::all_types) +(tts::type) +{ + using e_t = eve::element_type_t; + auto vmin = eve::valmin(eve::as()); + auto vmax = eve::valmax(eve::as()); + auto std_is_minf = [](auto e) -> eve::logical{ return e < 0 && e-e != 0; }; + EVE_ULP_RANGE_CHECK( T, eve::uniform_prng(vmin, vmax), std_is_minf, eve::is_minf ); + }; diff --git a/test/unit/module/core/is_minf.cpp b/test/unit/module/core/is_minf.cpp new file mode 100644 index 0000000000..c553e91da2 --- /dev/null +++ b/test/unit/module/core/is_minf.cpp @@ -0,0 +1,69 @@ +//================================================================================================== +/** + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#include "test.hpp" + +#include + +//================================================================================================== +// Types tests +//================================================================================================== +TTS_CASE_TPL("Check return types of eve::is_minf(simd)", eve::test::simd::all_types) +(tts::type) +{ + using eve::logical; + using v_t = eve::element_type_t; + TTS_EXPR_IS(eve::is_minf(T()), logical); + TTS_EXPR_IS(eve::is_minf(v_t()), logical); +}; + +//================================================================================================== +// Tests for eve::is_minf +//================================================================================================== +TTS_CASE_WITH("Check behavior of eve::is_minf(simd) integrals", + eve::test::simd::integers, + tts::generate(tts::ramp(0), tts::logicals(0, 3))) +(T a0, M const& t) +{ + using eve::detail::map; + TTS_EQUAL(eve::is_minf(a0), eve::false_(eve::as(a0))); + TTS_EQUAL(eve::is_minf[t](a0), + eve::if_else(t, eve::is_minf(a0), eve::false_(eve::as(a0)))); +}; + +TTS_CASE_WITH("Check behavior of eve::is_minf(simd) IEEE", + eve::test::simd::ieee_reals, + tts::generate(tts::ramp(0), tts::logicals(0, 3))) +(T a0, M const& t) +{ + using eve::detail::map; + using v_t = eve::element_type_t; + a0 = eve::if_else(eve::is_eqz(a0), eve::inf(eve::as()), eve::zero); + TTS_EQUAL(eve::is_minf(a0), + map([](auto e) -> eve::logical { return e - e != 0 && e == e < 0; }, a0)); + TTS_EQUAL(eve::is_minf[t](a0), + eve::if_else(t, eve::is_minf(a0), eve::false_(eve::as(a0)))); +}; + +//================================================================================================== +// Test cases values +//================================================================================================== +TTS_CASE_TPL("Check corner-cases behavior of eve::is_minf on wide",eve::test::simd::ieee_reals) +(tts::type tgt) +{ + using eve::as; + + auto cases = tts::limits(tgt); + TTS_EQUAL(eve::is_minf(cases.nan), eve::false_(as())); + TTS_EQUAL(eve::is_minf(-cases.nan), eve::false_(as())); + TTS_EQUAL(eve::is_minf(cases.minf), eve::true_(as())); + TTS_EQUAL(eve::is_minf(cases.inf), eve::false_(as())); + TTS_EQUAL(eve::is_minf(cases.zero), eve::false_(as())); + TTS_EQUAL(eve::is_minf(cases.mzero), eve::false_(as())); + TTS_EQUAL(eve::is_minf(cases.valmin), eve::false_(as())); + TTS_EQUAL(eve::is_minf(cases.valmax), eve::false_(as())); +}; From e2b2a8f37e712902d5251302f09bf1aacd349ae2 Mon Sep 17 00:00:00 2001 From: jtlap Date: Mon, 2 Sep 2024 19:48:55 +0200 Subject: [PATCH 17/25] is_minf unit test typo --- test/unit/module/core/is_minf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/module/core/is_minf.cpp b/test/unit/module/core/is_minf.cpp index c553e91da2..e70e837dff 100644 --- a/test/unit/module/core/is_minf.cpp +++ b/test/unit/module/core/is_minf.cpp @@ -44,7 +44,7 @@ TTS_CASE_WITH("Check behavior of eve::is_minf(simd) IEEE", using v_t = eve::element_type_t; a0 = eve::if_else(eve::is_eqz(a0), eve::inf(eve::as()), eve::zero); TTS_EQUAL(eve::is_minf(a0), - map([](auto e) -> eve::logical { return e - e != 0 && e == e < 0; }, a0)); + map([](auto e) -> eve::logical { return e - e != 0 && e < 0; }, a0)); TTS_EQUAL(eve::is_minf[t](a0), eve::if_else(t, eve::is_minf(a0), eve::false_(eve::as(a0)))); }; From af5c71c5eacd0d5319042647e5163ac34d15bd67 Mon Sep 17 00:00:00 2001 From: jtlap Date: Tue, 3 Sep 2024 09:01:48 +0200 Subject: [PATCH 18/25] is_nan is_negative --- include/eve/module/core/regular/add.hpp | 2 + .../core/regular/impl/simd/x86/is_nan.hpp | 74 +++++++++++++++++++ .../regular/impl/simd/x86/is_negative.hpp | 70 ++++++++++++++++++ .../eve/module/core/regular/is_negative.hpp | 14 +++- test/doc/core/is_negative.cpp | 6 +- test/unit/module/core/is_negative.cpp | 2 + 6 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_nan.hpp create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_negative.hpp diff --git a/include/eve/module/core/regular/add.hpp b/include/eve/module/core/regular/add.hpp index f3962c94fe..e2e5d0b477 100644 --- a/include/eve/module/core/regular/add.hpp +++ b/include/eve/module/core/regular/add.hpp @@ -59,6 +59,8 @@ namespace eve //! //! // Semantic options //! constexpr auto add[saturated](/*any of the above overloads*/) noexcept; // 4 +//! 2. [The operation is performed conditionnaly](@ref conditional). +//! //! } //! @endcode //! diff --git a/include/eve/module/core/regular/impl/simd/x86/is_nan.hpp b/include/eve/module/core/regular/impl/simd/x86/is_nan.hpp new file mode 100644 index 0000000000..bbd005144c --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_nan.hpp @@ -0,0 +1,74 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace eve::detail +{ + template + EVE_FORCEINLINE logical> is_nan_(EVE_REQUIRES(sse2_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto m = _CMP_UNORD_Q; + + if constexpr( match(c, category::integer_) ) return false_(eve::as()); + else if constexpr( current_api >= eve::avx512 ) + { + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return s_t {_mm512_cmp_pd_mask(a, a, m)}; + else if constexpr( c == category::float64x4 ) return s_t {_mm256_cmp_pd_mask(a, a, m)}; + else if constexpr( c == category::float64x2 ) return s_t {_mm_cmp_pd_mask(a, a, m)}; + else if constexpr( c == category::float32x16 ) return s_t {_mm512_cmp_ps_mask(a, a, m)}; + else if constexpr( c == category::float32x8 ) return s_t {_mm256_cmp_ps_mask(a, a, m)}; + else if constexpr( c == category::float32x4 ) return s_t {_mm_cmp_ps_mask(a, a, m)}; + } + else if constexpr( c == category::float64x4 ) return l_t(_mm256_cmp_pd(a, a, m)); + else if constexpr( c == category::float64x2 ) return l_t(_mm_cmpunord_pd(a, a)); + else if constexpr( c == category::float32x8 ) return l_t(_mm256_cmp_ps(a, a, m)); + else if constexpr( c == category::float32x4 ) return l_t(_mm_cmpunord_ps(a, a)); + } + +// ----------------------------------------------------------------------------------------------- +// masked implementation + template + EVE_FORCEINLINE auto is_nan_(EVE_REQUIRES(avx512_), + C const& cx, + O const& o, + wide const& v) noexcept + -> decltype(is_not_less_equal(v, v)) + requires x86_abi> + { + constexpr auto c = categorize>(); + + if constexpr( C::has_alternative || C::is_complete || abi_t::is_wide_logical ) + { + return is_nan.behavior(cpu_{}, o, v, v); + } + else + { + auto m = expand_mask(cx, as> {}).storage().value; + constexpr auto f = to_integer(cmp_flt::unord_q); + + if constexpr( c == category::float32x16 ) return mask16 {_mm512_mask_cmp_ps_mask(m, v, v, f)}; + else if constexpr( c == category::float64x8 ) return mask8 {_mm512_mask_cmp_pd_mask(m, v, v, f)}; + else if constexpr( c == category::float32x8 ) return mask8 {_mm256_mask_cmp_ps_mask(m, v, v, f)}; + else if constexpr( c == category::float64x4 ) return mask8 {_mm256_mask_cmp_pd_mask(m, v, v, f)}; + else if constexpr( c == category::float32x4 ) return mask8 {_mm_mask_cmp_ps_mask(m, v, v, f)}; + else if constexpr( c == category::float64x2 ) return mask8 {_mm_mask_cmp_pd_mask(m, v, v, f)}; + } + } +} diff --git a/include/eve/module/core/regular/impl/simd/x86/is_negative.hpp b/include/eve/module/core/regular/impl/simd/x86/is_negative.hpp new file mode 100644 index 0000000000..9eba938f0a --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_negative.hpp @@ -0,0 +1,70 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace eve::detail +{ + template + EVE_FORCEINLINE logical> is_negative_(EVE_REQUIRES(avx512_), + O const & o, + wide const &a) noexcept + requires x86_abi> + { + if constexpr(O::contains(pedantic)) + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = fpclass::neg|fpclass::negzero|fpclass::neginf; + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16 )return s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return s_t {_mm_fpclass_ps_mask(a, f)}; + } + else + return is_negative.behavior(cpu_{}, o, a); + } + +// ----------------------------------------------------------------------------------------------- +// masked implementation + template + EVE_FORCEINLINE auto is_negative_(EVE_REQUIRES(avx512_), + C const& cx, + O const& o, + wide const& v) noexcept + requires x86_abi> + { + constexpr auto c = categorize>(); + + if constexpr( C::has_alternative || C::is_complete || abi_t::is_wide_logical || !O::contains(pedantic)) + { + return is_negative.behavior(cpu_{}, o, v); + } + else + { + auto m = expand_mask(cx, as> {}).storage().value; + constexpr auto f = fpclass::neg|fpclass::negzero|fpclass::neginf; + + if constexpr( c == category::float32x16 ) return mask16 {_mm512_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x8 ) return mask8 {_mm512_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x8 ) return mask8 {_mm256_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x4 ) return mask8 {_mm256_mask_fpclass_pd_mask(m, v, f)}; + else if constexpr( c == category::float32x4 ) return mask8 {_mm_mask_fpclass_ps_mask(m, v, f)}; + else if constexpr( c == category::float64x2 ) return mask8 {_mm_mask_fpclass_pd_mask(m, v, f)}; + } + } +} diff --git a/include/eve/module/core/regular/is_negative.hpp b/include/eve/module/core/regular/is_negative.hpp index 7d1678b806..a5cc726917 100644 --- a/include/eve/module/core/regular/is_negative.hpp +++ b/include/eve/module/core/regular/is_negative.hpp @@ -15,7 +15,7 @@ namespace eve { template - struct is_negative_t : elementwise_callable + struct is_negative_t : elementwise_callable { template EVE_FORCEINLINE constexpr as_logical_t @@ -51,6 +51,9 @@ namespace eve //! // Lanes masking //! constexpr auto is_negative[conditional_expr auto c](value auto x) noexcept; // 2 //! constexpr auto is_negative[logical_value auto m](value auto x) noexcept; // 2 +//! +//! // Semantic options +//! constexpr auto is_negative[pedantic](value auto x)noexcept; // 3 //! } //! @endcode //! @@ -65,6 +68,7 @@ namespace eve //! 1. For signed types The call `is_negative(x)` returns true //! if and only if the bit of sign (most significant bit) is set. //! 2. [The operation is performed conditionnaly](@ref conditional). +//! 3. with this otion a nan is never negative. //! //! @note //! this function coincides with `is_ltz` on [integral real values](@ref eve::value), @@ -88,6 +92,10 @@ namespace eve { if constexpr( unsigned_value ) return false_(eve::as(v)); + else if constexpr(O::contains(pedantic)) + { + return is_negative(v) && is_not_nan(v); + } else { if constexpr( signed_integral_value ) @@ -108,3 +116,7 @@ namespace eve } } } + +#if defined(EVE_INCLUDE_X86_HEADER) +# include +#endif diff --git a/test/doc/core/is_negative.cpp b/test/doc/core/is_negative.cpp index 4578c88ac1..5ecc620f03 100644 --- a/test/doc/core/is_negative.cpp +++ b/test/doc/core/is_negative.cpp @@ -4,15 +4,17 @@ int main() { - eve::wide wf0{0.0, 1.0, 2.0, 3.0, -1.0, -2.0, -3.0, -4.0}; + auto nan = eve::nan(eve::as()); + eve::wide wf0{0.0, 1.0, 2.0, 3.0, -1.0, -2.0, -nan, nan}; eve::wide wi0{0, 1, 2, 3, -1, -2, -3, -4}; eve::wide wu0{0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u}; std::cout << "<- wf0 = " << wf0 << "\n"; std::cout << "<- wi0 = " << wi0 << "\n"; std::cout << "<- wu0 = " << wu0 << "\n"; - + std::cout << "-> is_negative(wf0) = " << eve::is_negative(wf0) << "\n"; + std::cout << "-> is_negative[pedantic](wf0) = " << eve::is_negative[eve::pedantic](wf0) << "\n"; std::cout << "-> is_negative[ignore_last(2)](wf0) = " << eve::is_negative[eve::ignore_last(2)](wf0) << "\n"; std::cout << "-> is_negative[wf0 != 0](wf0) = " << eve::is_negative[wf0 != 0](wf0) << "\n"; std::cout << "-> is_negative(wu0) = " << eve::is_negative(wu0) << "\n"; diff --git a/test/unit/module/core/is_negative.cpp b/test/unit/module/core/is_negative.cpp index 9e4cb7db25..375bc0d781 100644 --- a/test/unit/module/core/is_negative.cpp +++ b/test/unit/module/core/is_negative.cpp @@ -60,6 +60,8 @@ TTS_CASE_TPL("Check corner-cases behavior of eve::is_negative on wide", eve::tes auto cases = tts::limits(tgt); TTS_EQUAL(eve::is_negative(cases.nan), eve::true_(as())); TTS_EQUAL(eve::is_negative(-cases.nan), eve::false_(as())); + TTS_EQUAL(eve::is_negative[eve::pedantic](cases.nan), eve::false_(as())); + TTS_EQUAL(eve::is_negative[eve::pedantic](-cases.nan), eve::false_(as())); TTS_EQUAL(eve::is_negative(cases.minf), eve::true_(as())); TTS_EQUAL(eve::is_negative(cases.inf), eve::false_(as())); TTS_EQUAL(eve::is_negative(cases.zero), eve::false_(as())); From 84c89059878ccfa645e79b55ba5f75c83d87d567 Mon Sep 17 00:00:00 2001 From: jtlap Date: Tue, 3 Sep 2024 10:01:29 +0200 Subject: [PATCH 19/25] is_negative --- include/eve/module/core/regular/is_negative.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/eve/module/core/regular/is_negative.hpp b/include/eve/module/core/regular/is_negative.hpp index a5cc726917..e9ffc7950e 100644 --- a/include/eve/module/core/regular/is_negative.hpp +++ b/include/eve/module/core/regular/is_negative.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace eve From f957ed677bbe6c4469c8dbbf5e690ac32d2e6bc8 Mon Sep 17 00:00:00 2001 From: jtlap Date: Tue, 3 Sep 2024 10:33:12 +0200 Subject: [PATCH 20/25] is_negative is_nez --- .../core/regular/impl/simd/x86/is_nez.hpp | 36 +++++++++++++++++++ .../eve/module/core/regular/is_negative.hpp | 5 +-- include/eve/module/core/regular/is_nez.hpp | 4 +++ test/unit/module/core/is_negative.cpp | 2 -- 4 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_nez.hpp diff --git a/include/eve/module/core/regular/impl/simd/x86/is_nez.hpp b/include/eve/module/core/regular/impl/simd/x86/is_nez.hpp new file mode 100644 index 0000000000..4023580555 --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_nez.hpp @@ -0,0 +1,36 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace eve::detail +{ + template + EVE_FORCEINLINE logical> is_nez_(EVE_REQUIRES(avx512_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = fpclass::poszero | fpclass::negzero; + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return ~s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return ~s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return ~s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16) return ~s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return ~s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return ~s_t {_mm_fpclass_ps_mask(a, f)}; + } +} diff --git a/include/eve/module/core/regular/is_negative.hpp b/include/eve/module/core/regular/is_negative.hpp index e9ffc7950e..8fe2273118 100644 --- a/include/eve/module/core/regular/is_negative.hpp +++ b/include/eve/module/core/regular/is_negative.hpp @@ -67,9 +67,10 @@ namespace eve //! **Return value** //! //! 1. For signed types The call `is_negative(x)` returns true -//! if and only if the bit of sign (most significant bit) is set. +//! if and only if the bit of sign (most significant bit) is set. Of course the result on a NaN input +//! is generally out of control. //! 2. [The operation is performed conditionnaly](@ref conditional). -//! 3. with this otion a nan is never negative. +//! 3. with this option a NaN input always return false. //! //! @note //! this function coincides with `is_ltz` on [integral real values](@ref eve::value), diff --git a/include/eve/module/core/regular/is_nez.hpp b/include/eve/module/core/regular/is_nez.hpp index 2a30322179..ba0cba566c 100644 --- a/include/eve/module/core/regular/is_nez.hpp +++ b/include/eve/module/core/regular/is_nez.hpp @@ -81,3 +81,7 @@ namespace eve } } } + +#if defined(EVE_INCLUDE_X86_HEADER) +# include +#endif diff --git a/test/unit/module/core/is_negative.cpp b/test/unit/module/core/is_negative.cpp index 375bc0d781..b18d820553 100644 --- a/test/unit/module/core/is_negative.cpp +++ b/test/unit/module/core/is_negative.cpp @@ -58,8 +58,6 @@ TTS_CASE_TPL("Check corner-cases behavior of eve::is_negative on wide", eve::tes using eve::as; auto cases = tts::limits(tgt); - TTS_EQUAL(eve::is_negative(cases.nan), eve::true_(as())); - TTS_EQUAL(eve::is_negative(-cases.nan), eve::false_(as())); TTS_EQUAL(eve::is_negative[eve::pedantic](cases.nan), eve::false_(as())); TTS_EQUAL(eve::is_negative[eve::pedantic](-cases.nan), eve::false_(as())); TTS_EQUAL(eve::is_negative(cases.minf), eve::true_(as())); From 4184147e2f1b98c771b0ede70b15194009640341 Mon Sep 17 00:00:00 2001 From: jtlap Date: Tue, 3 Sep 2024 13:47:13 +0200 Subject: [PATCH 21/25] is_nemz is_nepz --- include/eve/module/core/regular/core.hpp | 3 + .../core/regular/impl/simd/x86/is_nemz.hpp | 36 ++++++ .../core/regular/impl/simd/x86/is_nepz.hpp | 36 ++++++ .../eve/module/core/regular/is_bit_equal.hpp | 107 ++++++++++++++++++ include/eve/module/core/regular/is_nemz.hpp | 90 +++++++++++++++ include/eve/module/core/regular/is_nepz.hpp | 87 ++++++++++++++ test/doc/core/is_bit_equal.cpp | 28 +++++ test/doc/core/is_bit_equal.hpp | 32 ++++++ test/doc/core/is_nemz.cpp | 16 +++ test/doc/core/is_nepz.cpp | 16 +++ test/random/module/core/is_nemz.cpp | 21 ++++ test/random/module/core/is_nepz.cpp | 21 ++++ test/unit/module/core/is_bit_equal.cpp | 68 +++++++++++ test/unit/module/core/is_nemz.cpp | 38 +++++++ test/unit/module/core/is_nepz.cpp | 38 +++++++ 15 files changed, 637 insertions(+) create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_nemz.hpp create mode 100644 include/eve/module/core/regular/impl/simd/x86/is_nepz.hpp create mode 100644 include/eve/module/core/regular/is_bit_equal.hpp create mode 100644 include/eve/module/core/regular/is_nemz.hpp create mode 100644 include/eve/module/core/regular/is_nepz.hpp create mode 100644 test/doc/core/is_bit_equal.cpp create mode 100644 test/doc/core/is_bit_equal.hpp create mode 100644 test/doc/core/is_nemz.cpp create mode 100644 test/doc/core/is_nepz.cpp create mode 100644 test/random/module/core/is_nemz.cpp create mode 100644 test/random/module/core/is_nepz.cpp create mode 100644 test/unit/module/core/is_bit_equal.cpp create mode 100644 test/unit/module/core/is_nemz.cpp create mode 100644 test/unit/module/core/is_nepz.cpp diff --git a/include/eve/module/core/regular/core.hpp b/include/eve/module/core/regular/core.hpp index 8349471403..92ec7a9ca2 100644 --- a/include/eve/module/core/regular/core.hpp +++ b/include/eve/module/core/regular/core.hpp @@ -89,6 +89,7 @@ #include #include #include +#include #include #include #include @@ -110,6 +111,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/include/eve/module/core/regular/impl/simd/x86/is_nemz.hpp b/include/eve/module/core/regular/impl/simd/x86/is_nemz.hpp new file mode 100644 index 0000000000..7ded91da6e --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_nemz.hpp @@ -0,0 +1,36 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace eve::detail +{ + template + EVE_FORCEINLINE logical> is_nemz_(EVE_REQUIRES(avx512_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = fpclass::negzero; + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return ~s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return ~s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return ~s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16) return ~s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return ~s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return ~s_t {_mm_fpclass_ps_mask(a, f)}; + } +} diff --git a/include/eve/module/core/regular/impl/simd/x86/is_nepz.hpp b/include/eve/module/core/regular/impl/simd/x86/is_nepz.hpp new file mode 100644 index 0000000000..f026a50067 --- /dev/null +++ b/include/eve/module/core/regular/impl/simd/x86/is_nepz.hpp @@ -0,0 +1,36 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace eve::detail +{ + template + EVE_FORCEINLINE logical> is_nepz_(EVE_REQUIRES(avx512_), + O const &, + wide const &a) noexcept + requires x86_abi> + { + using l_t = logical>; + constexpr auto c = categorize>(); + constexpr auto f = fpclass::poszero; + + using s_t = typename l_t::storage_type; + + if constexpr( c == category::float64x8 ) return ~s_t {_mm512_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x4 ) return ~s_t {_mm256_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float64x2 ) return ~s_t {_mm_fpclass_pd_mask(a, f)}; + else if constexpr( c == category::float32x16) return ~s_t {_mm512_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x8 ) return ~s_t {_mm256_fpclass_ps_mask(a, f)}; + else if constexpr( c == category::float32x4 ) return ~s_t {_mm_fpclass_ps_mask(a, f)}; + } +} diff --git a/include/eve/module/core/regular/is_bit_equal.hpp b/include/eve/module/core/regular/is_bit_equal.hpp new file mode 100644 index 0000000000..9d20a4909f --- /dev/null +++ b/include/eve/module/core/regular/is_bit_equal.hpp @@ -0,0 +1,107 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + + +#include +#include +#include +#include + + +namespace eve +{ + template + struct is_bit_equal_t : strict_elementwise_callable + { + template using b_t = bit_value_t; + template using ui_t = as_integer_t, unsigned>; + + template + constexpr EVE_FORCEINLINE auto operator()(T a, U b) const + -> decltype(is_equal(bit_cast(b_t(a), as>()), bit_cast(b_t(b), as>()))) + { + return EVE_DISPATCH_CALL(a, b); + } + + template + constexpr EVE_FORCEINLINE auto operator()(logical a, logical b) const + -> decltype(is_equal(a, b)) + { + return EVE_DISPATCH_CALL(a, b); + } + + EVE_CALLABLE_OBJECT(is_bit_equal_t, is_bit_equal_); + }; + +//================================================================================================ +//! @addtogroup core_predicates +//! @{ +//! @var is_bit_equal +//! @brief `elementwise callable` returning a logical true if and only if the element bits +//! are all equal. +//! +//! @groupheader{Header file} +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace eve +//! { +//! // Regular overload +//! constexpr auto is_bit_equal(value auto x, value auto y) noexcept; // 1 +//! +//! // Lanes masking +//! constexpr auto is_bit_equal[conditional_expr auto c](value auto x, value auto y) noexcept; // 2 +//! constexpr auto is_bit_equal[logical_value auto m](value auto x, value auto y) noexcept; // 2 +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `x`, `y`: [arguments](@ref eve::value). +//! * `c`: [Conditional expression](@ref conditional_expr) masking the operation. +//! * `m`: [Logical value](@ref logical) masking the operation. +//! +//! **Return value** +//! +//! 1. Returns the logical value containing the [elementwise](@ref glossary_elementwise) bit equality +//! test result between `x` and `y`. +//! 2. [The operation is performed conditionnaly](@ref conditional). +//! +//! @groupheader{Example} +//! @godbolt{doc/core/is_bit_equal.cpp} +//================================================================================================ + inline constexpr auto is_bit_equal = functor; +//================================================================================================ +//! @} +//================================================================================================ + + namespace detail + { + template + EVE_FORCEINLINE constexpr auto + is_bit_equal_(EVE_REQUIRES(cpu_),O const & o, T const& a, U const& b) noexcept + { + using b_t = bit_value_t; + using ui_t = as_integer_t; + return is_equal(bit_cast(b_t(a), as()), bit_cast(b_t(b), as())); + } + + template + EVE_FORCEINLINE constexpr auto + is_bit_equal_(EVE_REQUIRES(cpu_),O const & o, logical const& a, logical const& b) noexcept + { + return is_equal(a, b); + } + } +} diff --git a/include/eve/module/core/regular/is_nemz.hpp b/include/eve/module/core/regular/is_nemz.hpp new file mode 100644 index 0000000000..4f8d8d4bc7 --- /dev/null +++ b/include/eve/module/core/regular/is_nemz.hpp @@ -0,0 +1,90 @@ +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace eve +{ + template + struct is_nemz_t : elementwise_callable + { + template + EVE_FORCEINLINE constexpr as_logical_t + operator()(T t) const noexcept + { + return EVE_DISPATCH_CALL(t); + } + + EVE_CALLABLE_OBJECT(is_nemz_t, is_nemz_); + }; + +//================================================================================================ +//! @addtogroup core_predicates +//! @{ +//! @var is_nemz +//! @brief `elementwise callable` returning a logical true if and only if a "negative" zero. +//! +//! @groupheader{Header file} +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace eve +//! { +//! // Regular overload +//! constexpr auto is_nemz(floating_value auto x) noexcept; // 1 +//! +//! // Lanes masking +//! constexpr auto is_nemz[conditional_expr auto c](floating_value auto x) noexcept; // 2 +//! constexpr auto is_nemz[logical_value auto m](floating_value auto x) noexcept; // 2 +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `x`: [floating argument](@ref eve::floating_value). +//! * `c`: [Conditional expression](@ref conditional_expr) masking the operation. +//! * `m`: [Logical value](@ref logical) masking the operation. +//! +//! **Return value** +//! +//! 1. `is_nemz(x)` is semantically equivalent to bitwise equality to `mzero(as(x))`. +//! 2. [The operation is performed conditionnaly](@ref conditional). +//! +//! @groupheader{Example} +//! @godbolt{doc/core/is_nemz.cpp} +//================================================================================================ + inline constexpr auto is_nemz = functor; +//================================================================================================ +//! @} +//================================================================================================ + + namespace detail + { + template + EVE_FORCEINLINE constexpr as_logical_t + is_nemz_(EVE_REQUIRES(cpu_), O const &, T const& a) noexcept + { + if constexpr(integral_value) + return false_(as()); + else + return logical_andnot(is_nez(a), is_eqpz(a)); + } + } +} + +#if defined(EVE_INCLUDE_X86_HEADER) +# include +#endif diff --git a/include/eve/module/core/regular/is_nepz.hpp b/include/eve/module/core/regular/is_nepz.hpp new file mode 100644 index 0000000000..2ebd570c2b --- /dev/null +++ b/include/eve/module/core/regular/is_nepz.hpp @@ -0,0 +1,87 @@ +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace eve +{ + template + struct is_nepz_t : elementwise_callable + { + template + EVE_FORCEINLINE constexpr as_logical_t + operator()(T t) const noexcept + { + return EVE_DISPATCH_CALL(t); + } + + EVE_CALLABLE_OBJECT(is_nepz_t, is_nepz_); + }; + +//================================================================================================ +//! @addtogroup core_predicates +//! @{ +//! @var is_nepz +//! @brief `elementwise callable` returning a logical true if and only if "positive" zero. +//! +//! @groupheader{Header file} +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace eve +//! { +//! // Regular overload +//! constexpr auto is_nepz(value auto x) noexcept; // 1 +//! +//! // Lanes masking +//! constexpr auto is_nepz[conditional_expr auto c](value auto x) noexcept; // 2 +//! constexpr auto is_nepz[logical_value auto m](value auto x) noexcept; // 2 +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `x`: [floating argument](@ref eve::value). +//! * `c`: [Conditional expression](@ref conditional_expr) masking the operation. +//! * `m`: [Logical value](@ref logical) masking the operation. +//! +//! **Return value** +//! +//! 1. `is_nepz(x)` is true if and only if all bits of the representation of `x` are zero. +//! 2. [The operation is performed conditionnaly](@ref conditional). +//! +//! @groupheader{Example} +//! @godbolt{doc/core/is_nepz.cpp} +//================================================================================================ + inline constexpr auto is_nepz = functor; +//================================================================================================ +//! @} +//================================================================================================ + + namespace detail + { + template + EVE_FORCEINLINE constexpr as_logical_t + is_nepz_(EVE_REQUIRES(cpu_), O const &, T const& a) noexcept + { + return !is_eqpz(a); + } + } +} + +#if defined(EVE_INCLUDE_X86_HEADER) +# include +#endif diff --git a/test/doc/core/is_bit_equal.cpp b/test/doc/core/is_bit_equal.cpp new file mode 100644 index 0000000000..523f622169 --- /dev/null +++ b/test/doc/core/is_bit_equal.cpp @@ -0,0 +1,28 @@ +// revision 0 +#include +#include + +int main() +{ + eve::wide wf0{0.0, 1.0, 2.0, 3.0, -1.0, -2.0, -3.0, -0.0}; + eve::wide wf1{0.0, -4.0, 1.0, -1.0, 2.0, -2.0, 3.0, 0.0}; + eve::wide wi0{0, 1, 2, 3, -1, -2, -3, -4}; + eve::wide wi1{0, -4, 1, 3, 2, -2, 3, -3}; + eve::wide wu0{0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u}; + eve::wide wu1{7u, 6u, 5u, 4u, 4u, 2u, 1u, 0u}; + + std::cout << "<- wf0 = " << wf0 << "\n"; + std::cout << "<- wf1 = " << wf1 << "\n"; + std::cout << "<- wi0 = " << wi0 << "\n"; + std::cout << "<- wi1 = " << wi1 << "\n"; + std::cout << "<- wu0 = " << wu0 << "\n"; + std::cout << "<- wu1 = " << wu1 << "\n"; + + std::cout << "-> is_bit_equal(wf0, wf1) = " << eve::is_bit_equal(wf0, wf1) << "\n"; + std::cout << "-> is_bit_equal[ignore_last(2)](wf0, wf1) = " << eve::is_bit_equal[eve::ignore_last(2)](wf0, wf1) << "\n"; + std::cout << "-> is_bit_equal[wf0 != 0](wf0, wf1) = " << eve::is_bit_equal[wf0 != 0](wf0, wf1) << "\n"; + std::cout << "-> is_bit_equal[wu0 != 0](wu0, wu1) = " << eve::is_bit_equal[wu0 != 0](wu0, wu1) << "\n"; + std::cout << "-> is_bit_equal(wi0, wi1) = " << eve::is_bit_equal(wi0, wi1) << "\n"; + std::cout << "-> is_bit_equal[ignore_last(2)](wi0, wi1) = " << eve::is_bit_equal[eve::ignore_last(2)](wi0, wi1) << "\n"; + std::cout << "-> is_bit_equal[wi0 != 0](wi0, wi1) = " << eve::is_bit_equal[wi0 != 0](wi0, wi1) << "\n"; +} diff --git a/test/doc/core/is_bit_equal.hpp b/test/doc/core/is_bit_equal.hpp new file mode 100644 index 0000000000..7478dc1b68 --- /dev/null +++ b/test/doc/core/is_bit_equal.hpp @@ -0,0 +1,32 @@ +// revision 0 +#include +#include + +int main() +{ + eve::wide wf0{0.0, 1.0, 2.0, 3.0, -1.0, -2.0, -3.0, -0.0}; + eve::wide wf1{0.0, -4.0, 1.0, -1.0, 2.0, -2.0, 3.0, 0.0}; + eve::wide wi0{0, 1, 2, 3, -1, -2, -3, -4}; + eve::wide wi1{0, -4, 1, 3, 2, -2, 3, -3}; + eve::wide wu0{0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u}; + eve::wide wu1{7u, 6u, 5u, 4u, 4u, 2u, 1u, 0u}; + + std::cout << "<- wf0 = " << wf0 << "\n"; + std::cout << "<- wf1 = " << wf1 << "\n"; + std::cout << "<- wi0 = " << wi0 << "\n"; + std::cout << "<- wi1 = " << wi1 << "\n"; + std::cout << "<- wu0 = " << wu0 << "\n"; + std::cout << "<- wu1 = " << wu1 << "\n"; + + std::cout << "-> is_equal(wf0, wf1) = " << eve::is_equal(wf0, wf1) << "\n"; + std::cout << "-> is_equal[ignore_last(2)](wf0, wf1) = " << eve::is_equal[eve::ignore_last(2)](wf0, wf1) << "\n"; + std::cout << "-> is_equal[wf0 != 0](wf0, wf1) = " << eve::is_equal[wf0 != 0](wf0, wf1) << "\n"; + std::cout << "-> is_equal[numeric](wf0, wf1) = " << eve::is_equal[eve::numeric](wf0, wf1) << "\n"; + std::cout << "-> is_equal[almost](wf0, wf1) = " << eve::is_equal[eve::almost](wf0, wf1) << "\n"; + std::cout << "-> is_equal(wu0, wu1) = " << eve::is_equal(wu0, wu1) << "\n"; + std::cout << "-> is_equal[ignore_last(2)](wu0, wu1) = " << eve::is_equal[eve::ignore_last(2)](wu0, wu1) << "\n"; + std::cout << "-> is_equal[wu0 != 0](wu0, wu1) = " << eve::is_equal[wu0 != 0](wu0, wu1) << "\n"; + std::cout << "-> is_equal(wi0, wi1) = " << eve::is_equal(wi0, wi1) << "\n"; + std::cout << "-> is_equal[ignore_last(2)](wi0, wi1) = " << eve::is_equal[eve::ignore_last(2)](wi0, wi1) << "\n"; + std::cout << "-> is_equal[wi0 != 0](wi0, wi1) = " << eve::is_equal[wi0 != 0](wi0, wi1) << "\n"; +} diff --git a/test/doc/core/is_nemz.cpp b/test/doc/core/is_nemz.cpp new file mode 100644 index 0000000000..63f59e455d --- /dev/null +++ b/test/doc/core/is_nemz.cpp @@ -0,0 +1,16 @@ +// revision 0 +#include +#include + +int main() +{ + eve::wide wf0{0.0, 1.0, 2.0, 3.0, -1.0, -2.0, -3.0, -0.0}; + eve::wide wi0{0, 1, 2, 3, -1, -2, -3, -4}; + eve::wide wu0{0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u}; + + std::cout << "<- wf0 = " << wf0 << "\n"; + + std::cout << "-> is_nemz(wf0) = " << eve::is_nemz(wf0) << "\n"; + std::cout << "-> is_nemz[ignore_last(2)](wf0) = " << eve::is_nemz[eve::ignore_last(2)](wf0) << "\n"; + std::cout << "-> is_nemz[wf0 != 0](wf0) = " << eve::is_nemz[wf0 != 0](wf0) << "\n"; +} diff --git a/test/doc/core/is_nepz.cpp b/test/doc/core/is_nepz.cpp new file mode 100644 index 0000000000..a179118226 --- /dev/null +++ b/test/doc/core/is_nepz.cpp @@ -0,0 +1,16 @@ +// revision 0 +#include +#include + +int main() +{ + eve::wide wf0{0.0, 1.0, 2.0, 3.0, -1.0, -2.0, -3.0, -0.0}; + eve::wide wi0{0, 1, 2, 3, -1, -2, -3, -4}; + eve::wide wu0{0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u}; + + std::cout << "<- wf0 = " << wf0 << "\n"; + + std::cout << "-> is_nepz(wf0) = " << eve::is_nepz(wf0) << "\n"; + std::cout << "-> is_nepz[ignore_last(2)](wf0) = " << eve::is_nepz[eve::ignore_last(2)](wf0) << "\n"; + std::cout << "-> is_nepz[wf0 != 0](wf0) = " << eve::is_nepz[wf0 != 0](wf0) << "\n"; +} diff --git a/test/random/module/core/is_nemz.cpp b/test/random/module/core/is_nemz.cpp new file mode 100644 index 0000000000..1aca799914 --- /dev/null +++ b/test/random/module/core/is_nemz.cpp @@ -0,0 +1,21 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include +#include "producers.hpp" + +#include + +TTS_CASE_TPL("Random check for eve::is_nemz", eve::test::simd::ieee_reals) +(tts::type) +{ + using e_t = eve::element_type_t; + auto vmin = eve::valmin(eve::as()); + auto vmax = eve::valmax(eve::as()); + auto std_is_nemz = [](auto e) -> eve::logical{ return !eve::is_eqmz(e) || eve::is_nan(e); }; + EVE_ULP_RANGE_CHECK( T, eve::uniform_prng(vmin, vmax), std_is_nemz, eve::is_nemz ); + }; diff --git a/test/random/module/core/is_nepz.cpp b/test/random/module/core/is_nepz.cpp new file mode 100644 index 0000000000..1358013e87 --- /dev/null +++ b/test/random/module/core/is_nepz.cpp @@ -0,0 +1,21 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include +#include "producers.hpp" + +#include + +TTS_CASE_TPL("Random check for eve::is_nepz", eve::test::simd::ieee_reals) +(tts::type) +{ + using e_t = eve::element_type_t; + auto vmin = eve::valmin(eve::as()); + auto vmax = eve::valmax(eve::as()); + auto std_is_nepz = [](auto e) -> eve::logical{ return !eve::is_eqpz(e) || eve::is_nan(e); }; + EVE_ULP_RANGE_CHECK( T, eve::uniform_prng(vmin, vmax), std_is_nepz, eve::is_nepz ); + }; diff --git a/test/unit/module/core/is_bit_equal.cpp b/test/unit/module/core/is_bit_equal.cpp new file mode 100644 index 0000000000..768481f2c9 --- /dev/null +++ b/test/unit/module/core/is_bit_equal.cpp @@ -0,0 +1,68 @@ +//================================================================================================== +/** + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#include "test.hpp" + +#include + +//================================================================================================== +//== Types tests +//================================================================================================== +TTS_CASE_TPL("Check return types of eve::is_bit_equal(simd)", eve::test::simd::all_types) +(tts::type) +{ + using eve::logical; + using v_t = eve::element_type_t; + using ui_t= eve::as_integer_t; + using vi_t= eve::as_integer_t; + TTS_EXPR_IS(eve::is_bit_equal(T(), T()), logical); + TTS_EXPR_IS(eve::is_bit_equal(v_t(), v_t()), logical); + TTS_EXPR_IS(eve::is_bit_equal(T(), v_t()), logical); + TTS_EXPR_IS(eve::is_bit_equal(v_t(), T()), logical); + TTS_EXPR_IS(eve::is_bit_equal(logical(), logical()), logical); + TTS_EXPR_IS(eve::is_bit_equal(logical(), logical()), logical); +}; + +//================================================================================================== +//== Tests for eve::is_bit_equal +//================================================================================================== +TTS_CASE_WITH( + "Check behavior of eve::is_bit_equal(simd)", + eve::test::simd::all_types, + tts::generate(tts::ramp(0), tts::reverse_ramp(4, 2), tts::logicals(0, 3), tts::logicals(1, 2))) +(T const& a0, T const& a1, M const& l0, M const& l1) +{ + using eve::detail::map; + using eve::as; + using eve::bit_cast; + using v_t = eve::element_type_t; + using vi_t= eve::as_integer_t; + using bi_t= eve::as_integer_t; + TTS_EQUAL(eve::is_bit_equal(a0, a1), + map([](auto e, auto f) -> eve::logical { return bit_cast(e, as())== bit_cast(f, as()); }, a0, a1)); + TTS_EQUAL(eve::is_bit_equal(a0, a0), + map([](auto e, auto f) -> eve::logical { return bit_cast(e, as())== bit_cast(f, as()); }, a0, a0)); + TTS_EQUAL(eve::is_bit_equal(l0, l1), + map([](auto e, auto f) { return e == f; }, l0, l1)); + TTS_EQUAL(eve::is_bit_equal[l0](a0, a1), + eve::if_else(l0, eve::is_bit_equal(a0, a1), eve::false_(eve::as()))); +}; + +//================================================================================================== +//== Tests for eve::is_bit_equal corner cases for floating +//================================================================================================== +TTS_CASE_TPL("Check behavior of eve::is_bit_equal(simd)", eve::test::simd::ieee_reals) +(tts::type const& tgt) +{ + + using bi_t= eve::as_integer_t; + auto cases = tts::limits(tgt); + TTS_EQUAL(eve::is_bit_equal(cases.nan, cases.nan), eve::true_(eve::as())); + TTS_EQUAL(eve::is_bit_equal(cases.mzero, cases.mzero), eve::true_(eve::as())); + TTS_EQUAL(eve::is_bit_equal(cases.mzero, cases.zero), eve::false_(eve::as())); + +}; diff --git a/test/unit/module/core/is_nemz.cpp b/test/unit/module/core/is_nemz.cpp new file mode 100644 index 0000000000..8138141e24 --- /dev/null +++ b/test/unit/module/core/is_nemz.cpp @@ -0,0 +1,38 @@ +//================================================================================================== +/** + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#include "test.hpp" + +#include + +//================================================================================================== +// Types tests +//================================================================================================== +TTS_CASE_TPL("Check return types of eve::is_nemz(simd)", eve::test::simd::ieee_reals) +(tts::type) +{ + using eve::logical; + using v_t = eve::element_type_t; + TTS_EXPR_IS(eve::is_nemz(T()), logical); + TTS_EXPR_IS(eve::is_nemz(v_t()), logical); +}; + +//================================================================================================== +// Tests for eve::is_nemz +//================================================================================================== + +TTS_CASE_WITH("Check behavior of eve::is_nemz(simd)", + eve::test::simd::ieee_reals, + tts::generate(tts::ramp(0), tts::logicals(0, 3))) +(T const& a0, M const& t) +{ + using eve::detail::map; + using v_t = eve::element_type_t; + + TTS_EQUAL(eve::is_nemz(a0), map([](auto e) -> eve::logical { return eve::isltz(e) || eve::is_positive(e); }, a0)); + TTS_EQUAL(eve::is_nemz[t](a0), eve::if_else(t, eve::is_nemz(a0), eve::false_(eve::as(a0)))); +}; diff --git a/test/unit/module/core/is_nepz.cpp b/test/unit/module/core/is_nepz.cpp new file mode 100644 index 0000000000..6317d39a50 --- /dev/null +++ b/test/unit/module/core/is_nepz.cpp @@ -0,0 +1,38 @@ +//================================================================================================== +/** + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#include "test.hpp" + +#include + +//================================================================================================== +// Types tests +//================================================================================================== +TTS_CASE_TPL("Check return types of eve::is_nepz(simd)", eve::test::simd::ieee_reals) +(tts::type) +{ + using eve::logical; + using v_t = eve::element_type_t; + TTS_EXPR_IS(eve::is_nepz(T()), logical); + TTS_EXPR_IS(eve::is_nepz(v_t()), logical); +}; + +//================================================================================================== +// Tests for eve::is_nepz +//================================================================================================== + +TTS_CASE_WITH("Check behavior of eve::is_nepz(simd)", + eve::test::simd::ieee_reals, + tts::generate(tts::ramp(0), tts::logicals(0, 3))) +(T const& a0, M const& t) +{ + using eve::detail::map; + using v_t = eve::element_type_t; + + TTS_EQUAL(eve::is_nepz(a0), map([](auto e) -> eve::logical { return eve::is_gtz(e) || eve::is_negative(e); }, a0)); + TTS_EQUAL(eve::is_nepz[t](a0), eve::if_else(t, eve::is_nepz(a0), eve::false_(eve::as(a0)))); +}; From d5f6778fd720db7f2b582c94b7c34c41998937da Mon Sep 17 00:00:00 2001 From: jtlap Date: Tue, 3 Sep 2024 13:53:57 +0200 Subject: [PATCH 22/25] is_bit_equal unused param --- include/eve/module/core/regular/is_bit_equal.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/eve/module/core/regular/is_bit_equal.hpp b/include/eve/module/core/regular/is_bit_equal.hpp index 9d20a4909f..4929f4d874 100644 --- a/include/eve/module/core/regular/is_bit_equal.hpp +++ b/include/eve/module/core/regular/is_bit_equal.hpp @@ -90,7 +90,7 @@ namespace eve { template EVE_FORCEINLINE constexpr auto - is_bit_equal_(EVE_REQUIRES(cpu_),O const & o, T const& a, U const& b) noexcept + is_bit_equal_(EVE_REQUIRES(cpu_),O const &, T const& a, U const& b) noexcept { using b_t = bit_value_t; using ui_t = as_integer_t; @@ -99,7 +99,7 @@ namespace eve template EVE_FORCEINLINE constexpr auto - is_bit_equal_(EVE_REQUIRES(cpu_),O const & o, logical const& a, logical const& b) noexcept + is_bit_equal_(EVE_REQUIRES(cpu_),O const &, logical const& a, logical const& b) noexcept { return is_equal(a, b); } From 9e4415d00abfdf4b94aec313ce671dc90a92171a Mon Sep 17 00:00:00 2001 From: jtlap Date: Tue, 3 Sep 2024 14:30:56 +0200 Subject: [PATCH 23/25] is_nemz typo --- test/unit/module/core/is_nemz.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/module/core/is_nemz.cpp b/test/unit/module/core/is_nemz.cpp index 8138141e24..9ff6c695ca 100644 --- a/test/unit/module/core/is_nemz.cpp +++ b/test/unit/module/core/is_nemz.cpp @@ -33,6 +33,6 @@ TTS_CASE_WITH("Check behavior of eve::is_nemz(simd)", using eve::detail::map; using v_t = eve::element_type_t; - TTS_EQUAL(eve::is_nemz(a0), map([](auto e) -> eve::logical { return eve::isltz(e) || eve::is_positive(e); }, a0)); + TTS_EQUAL(eve::is_nemz(a0), map([](auto e) -> eve::logical { return eve::is_ltz(e) || eve::is_positive(e); }, a0)); TTS_EQUAL(eve::is_nemz[t](a0), eve::if_else(t, eve::is_nemz(a0), eve::false_(eve::as(a0)))); }; From a880be0c25900f9b7150666baa0944570448d185 Mon Sep 17 00:00:00 2001 From: jtlap Date: Tue, 3 Sep 2024 15:05:18 +0200 Subject: [PATCH 24/25] is_nemz --- include/eve/module/core/regular/is_nemz.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/eve/module/core/regular/is_nemz.hpp b/include/eve/module/core/regular/is_nemz.hpp index 4f8d8d4bc7..2295ecd85b 100644 --- a/include/eve/module/core/regular/is_nemz.hpp +++ b/include/eve/module/core/regular/is_nemz.hpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include namespace eve { @@ -80,7 +82,7 @@ namespace eve if constexpr(integral_value) return false_(as()); else - return logical_andnot(is_nez(a), is_eqpz(a)); + return logical_or(is_positive(a), is_ltz(a)); } } } From d4e74e32ddddf469433e2abe0efac125f40b573c Mon Sep 17 00:00:00 2001 From: jtlap Date: Tue, 3 Sep 2024 20:02:34 +0200 Subject: [PATCH 25/25] [no ci] spurious file --- test/doc/core/is_bit_equal.hpp | 32 -------------------------------- 1 file changed, 32 deletions(-) delete mode 100644 test/doc/core/is_bit_equal.hpp diff --git a/test/doc/core/is_bit_equal.hpp b/test/doc/core/is_bit_equal.hpp deleted file mode 100644 index 7478dc1b68..0000000000 --- a/test/doc/core/is_bit_equal.hpp +++ /dev/null @@ -1,32 +0,0 @@ -// revision 0 -#include -#include - -int main() -{ - eve::wide wf0{0.0, 1.0, 2.0, 3.0, -1.0, -2.0, -3.0, -0.0}; - eve::wide wf1{0.0, -4.0, 1.0, -1.0, 2.0, -2.0, 3.0, 0.0}; - eve::wide wi0{0, 1, 2, 3, -1, -2, -3, -4}; - eve::wide wi1{0, -4, 1, 3, 2, -2, 3, -3}; - eve::wide wu0{0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u}; - eve::wide wu1{7u, 6u, 5u, 4u, 4u, 2u, 1u, 0u}; - - std::cout << "<- wf0 = " << wf0 << "\n"; - std::cout << "<- wf1 = " << wf1 << "\n"; - std::cout << "<- wi0 = " << wi0 << "\n"; - std::cout << "<- wi1 = " << wi1 << "\n"; - std::cout << "<- wu0 = " << wu0 << "\n"; - std::cout << "<- wu1 = " << wu1 << "\n"; - - std::cout << "-> is_equal(wf0, wf1) = " << eve::is_equal(wf0, wf1) << "\n"; - std::cout << "-> is_equal[ignore_last(2)](wf0, wf1) = " << eve::is_equal[eve::ignore_last(2)](wf0, wf1) << "\n"; - std::cout << "-> is_equal[wf0 != 0](wf0, wf1) = " << eve::is_equal[wf0 != 0](wf0, wf1) << "\n"; - std::cout << "-> is_equal[numeric](wf0, wf1) = " << eve::is_equal[eve::numeric](wf0, wf1) << "\n"; - std::cout << "-> is_equal[almost](wf0, wf1) = " << eve::is_equal[eve::almost](wf0, wf1) << "\n"; - std::cout << "-> is_equal(wu0, wu1) = " << eve::is_equal(wu0, wu1) << "\n"; - std::cout << "-> is_equal[ignore_last(2)](wu0, wu1) = " << eve::is_equal[eve::ignore_last(2)](wu0, wu1) << "\n"; - std::cout << "-> is_equal[wu0 != 0](wu0, wu1) = " << eve::is_equal[wu0 != 0](wu0, wu1) << "\n"; - std::cout << "-> is_equal(wi0, wi1) = " << eve::is_equal(wi0, wi1) << "\n"; - std::cout << "-> is_equal[ignore_last(2)](wi0, wi1) = " << eve::is_equal[eve::ignore_last(2)](wi0, wi1) << "\n"; - std::cout << "-> is_equal[wi0 != 0](wi0, wi1) = " << eve::is_equal[wi0 != 0](wi0, wi1) << "\n"; -}