Skip to content

Commit

Permalink
Turn eve::if_else into a new style callable
Browse files Browse the repository at this point in the history
  • Loading branch information
jfalcou authored Sep 24, 2024
1 parent 04d5753 commit d8b0b41
Show file tree
Hide file tree
Showing 18 changed files with 364 additions and 350 deletions.
2 changes: 1 addition & 1 deletion include/eve/arch/riscv/tags.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ struct riscv_ : rvv_abi_<1>
//================================================================================================
// Dispatching tag for RISC-V SIMD implementation
//================================================================================================
struct rvv_ : simd_api<simd_, spy::rvv_>
struct rvv_ : simd_api<simd_, spy::fixed_rvv_>
{
using is_rvv = void;
};
Expand Down
45 changes: 12 additions & 33 deletions include/eve/concept/generator.hpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
//==================================================================================================
//======================================================================================================================
/*
EVE - Expressive Vector Engine
Copyright : EVE Project Contributors
SPDX-License-Identifier: BSL-1.0
*/
//==================================================================================================
//======================================================================================================================
#pragma once

#include <eve/as.hpp>
Expand All @@ -15,35 +15,14 @@

namespace eve
{
namespace detail
{
// Can I pass Type to a constant ?
template<typename Constant, typename Type>
struct is_generator : std::bool_constant<eve::invocable<Constant, as<Type>>>
{};

template<typename Constant, typename Type, typename Index> struct is_generator_impl;

template<typename Constant, typename Type, std::size_t... I>
struct is_generator_impl<Constant, Type, std::index_sequence<I...>>
: std::bool_constant<(is_generator<Constant, std::tuple_element_t<I, Type>>::value && ...)>
{};

template<typename Constant, kumi::product_type Type>
struct is_generator<Constant, Type>
: is_generator_impl<Constant, Type, std::make_index_sequence<std::tuple_size<Type>::value>>
{};
}

//==================================================================================================
//! @ingroup simd_concepts
//! @concept generator
//! The concept `generator<Constant,Type>` is satisfied if `Constant{}( eve::as<Type>() )` is
//! well formed.
//!
//! @groupheader{Examples}
//! - `eve::callable_one_`
//==================================================================================================
template<typename Constant, typename Type>
concept generator = !kumi::product_type<Constant> && detail::is_generator<Constant, Type>::value;
//====================================================================================================================
//! @ingroup simd_concepts
//! @concept generator
//! The concept `generator<Constant>` is satisfied if `Constant` is built as a eve::constant_callable.
//!
//! @groupheader{Examples}
//! - `eve::one`
//====================================================================================================================
template<typename Constant>
concept generator = requires { typename Constant::constant_callable_tag; };
}
12 changes: 6 additions & 6 deletions include/eve/detail/function/simd/riscv/bitmask.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@
#pragma once

#include <eve/detail/abi.hpp>
#include <eve/module/core/regular/if_else.hpp>

#include <bitset>

namespace eve::detail
{
//================================================================================================
// Logical to Bits
//================================================================================================
template<typename T, typename N>
EVE_FORCEINLINE auto
EVE_FORCEINLINE typename logical<wide<T, N>>::bits_type
to_bits(rvv_ const&, logical<wide<T, N>> p) noexcept
requires rvv_abi<abi_t<T, N>>
{
using uint_type = as_uinteger_t<T>;
return eve::if_else(p, static_cast<uint_type>(-1), static_cast<uint_type>(0));
using u_t = as_uinteger_t<T>;
auto z = wide<u_t, N>(0);
auto a = allbits(as<wide<u_t, N>>{});

return __riscv_vmerge_tu(a.storage(), z.storage(), a.storage(), p.storage(), N::value);
}

//================================================================================================
Expand Down
2 changes: 1 addition & 1 deletion include/eve/detail/function/simd/riscv/to_logical.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace eve::detail
{
template<typename T, typename N>
EVE_FORCEINLINE auto
to_logical(wide<T, N> v) noexcept
to_logical(wide<T, N> const& v) noexcept
requires rvv_abi<abi_t<T, N>>
{
return v != static_cast<T>(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ namespace eve::detail
else if constexpr ( N() == 2 )
{
auto to_left = eve::slide_left( v, eve::index<1> );
auto compressed = eve::if_else[mask]( v, to_left );
auto compressed = eve::if_else(mask, v, to_left );

kumi::tuple cur{ compressed, eve::count_true(mask) };
return kumi::tuple<decltype(cur)> { cur };
Expand All @@ -240,7 +240,7 @@ namespace eve::detail
{
// Reduce variations: in each pair from 4 to 3. 10 and 01 become the same.
// Two last elements don't matter.
v = eve::if_else[mask]( v, compress_using_masks_to_left( v ) );
v = eve::if_else(mask, v, compress_using_masks_to_left( v ) );

auto [num, count] = compress_store_swizzle_mask_num(mask);
kumi::tuple cur { compress_using_masks_shuffle(v, num), count };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ namespace eve::detail
if constexpr ( max_scalar_size_v<T> == 2 && current_api < avx ) return compress_using_masks_(EVE_RETARGET(cpu_), c, v, mask);
else
{
v = eve::if_else[mask]( v, compress_using_masks_to_left( v ) );
v = eve::if_else(mask, v, compress_using_masks_to_left( v ) );
auto [lo_idx, lo_count, hi_idx, hi_count] = compress_store_swizzle_mask_num(mask);

auto [shuffled_lo, shuffled_hi] = compress_using_masks_shuffle_16{lo_idx, hi_idx}(v);
Expand Down
211 changes: 157 additions & 54 deletions include/eve/module/core/regular/if_else.hpp
Original file line number Diff line number Diff line change
@@ -1,67 +1,170 @@
//==================================================================================================
//======================================================================================================================
/*
EVE - Expressive Vector Engine
Copyright : EVE Project Contributors
SPDX-License-Identifier: BSL-1.0
*/
//==================================================================================================
//======================================================================================================================
#pragma once

#include <eve/arch.hpp>
#include <eve/detail/overload.hpp>

#include <eve/traits/overload.hpp>
#include <eve/concept/generator.hpp>
namespace eve
{
//================================================================================================
//! @addtogroup core_logical
//! @{
//! @var if_else
//! @brief Computes the results of a choice under condition
//!
//! @groupheader{Header file}
//!
//! @code
//! #include <eve/module/core.hpp>
//! @endcode
//!
//! @groupheader{Callable Signatures}
//!
//! @code
//! namespace eve
//! {
//! constexpr auto if_else(value auto x, value auto y, value auto z ) noexcept;
//! }
//! @endcode
//!
//! **Parameters**
//!
//! * `x`: condition
//! * `y`, `z`: choice [value](@ref value).
//!
//! **Return value**
//!
//! The call `if_else(x, y, z)` performs [elementwise](@ref glossary_elementwise)
//! a choice between the elements of `y` and `z`
//! according to the truth value of the elements of `x`.
//!
//! **Possible optimizations**
//!
//! The following calls where `x`, `y` and `z` are values can be optimized:
//!
//! * `if_else(x, y, allbits< T >())` writing: `if_else(x, y, allbits)`
//! * `if_else(x, y, one< T >() )` writing: `if_else(x, y, one )`
//! * `if_else(x, y, mone< T >() )` writing: `if_else(x, y, mone )`
//! * `if_else(x, y, zero< T >() )` writing: `if_else(x, y, zero )`
//! * `if_else(x, allbits< T >(), z)` writing: `if_else(x, allbits, z)`
//! * `if_else(x, one< T >(), z )` writing: `if_else(x, one, z )`
//! * `if_else(x, mone< T >(), z )` writing: `if_else(x, mone, z )`
//! * `if_else(x, zero< T >(), z )` writing: `if_else(x, zero, z )`
//!
//! @groupheader{Example}
//! @godbolt{doc/core/if_else.cpp}
//! @}
//================================================================================================
EVE_MAKE_CALLABLE(if_else_, if_else);
template<typename Options>
struct if_else_t : callable<if_else_t, Options>
{
//==================================================================================================================
// The following requires ensure proper, short error messages
// We rely on the semantic of as_wide_as to handle bool and conditional_expr properly
template<typename C, typename T, typename U> struct result;

template<typename C, typename T, typename U>
requires(requires { typename common_value<T,U>::type; })
struct result<C,T,U> : as_wide_as<common_value_t<T,U>,C> {};

template<typename C, typename T, typename U>
requires(requires { typename common_logical<T,U>::type; })
struct result<C, logical<T>, logical<U>> : as_wide_as<common_logical_t<T,U>,C> {};

template<typename C, typename T, generator U> struct result<C, T, U> : as_wide_as<T,C> {};
template<typename C, generator T, typename U> struct result<C, T, U> : as_wide_as<U,C> {};
//==================================================================================================================

// IF_ELSE with a value as condition
template<value C, value T, value U>
EVE_FORCEINLINE constexpr typename result<C,T,U>::type
operator()(C mask, T v0, U v1) const noexcept
requires(eve::same_lanes_or_scalar<C,T,U>)
{
return EVE_DISPATCH_CALL(mask,v0,v1);
}

template<value C, typename T, typename U>
EVE_FORCEINLINE constexpr typename result<C,T,U>::type
operator()(C mask, T v0, U v1) const noexcept
requires( (eve::same_lanes_or_scalar<C,T> && generator<U> && value<T>)
|| (eve::same_lanes_or_scalar<C,U> && generator<T> && value<U>)
)
{
return EVE_DISPATCH_CALL(mask,v0,v1);
}

// IF_ELSE with a conditional_expr as condition
template<conditional_expr C, value T, value U>
EVE_FORCEINLINE constexpr typename result<C,T,U>::type
operator()(C mask, T v0, U v1) const noexcept
requires(eve::same_lanes_or_scalar<T,U>)
{
return EVE_DISPATCH_CALL(mask,v0,v1);
}

template<conditional_expr C, typename T, typename U>
EVE_FORCEINLINE constexpr typename result<C,T,U>::type
operator()(C mask, T v0, U v1) const noexcept
requires( (generator<U> && value<T>) || (generator<T> && value<U>) )
{
return EVE_DISPATCH_CALL(mask,v0,v1);
}

// IF_ELSE with explicit bool
template<value T, value U>
EVE_FORCEINLINE constexpr typename result<bool,T,U>::type
operator()(bool mask, T v0, U v1) const noexcept
requires(eve::same_lanes_or_scalar<T,U>)
{
return EVE_DISPATCH_CALL(logical<std::uint8_t>(mask),v0,v1);
}

template<typename T, typename U>
EVE_FORCEINLINE constexpr typename result<bool,T,U>::type
operator()(bool mask, T v0, U v1) const noexcept
requires( (generator<U> && value<T>) || (generator<T> && value<U>) )
{
return EVE_DISPATCH_CALL(logical<std::uint8_t>(mask),v0,v1);
}

EVE_CALLABLE_OBJECT(if_else_t, if_else_);
};

//================================================================================================
//! @addtogroup core_logical
//! @{
//! @var if_else
//! @brief Select value based on conditional mask or values
//!
//! **Defined in Header**
//!
//! @code
//! #include <eve/module/core.hpp>
//! @endcode
//!
//! @groupheader{Callable Signatures}
//!
//! @code
//! namespace eve
//! {
//! template<eve::value U, eve::value V>
//! constexpr auto if_else(bool mask, U t, V f) noexcept;
//!
//! template<eve::value M, eve::value U, eve::value V>
//! constexpr auto if_else(M mask, U t, V f) noexcept;
//!
//! template<eve::value M, eve::generator U, eve::value V>
//! constexpr auto if_else(M mask, U t, V f) noexcept;
//!
//! template<eve::value M, eve::value U, eve::generator V>
//! constexpr auto if_else(M mask, U t, V f) noexcept;
//!
//! template<eve::conditional_expr C, eve::value U, eve::value V >
//! constexpr auto if_else(C mask, U t, V f) noexcept;
//!
//! template<eve::conditional_expr C, eve::generator U, eve::value V >
//! constexpr auto if_else(C mask, U t, V f) noexcept;
//!
//! template<eve::conditional_expr C, eve::value U, eve::generator V >
//! constexpr auto if_else(C mask, U t, V f) noexcept;
//! }
//! @endcode
//!
//! **Parameters**
//!
//! * `mask`: [logical value](@ref eve::logical_value) or [condition](@ref eve::conditional_expr) to use as mask.
//! * `t`: Value or constant to use where `mask` evaluates to `true`.
//! * `f`: Value or constant to use where `mask` evaluates to `false`.
//!
//! **Return value**
//!
//! The call `if_else(mask, t, f)` performs an [elementwise](@ref glossary_elementwise)
//! selection between the elements of `t` and `f` according to the value of the elements of `mask`.
//!
//! **Possible optimizations**
//!
//! The following calls, where `t` and `f` are values, are optimized so the constant are not evaluated:
//! * `if_else(mask, t , eve::allbits)`
//! * `if_else(mask, t , eve::one )`
//! * `if_else(mask, t , eve::mone )`
//! * `if_else(mask, t , eve::zero )`
//! * `if_else(mask, eve::allbits , f )`
//! * `if_else(mask, eve::one , f )`
//! * `if_else(mask, eve::mone , f )`
//! * `if_else(mask, eve::zero , f )`
//!
//! In addition, the following calls, where `t` and `f` are unsigned values, are optimized so the
//! constant are not evaluated:
//! * `if_else(mask, t , eve::valmax)`
//! * `if_else(mask, t , eve::valmin)`
//! * `if_else(mask, eve::valmax, f )`
//! * `if_else(mask, eve::valmin, f )`
//!
//! @groupheader{Example}
//!
//! @godbolt{doc/core/if_else.cpp}
//!
//! @}
//================================================================================================
inline constexpr auto if_else = functor<if_else_t>;
}

#include <eve/module/core/regular/impl/if_else.hpp>
Expand Down
Loading

0 comments on commit d8b0b41

Please sign in to comment.