Skip to content

Commit

Permalink
Implements SVE first_true
Browse files Browse the repository at this point in the history
  • Loading branch information
DenisYaroshevskiy authored Aug 22, 2023
1 parent 0d37461 commit 3d85d28
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 6 deletions.
12 changes: 9 additions & 3 deletions include/eve/arch/arm/sve/sve_true.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,22 @@ sve_true()
// Returns clear sve_true for type of a given cardinal
// while masking potential garbage value
template<relative_conditional_expr C, typename T>
EVE_FORCEINLINE svbool_t
EVE_FORCEINLINE T
sve_true(C cond, as<T> tgt)
{
if constexpr(C::is_complete && C::is_inverted)
{
using v_t = element_type_t<T>;
using fc_t = fundamental_cardinal_t<v_t>;

if constexpr(T::size() >= fc_t::value ) return sve_true<v_t>();
else return keep_first(T::size()).mask(as<as_wide_t<v_t,fc_t>>{});
if constexpr ( eve::has_aggregated_abi_v<T> )
{
using half_t = as_wide_t<v_t, eve::fixed<T::size() / 2>>;
half_t half = sve_true(cond, eve::as<half_t>{});
return T{half, half};
}
else if constexpr(T::size() == fc_t::value ) return sve_true<v_t>();
else return bit_cast(keep_first(T::size()).mask(as<as_wide_t<v_t, fc_t>>{}), tgt);
}
else
{
Expand Down
6 changes: 4 additions & 2 deletions include/eve/module/core/compress/compress.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@ namespace eve
//! template <simd_value T, logical_simd_value L>
//! auto compress(T x, L m); // (1)
//!
//! template <simd_value T, logical_simd_value L>
//! auto compress[ignore](T x, L m) // (2)
//! template <relative_conditional_expr C,
//! simd_value T,
//! logical_simd_value L>
//! auto compress[C ignore](T x, L m) // (2)
//! }
//! @endcode
//!
Expand Down
54 changes: 53 additions & 1 deletion include/eve/module/core/regular/first_true.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,54 @@ namespace eve
{
//================================================================================================
//! @addtogroup core_reduction
// DOC TO DO
//! @{
//! @var first_true
//! @brief A function to find a first true value, if there is one.
//!
//! @code
//! #include <eve/module/core.hpp>
//! @endcode
//!
//! ## Should you check for any?
//!
//! The function is considering the case when nothing is set to be likely,
//! checking for eve::any before hand is not going to be helpful.
//! At the moment there isn't a function that would do it otherwise.
//!
//! ## What if I know there is a match?
//! We would recommend `*eve::first_true(m)` - this is likely to trigger
//! compiler optimizations, based on it being UB otherwise.
//!
//! @groupheader{Callable Signatures}
//!
//! @code
//! template <logical_simd_value L>
//! std::optional<std::ptrdiff_t> first_true(L m); // (1)
//!
//! template <logical_simd_value L>
//! std::optional<std::ptrdiff_t> first_true(top_bits<L> m); // (2)
//!
//! template <relative_conditional_expr C, logical_simd_value L>
//! std::optional<std::ptrdiff_t> first_true[C ignore](L m); // (3)
//!
//! std::optional<std::ptrdiff_t> first_true(bool m); // (4)
//! @endcode
//!
//! **Parameters**
//!
//! * m - logical_value or top_bits where to find first true value
//! * ignore - ignored elements are considred false. Only supported for
//! `logical_simd_value`
//!
//! **Return value**
//!
//! Returns `std::nullopt` if eve::none(m).
//! Otherwise returns 0 based index.
//!
//! @groupheader{Example}
//!
//! @godbolt{doc/core/regular/first_true.cpp}
//! @}
//================================================================================================
EVE_MAKE_CALLABLE(first_true_, first_true);
}
Expand All @@ -24,3 +71,8 @@ EVE_MAKE_CALLABLE(first_true_, first_true);
#if defined(EVE_INCLUDE_ARM_HEADER)
# include <eve/module/core/regular/impl/simd/arm/neon/first_true.hpp>
#endif


#if defined(EVE_INCLUDE_SVE_HEADER)
# include <eve/module/core/regular/impl/simd/arm/sve/first_true.hpp>
#endif
62 changes: 62 additions & 0 deletions include/eve/module/core/regular/impl/simd/arm/sve/first_true.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//==================================================================================================
/*
EVE - Expressive Vector Engine
Copyright : EVE Project Contributors
SPDX-License-Identifier: BSL-1.0
*/
//==================================================================================================
#pragma once

namespace eve::detail
{

// There are some explanations
// Here: https://lemire.me/blog/2022/12/19/implementing-strlen-using-sve/
// Or: https://www.stonybrook.edu/commcms/ookami/support/_docs/5%20-%20Advanced%20SVE.pdf
template<relative_conditional_expr C, logical_simd_value L>
EVE_FORCEINLINE std::optional<std::ptrdiff_t>
first_true_(EVE_SUPPORTS(sve_), C c, L m) noexcept
{
if constexpr( C::is_complete && !C::is_inverted ) return std::nullopt;
else if constexpr( has_aggregated_abi_v<L> )
{
if constexpr( !C::is_complete ) m = m && sve_true(c, as(m));
auto [lo, hi] = m.slice();
auto lo_res = first_true[ignore_none](lo);
auto hi_res = first_true[ignore_none](hi);
if( lo_res ) return lo_res;
if( hi_res ) *hi_res += lo.size();
return hi_res;
}
else
{
auto c_m = L {sve_true(c, eve::as(m))};

// We don't need this much but it makes the `no matches` case
// faster
if( !svptest_any(c_m, m) ) return std::nullopt;

// we need to ignore as false
if constexpr( !C::is_complete ) m = m && c_m;

eve::as_wide_t<eve::element_type_t<L>> first_true_mask =
svbrkb_z(sve_true<element_type_t<L>>(), m);
return count_true(first_true_mask);
}
}

template<logical_simd_value L>
EVE_FORCEINLINE std::optional<std::ptrdiff_t>
first_true_(EVE_SUPPORTS(sve_), L m) noexcept
{
return first_true[ignore_none](m);
}

template<logical_simd_value L>
EVE_FORCEINLINE std::optional<std::ptrdiff_t>
first_true_(EVE_SUPPORTS(sve_), top_bits<L> m) noexcept
{
return first_true(to_logical(m));
}

}
28 changes: 28 additions & 0 deletions test/doc/core/regular/first_true.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <eve/module/core.hpp>
#include <tts/tts.hpp>

using w_t = eve::wide<int, eve::fixed<4>>;

int main()
{
w_t x = {1, 2, 3, 4};

// logicals

TTS_EQUAL(std::nullopt, eve::first_true(x == 0));
TTS_EQUAL(0, eve::first_true(x == 1));
TTS_EQUAL(1, eve::first_true(x == 2));

TTS_EQUAL(std::nullopt, eve::first_true[eve::ignore_first(1)](x == 1));
TTS_EQUAL(2, eve::first_true[eve::ignore_first(2)](x < 5));

// top_bits

eve::top_bits mmask{x >= 2};
TTS_EQUAL(1, eve::first_true(mmask));

// scalar

TTS_EQUAL(std::nullopt, eve::first_true(false));
TTS_EQUAL(0, eve::first_true(true));
}

0 comments on commit 3d85d28

Please sign in to comment.