Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Move self_less to the is_less callable #2048

Merged
merged 19 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions include/eve/arch/cpu/wide.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -861,32 +861,32 @@ namespace eve
friend EVE_FORCEINLINE auto operator!=(S v, wide w) noexcept { return w != v; }

//! @brief Element-wise less-than comparison between eve::wide
friend EVE_FORCEINLINE auto operator<(wide v, wide w) noexcept
friend EVE_FORCEINLINE auto operator<(wide a, wide b) noexcept
#if !defined(EVE_DOXYGEN_INVOKED)
requires(supports_ordering_v<Type>)
#endif
{
return detail::self_less(v, w);
return is_less(a, b);
}

//! @brief Element-wise less-than comparison between a eve::wide and a scalar
template<scalar_value S>
friend EVE_FORCEINLINE auto operator<(wide v, S w) noexcept
friend EVE_FORCEINLINE auto operator<(wide w, S s) noexcept
#if !defined(EVE_DOXYGEN_INVOKED)
requires(supports_ordering_v<Type>)
#endif
{
return v < wide {w};
return is_less(w, s);
}

//! @brief Element-wise less-than comparison between a scalar and a eve::wide
template<scalar_value S>
friend EVE_FORCEINLINE auto operator<(S v, wide w) noexcept
friend EVE_FORCEINLINE auto operator<(S s, wide w) noexcept
#if !defined(EVE_DOXYGEN_INVOKED)
requires(supports_ordering_v<Type>)
#endif
{
return wide {v} < w;
return is_less(s, w);
}

//! @brief Element-wise greater-than comparison between eve::wide
Expand Down
12 changes: 4 additions & 8 deletions include/eve/concept/compatible.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,15 @@ namespace eve
concept size_compatible_values = size_compatible_to<T, U>
|| size_compatible_to<U, T>;


template<typename T, typename U>
concept same_value_type = std::same_as< element_type_t<std::remove_cvref_t<T>>
, element_type_t<std::remove_cvref_t<U>>
>;
template<typename T, typename... Ts>
concept same_element_type = (std::same_as<element_type_t<std::remove_cvref_t<T>>, element_type_t<std::remove_cvref_t<Ts>>> && ...);

template<typename T, typename U>
concept different_value_type = !std::same_as<element_type_t<U>, element_type_t<T>>;


template<typename I, typename T>
concept index_compatible_values = integral_value<I> && floating_value<T> && size_compatible_values<I, T>;



template<typename T, typename U>
concept compatible_arithmetic_values = scalar_value<T> || scalar_value<U> || std::same_as<T, U>;
}
19 changes: 19 additions & 0 deletions include/eve/concept/value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,25 @@ namespace eve
//! @}
//================================================================================================

//================================================================================================
//! @ingroup simd_concepts
//! @{
//! @concept arithmetic_value
//! @brief The concept `plain_value<T>` is satisfied if and only if T satisfies
//! `eve::arithmetic_simd_value` or `eve::arithmetic_scalar_value`.
//!
//! @groupheader{Examples}
//! - `int`
//! - `eve::wide<double>`
//! - `kumi::tuple<double, int>`
//! - `eve::wide<kumi::tuple<double, int>>`
//================================================================================================
template <typename T>
concept arithmetic_value = arithmetic_simd_value<T> || arithmetic_scalar_value<T>;
SadiinsoSnowfall marked this conversation as resolved.
Show resolved Hide resolved
//================================================================================================
//! @}
//================================================================================================

//================================================================================================
//! @ingroup simd_concepts
//! @{
Expand Down
39 changes: 0 additions & 39 deletions include/eve/detail/function/simd/arm/neon/friends.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,45 +62,6 @@ namespace eve::detail
return !(v == w);
}

//================================================================================================
// operator!= implementation
//================================================================================================
template<typename T, typename N>
EVE_FORCEINLINE logical<wide<T, N>> self_less ( wide<T, N> v
, wide<T, N> w
) noexcept
requires arm_abi<abi_t<T, N>>
{
constexpr auto cat = categorize<wide<T, N>>();

if constexpr( cat == category::int32x4 ) return vcltq_s32(v, w);
else if constexpr( cat == category::int16x8 ) return vcltq_s16(v, w);
else if constexpr( cat == category::int8x16 ) return vcltq_s8(v, w);
else if constexpr( cat == category::uint32x4 ) return vcltq_u32(v, w);
else if constexpr( cat == category::uint16x8 ) return vcltq_u16(v, w);
else if constexpr( cat == category::uint8x16 ) return vcltq_u8(v, w);
else if constexpr( cat == category::float32x4) return vcltq_f32(v, w);
else if constexpr( cat == category::int32x2 ) return vclt_s32(v, w);
else if constexpr( cat == category::int16x4 ) return vclt_s16(v, w);
else if constexpr( cat == category::int8x8 ) return vclt_s8(v, w);
else if constexpr( cat == category::uint32x2 ) return vclt_u32(v, w);
else if constexpr( cat == category::uint16x4 ) return vclt_u16(v, w);
else if constexpr( cat == category::uint8x8 ) return vclt_u8(v, w);
else if constexpr( cat == category::float32x2) return vclt_f32(v, w);
else if constexpr( current_api >= asimd)
{
if constexpr( cat == category::float64x1) return vclt_f64(v, w);
else if constexpr( cat == category::int64x1) return vclt_s64(v, w);
else if constexpr( cat == category::uint64x1) return vclt_u64(v, w);
else if constexpr( cat == category::float64x2) return vcltq_f64(v, w);
else if constexpr( cat == category::int64x2) return vcltq_s64(v, w);
else if constexpr( cat == category::uint64x2) return vcltq_u64(v, w);
}
else if constexpr( sizeof(T) == 8 )
return map([]<typename E>(E const& e, E const& f){ return as_logical_t<E>(e < f); }, v, w);

}

template<typename T, typename N>
EVE_FORCEINLINE logical<wide<T, N>> self_greater( wide<T, N> v
, wide<T, N> w
Expand Down
5 changes: 0 additions & 5 deletions include/eve/detail/function/simd/arm/sve/friends.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ EVE_FORCEINLINE auto
self_neq(wide<T, N> v, wide<T, N> w) noexcept -> as_logical_t<wide<T, N>>
requires sve_abi<abi_t<T, N>> { return svcmpne(sve_true<T>(), v, w); }

template<arithmetic_scalar_value T, typename N>
EVE_FORCEINLINE auto
self_less(wide<T, N> v, wide<T, N> w) noexcept -> as_logical_t<wide<T, N>>
requires sve_abi<abi_t<T, N>> { return svcmplt(sve_true<T>(), v, w); }

template<arithmetic_scalar_value T, typename N>
EVE_FORCEINLINE auto
self_greater(wide<T, N> v, wide<T, N> w) noexcept -> as_logical_t<wide<T, N>>
Expand Down
20 changes: 3 additions & 17 deletions include/eve/detail/function/simd/common/friends.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace eve::detail
}
else
{
return convert(v.storage() == w.storage(), as_element<as_logical_t<Wide>>());
return v.storage() == w.storage();
}
}

Expand Down Expand Up @@ -77,7 +77,7 @@ namespace eve::detail
}
else
{
return convert(v.storage() != w.storage(), as_element<as_logical_t<Wide>>());
return v.storage() != w.storage();
}
}

Expand All @@ -99,20 +99,6 @@ namespace eve::detail

//================================================================================================
// Ordering operators
template<simd_value Wide>
EVE_FORCEINLINE auto self_less(Wide const& v,Wide const& w) noexcept
{
if constexpr( product_type<Wide> )
{
return convert(kumi::to_tuple(v) < kumi::to_tuple(w), as_element<as_logical_t<Wide>>());
}
else
{
constexpr auto lt = []<typename E>(E const& e, E const& f) { return as_logical_t<E>(e < f); };
return apply_over(lt, v, w);
}
}

template<simd_value Wide>
EVE_FORCEINLINE auto self_leq(Wide const& v,Wide const& w) noexcept
{
Expand Down Expand Up @@ -146,7 +132,7 @@ namespace eve::detail
{
if constexpr( product_type<Wide> )
{
return convert(kumi::to_tuple(v) >= kumi::to_tuple(w), as_element<as_logical_t<Wide>>());
return kumi::to_tuple(v) >= kumi::to_tuple(w);
}
else
{
Expand Down
7 changes: 0 additions & 7 deletions include/eve/detail/function/simd/ppc/friends.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,6 @@ namespace eve::detail
return logical<wide<T,N>>(vec_cmpne(v.storage(), w.storage()));
}

template<arithmetic_scalar_value T, typename N>
EVE_FORCEINLINE auto self_less(wide<T, N> const &v, wide<T, N> const &w) noexcept
requires ppc_abi<abi_t<T, N>>
{
return logical<wide<T,N>>(vec_cmplt(v.storage(), w.storage()));
}

template<arithmetic_scalar_value T, typename N>
EVE_FORCEINLINE auto self_greater(wide<T, N> const &v, wide<T, N> const &w) noexcept
requires ppc_abi<abi_t<T, N>>
Expand Down
31 changes: 0 additions & 31 deletions include/eve/detail/function/simd/riscv/friends.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,37 +44,6 @@ requires rvv_abi<abi_t<T, N>>
return self_greater_impl(lhs, rhs);
}

template<plain_scalar_value T, typename N, value U>
EVE_FORCEINLINE auto
self_less_impl(wide<T, N> lhs, U rhs) noexcept -> logical<wide<T, N>>
requires rvv_abi<abi_t<T, N>> && (std::same_as<wide<T, N>, U> || scalar_value<U>)
{
if constexpr( scalar_value<U> && !std::same_as<T, U> ) return self_less(lhs, static_cast<T>(rhs));
else
{
constexpr auto c = categorize<wide<T, N>>();
if constexpr( match(c, category::int_) ) return __riscv_vmslt(lhs, rhs, N::value);
else if constexpr( match(c, category::uint_) ) return __riscv_vmsltu(lhs, rhs, N::value);
else if constexpr( match(c, category::float_) ) return __riscv_vmflt(lhs, rhs, N::value);
}
}

template<plain_scalar_value T, typename N>
EVE_FORCEINLINE auto
self_less(wide<T, N> lhs, wide<T, N> rhs) noexcept -> logical<wide<T, N>>
requires rvv_abi<abi_t<T, N>>
{
return self_less_impl(lhs, rhs);
}

template<plain_scalar_value T, typename N>
EVE_FORCEINLINE auto
self_less(wide<T, N> lhs, std::convertible_to<T> auto rhs) noexcept -> logical<wide<T, N>>
requires rvv_abi<abi_t<T, N>>
{
return self_less_impl(lhs, rhs);
}

template<plain_scalar_value T, typename N, value U>
EVE_FORCEINLINE auto
self_geq_impl(wide<T, N> lhs, U rhs) noexcept -> logical<wide<T, N>>
Expand Down
80 changes: 0 additions & 80 deletions include/eve/detail/function/simd/x86/friends.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,86 +179,6 @@ self_neq(logical<wide<T, N>> v, logical<wide<T, N>> w) noexcept requires x86_abi
else { return bit_cast(v.bits() ^ w.bits(), as(v)); }
}

//================================================================================================
template<arithmetic_scalar_value T, typename N>
EVE_FORCEINLINE as_logical_t<wide<T, N>>
self_less(wide<T, N> v, wide<T, N> w) noexcept requires x86_abi<abi_t<T, N>>
{
constexpr auto c = categorize<wide<T, N>>();
constexpr auto f = to_integer(cmp_flt::lt_oq);

if constexpr( current_api >= avx512 )
{
if constexpr( c == category::float32x16 ) return mask16 {_mm512_cmp_ps_mask(v, w, f)};
else if constexpr( c == category::float32x8 ) return mask8 {_mm256_cmp_ps_mask(v, w, f)};
else if constexpr( c == category::float32x4 ) return mask8 {_mm_cmp_ps_mask(v, w, f)};
else if constexpr( c == category::float64x8 ) return mask8 {_mm512_cmp_pd_mask(v, w, f)};
else if constexpr( c == category::float64x4 ) return mask8 {_mm256_cmp_pd_mask(v, w, f)};
else if constexpr( c == category::float64x2 ) return mask8 {_mm_cmp_pd_mask(v, w, f)};
else if constexpr( c == category::uint64x8 ) return mask8 {_mm512_cmplt_epu64_mask(v, w)};
else if constexpr( c == category::uint64x4 ) return mask8 {_mm256_cmplt_epu64_mask(v, w)};
else if constexpr( c == category::uint64x2 ) return mask8 {_mm_cmplt_epu64_mask(v, w)};
else if constexpr( c == category::uint32x16 ) return mask16 {_mm512_cmplt_epu32_mask(v, w)};
else if constexpr( c == category::uint32x8 ) return mask8 {_mm256_cmplt_epu32_mask(v, w)};
else if constexpr( c == category::uint32x4 ) return mask8 {_mm_cmplt_epu32_mask(v, w)};
else if constexpr( c == category::uint16x32 ) return mask32 {_mm512_cmplt_epu16_mask(v, w)};
else if constexpr( c == category::uint16x16 ) return mask16 {_mm256_cmplt_epu16_mask(v, w)};
else if constexpr( c == category::uint16x8 ) return mask8 {_mm_cmplt_epu16_mask(v, w)};
else if constexpr( c == category::uint8x64 ) return mask64 {_mm512_cmplt_epu8_mask(v, w)};
else if constexpr( c == category::uint8x32 ) return mask32 {_mm256_cmplt_epu8_mask(v, w)};
else if constexpr( c == category::uint8x16 ) return mask16 {_mm_cmplt_epu8_mask(v, w)};
else if constexpr( c == category::int64x8 ) return mask8 {_mm512_cmplt_epi64_mask(v, w)};
else if constexpr( c == category::int64x4 ) return mask8 {_mm256_cmplt_epi64_mask(v, w)};
else if constexpr( c == category::int64x2 ) return mask8 {_mm_cmplt_epi64_mask(v, w)};
else if constexpr( c == category::int32x16 ) return mask16 {_mm512_cmplt_epi32_mask(v, w)};
else if constexpr( c == category::int32x8 ) return mask8 {_mm256_cmplt_epi32_mask(v, w)};
else if constexpr( c == category::int32x4 ) return mask8 {_mm_cmplt_epi32_mask(v, w)};
else if constexpr( c == category::int16x32 ) return mask32 {_mm512_cmplt_epi16_mask(v, w)};
else if constexpr( c == category::int16x16 ) return mask16 {_mm256_cmplt_epi16_mask(v, w)};
else if constexpr( c == category::int16x8 ) return mask8 {_mm_cmplt_epi16_mask(v, w)};
else if constexpr( c == category::int8x64 ) return mask64 {_mm512_cmplt_epi8_mask(v, w)};
else if constexpr( c == category::int8x32 ) return mask32 {_mm256_cmplt_epi8_mask(v, w)};
else if constexpr( c == category::int8x16 ) return mask16 {_mm_cmplt_epi8_mask(v, w)};
}
else
{
if constexpr( c == category::float32x8 ) return _mm256_cmp_ps(v, w, f);
else if constexpr( c == category::float64x4 ) return _mm256_cmp_pd(v, w, f);
else if constexpr( c == category::float32x4 ) return _mm_cmplt_ps(v, w);
else if constexpr( c == category::float64x2 ) return _mm_cmplt_pd(v, w);
else
{
constexpr auto use_avx2 = current_api >= avx2;
constexpr auto lt = []<typename E>(E ev, E fv) { return as_logical_t<E>(ev < fv); };

[[maybe_unused]] auto unsigned_cmp = [](auto vv, auto wv)
{
using l_t = logical<wide<T, N>>;
auto const sm = signmask(as<as_integer_t<wide<T, N>, signed>>());
return bit_cast((bit_cast(vv, as(sm)) - sm) < (bit_cast(wv, as(sm)) - sm), as<l_t> {});
};

if constexpr( use_avx2 && c == category::int64x4 ) return _mm256_cmpgt_epi64(w, v);
else if constexpr( use_avx2 && c == category::uint64x4 ) return unsigned_cmp(v, w);
else if constexpr( use_avx2 && c == category::int32x8 ) return _mm256_cmpgt_epi32(w, v);
else if constexpr( use_avx2 && c == category::uint32x8 ) return unsigned_cmp(v, w);
else if constexpr( use_avx2 && c == category::int16x16 ) return _mm256_cmpgt_epi16(w, v);
else if constexpr( use_avx2 && c == category::uint16x16 ) return unsigned_cmp(v, w);
else if constexpr( use_avx2 && c == category::int8x32 ) return _mm256_cmpgt_epi8(w, v);
else if constexpr( use_avx2 && c == category::uint8x32 ) return unsigned_cmp(v, w);
else if constexpr( c == category::int64x2 ) return map(lt, v, w);
else if constexpr( c == category::int32x4 ) return _mm_cmplt_epi32(v, w);
else if constexpr( c == category::int16x8 ) return _mm_cmplt_epi16(v, w);
else if constexpr( c == category::int8x16 ) return _mm_cmplt_epi8(v, w);
else if constexpr( c == category::uint64x2 ) return map(lt, v, w);
else if constexpr( c == category::uint32x4 ) return unsigned_cmp(v, w);
else if constexpr( c == category::uint16x8 ) return unsigned_cmp(v, w);
else if constexpr( c == category::uint8x16 ) return unsigned_cmp(v, w);
else return aggregate(lt, v, w);
}
}
}

//================================================================================================
template<arithmetic_scalar_value T, typename N>
EVE_FORCEINLINE as_logical_t<wide<T, N>>
Expand Down
34 changes: 34 additions & 0 deletions include/eve/module/core/regular/impl/is_less.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//==================================================================================================
/*
EVE - Expressive Vector Engine
Copyright : EVE Project Contributors
SPDX-License-Identifier: BSL-1.0
*/
//==================================================================================================
#pragma once

namespace eve::detail
{
template<callable_options O, typename T>
EVE_FORCEINLINE constexpr as_logical_t<T> is_less_(EVE_REQUIRES(cpu_), O const& o, T a, T b) noexcept
{
SadiinsoSnowfall marked this conversation as resolved.
Show resolved Hide resolved
if constexpr (O::contains(definitely))
SadiinsoSnowfall marked this conversation as resolved.
Show resolved Hide resolved
{
static_assert(floating_value<T>, "[eve::is_less] The definitely option is only supported for floating types.");

auto tol = o[definitely].value(T{});

if constexpr (integral_value<decltype(tol)>) return a < eve::prev(b, tol);
else return a < fam(b, -tol, eve::max(eve::abs(a), eve::abs(b)));
}
else if constexpr (product_type<T>)
{
return kumi::to_tuple(a) < kumi::to_tuple(b);
}
else
{
if constexpr (scalar_value<T>) return as_logical_t<T>(a < b);
else return map([](auto e, auto f) { return e < f; }, a, b);
}
}
DenisYaroshevskiy marked this conversation as resolved.
Show resolved Hide resolved
}
Loading
Loading