Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
32 changes: 14 additions & 18 deletions include/xsimd/arch/xsimd_avx512f.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "../types/xsimd_avx512f_register.hpp"
#include "../types/xsimd_batch_constant.hpp"
#include "../utils/bits.hpp"

#include <complex>
#include <limits>
Expand Down Expand Up @@ -2255,11 +2256,8 @@ namespace xsimd
XSIMD_INLINE batch_bool<T, A> set(batch_bool<T, A> const&, requires_arch<avx512f>, Values... values) noexcept
{
static_assert(sizeof...(Values) == batch_bool<T, A>::size, "consistent init");
using register_type = typename batch_bool<T, A>::register_type;
register_type r = 0;
unsigned shift = 0;
(void)std::initializer_list<register_type> { (r |= register_type(values ? 1 : 0) << (shift++))... };
return r;
using reg_t = typename batch_bool<T, A>::register_type;
return ::xsimd::utils::make_bit_mask_from_bools<reg_t>(values...);
}

// shuffle
Expand Down Expand Up @@ -2656,21 +2654,19 @@ namespace xsimd

namespace detail
{
template <class T, class A, T... Idx>
struct is_pair_of_contiguous_indices;

template <class T, class A>
struct is_pair_of_contiguous_indices<T, A> : std::true_type
template <class T, T... Idx, std::size_t... Is>
constexpr bool is_pair_of_contiguous_indices_impl(std::index_sequence<Is...>) noexcept
{
};
constexpr T idx[] = { Idx... };
return (... && (idx[2 * Is] % 2 == 0 && idx[2 * Is] + 1 == idx[2 * Is + 1]));
}

template <class T, class A, T Idx0, T Idx1, T... Idx>
struct is_pair_of_contiguous_indices<T, A, Idx0, Idx1, Idx...> : std::conditional_t<(Idx0 % 2 == 0) && (Idx0 + 1 == Idx1), is_pair_of_contiguous_indices<T, A, Idx...>, std::false_type>
template <class T, T... Idx>
constexpr bool is_pair_of_contiguous_indices() noexcept
{
};

template <class T, class A, T... Idx>
inline constexpr bool is_pair_of_contiguous_indices_v = is_pair_of_contiguous_indices<T, A, Idx...>::value;
static_assert(sizeof...(Idx) % 2 == 0, "indices come in pairs");
return is_pair_of_contiguous_indices_impl<T, Idx...>(std::make_index_sequence<sizeof...(Idx) / 2>());
}

template <class A, uint16_t I0, uint16_t I1, uint16_t I2, uint16_t I3, uint16_t I4, uint16_t I5, uint16_t I6, uint16_t I7,
uint16_t I8, uint16_t I9, uint16_t I10, uint16_t I11, uint16_t I12, uint16_t I13, uint16_t I14, uint16_t I15,
Expand Down Expand Up @@ -2703,7 +2699,7 @@ namespace xsimd
template <class A, uint16_t... Idx>
XSIMD_INLINE batch<uint16_t, A> swizzle(batch<uint16_t, A> const& self, batch_constant<uint16_t, A, Idx...> mask, requires_arch<avx512f>) noexcept
{
if constexpr (detail::is_pair_of_contiguous_indices_v<uint16_t, A, Idx...>)
if constexpr (detail::is_pair_of_contiguous_indices<uint16_t, Idx...>())
{
constexpr typename detail::fold_batch_constant<A, Idx...>::type mask32;
return _mm512_permutexvar_epi32(static_cast<batch<uint32_t, A>>(mask32), self);
Expand Down
8 changes: 3 additions & 5 deletions include/xsimd/arch/xsimd_avx512vl_128.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "../types/xsimd_avx512vl_register.hpp"
#include "../types/xsimd_batch_constant.hpp"
#include "../utils/bits.hpp"

#include <type_traits>

Expand Down Expand Up @@ -173,11 +174,8 @@ namespace xsimd
XSIMD_INLINE batch_bool<T, A> set(batch_bool<T, A> const&, requires_arch<avx512vl_128>, Values... values) noexcept
{
static_assert(sizeof...(Values) == batch_bool<T, A>::size, "consistent init");
using register_type = typename batch_bool<T, A>::register_type;
register_type r = 0;
unsigned shift = 0;
(void)std::initializer_list<register_type> { (r |= register_type(values ? 1 : 0) << (shift++))... };
return r;
using reg_t = typename batch_bool<T, A>::register_type;
return ::xsimd::utils::make_bit_mask_from_bools<reg_t>(values...);
}

// store
Expand Down
8 changes: 3 additions & 5 deletions include/xsimd/arch/xsimd_avx512vl_256.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "../types/xsimd_avx512vl_register.hpp"
#include "../types/xsimd_batch_constant.hpp"
#include "../utils/bits.hpp"

#include <type_traits>

Expand Down Expand Up @@ -173,11 +174,8 @@ namespace xsimd
XSIMD_INLINE batch_bool<T, A> set(batch_bool<T, A> const&, requires_arch<avx512vl_256>, Values... values) noexcept
{
static_assert(sizeof...(Values) == batch_bool<T, A>::size, "consistent init");
using register_type = typename batch_bool<T, A>::register_type;
register_type r = 0;
unsigned shift = 0;
(void)std::initializer_list<register_type> { (r |= register_type(values ? 1 : 0) << (shift++))... };
return r;
using reg_t = typename batch_bool<T, A>::register_type;
return ::xsimd::utils::make_bit_mask_from_bools<reg_t>(values...);
}

// store
Expand Down
21 changes: 2 additions & 19 deletions include/xsimd/config/xsimd_arch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include "./xsimd_config.hpp"
#include "./xsimd_cpuid.hpp"

#include <initializer_list>
#include <type_traits>
#include <utility>

Expand All @@ -40,22 +39,6 @@ namespace xsimd

namespace detail
{
// Checks whether T appears in Tys.
template <class T, class... Tys>
struct contains;

template <class T>
struct contains<T> : std::false_type
{
};

template <class T, class Ty, class... Tys>
struct contains<T, Ty, Tys...>
: std::conditional_t<std::is_same_v<Ty, T>, std::true_type,
contains<T, Tys...>>
{
};

template <typename T>
XSIMD_INLINE constexpr T max_of(T value) noexcept
{
Expand Down Expand Up @@ -100,13 +83,13 @@ namespace xsimd
template <class Arch>
static constexpr bool contains() noexcept
{
return detail::contains<Arch, Archs...>::value;
return (std::is_same_v<Arch, Archs> || ...);
}

template <class F>
static XSIMD_INLINE void for_each(F&& f) noexcept
{
(void)std::initializer_list<bool> { (f(Archs {}), true)... };
(f(Archs {}), ...);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how ugly (but less then the previous expression, so OK, of course)

}

static constexpr std::size_t alignment() noexcept
Expand Down
29 changes: 3 additions & 26 deletions include/xsimd/types/xsimd_batch_constant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#define XSIMD_BATCH_CONSTANT_HPP

#include "../config/xsimd_config.hpp"
#include "../utils/bits.hpp"
#include "./xsimd_batch.hpp"
#include "./xsimd_utils.hpp"

Expand Down Expand Up @@ -61,7 +62,7 @@ namespace xsimd

static constexpr int mask() noexcept
{
return mask_helper(0, static_cast<int>(Values)...);
return static_cast<int>(bits());
}

static constexpr bool none() noexcept
Expand Down Expand Up @@ -128,14 +129,6 @@ namespace xsimd
}

private:
static constexpr int mask_helper(int acc) noexcept { return acc; }

template <class... Tys>
static constexpr int mask_helper(int acc, int mask, Tys... masks) noexcept
{
return mask_helper(acc | mask, (masks << 1)...);
}

struct logical_or
{
constexpr bool operator()(bool x, bool y) const { return x || y; }
Expand Down Expand Up @@ -191,25 +184,9 @@ namespace xsimd

private:
// Build a 64-bit mask from Values... (LSB = index 0)
template <std::size_t I, bool... Remaining>
struct build_bits_helper;

template <std::size_t I>
struct build_bits_helper<I>
{
static constexpr uint64_t value = 0u;
};

template <std::size_t I, bool Current, bool... Remaining>
struct build_bits_helper<I, Current, Remaining...>
{
static constexpr uint64_t value = (Current ? (uint64_t(1) << I) : 0u)
| build_bits_helper<I + 1, Remaining...>::value;
};

static constexpr uint64_t bits() noexcept
{
return build_bits_helper<0, Values...>::value;
return utils::make_bit_mask_from_bools<uint64_t>(Values...);
}
static constexpr uint64_t low_mask(std::size_t k) noexcept
{
Expand Down
31 changes: 20 additions & 11 deletions include/xsimd/utils/bits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,40 @@ namespace xsimd
{
namespace utils
{
template <typename I>
constexpr I make_bit_mask(I bit)
template <typename... Args>
constexpr auto make_bit_mask(Args... bits)
{
static_assert(std::is_unsigned_v<I>, "Bit operations must be done on unsigned integers");
assert(bit < static_cast<I>(8 * sizeof(I)));
return static_cast<I>(I { 1 } << bit);
using out_type = std::common_type_t<unsigned short, std::make_unsigned_t<Args>...>;
[[maybe_unused]] constexpr auto bit_count = static_cast<out_type>(8 * sizeof(out_type));
assert((((static_cast<out_type>(bits) < bit_count) && ...)));
return static_cast<out_type>((0u | ... | (1u << bits)));
}

template <typename I, typename... Args>
constexpr I make_bit_mask(I bit, Args... bits)
/**
* Return a mask whose bit `i` holds the truth value of the `i`th argument.
*/
template <typename I, typename... Bools>
constexpr I make_bit_mask_from_bools(Bools... bools) noexcept
{
// TODO(C++17): Use fold expression
static_assert(std::is_unsigned_v<I>, "Bit operations must be done on unsigned integers");
return make_bit_mask<I>(bit) | make_bit_mask<I>(static_cast<I>(bits)...);
static_assert(sizeof...(Bools) <= 8 * sizeof(I), "Not enough bits to hold all the values");
// GCC's -Wsequence-point does not model fold sequencing and rejects `shift++` inside
// the fold operand, hence the comma to separate read from increment.
I mask = 0;
unsigned shift = 0;
((mask |= static_cast<I>(static_cast<I>(bools ? 1 : 0) << shift), ++shift), ...);
return mask;
}

template <int... Bits, typename I>
template <auto... Bits, typename I>
constexpr bool all_bits_set(I value)
{
static_assert(std::is_unsigned_v<I>, "Bit operations must be done on unsigned integers");
constexpr I mask = make_bit_mask<I>(static_cast<I>(Bits)...);
return (value & mask) == mask;
}

template <int Bit, typename I>
template <auto Bit, typename I>
constexpr I set_bit(I value)
{
static_assert(std::is_unsigned_v<I>, "Bit operations must be done on unsigned integers");
Expand Down
21 changes: 21 additions & 0 deletions test/test_utils_bits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

TEST_CASE("[utils::make_bit_mask] single bit")
{
CHECK_EQ(xsimd::utils::make_bit_mask(), 0x0);
CHECK_EQ(xsimd::utils::make_bit_mask(1), 0b0010);
CHECK_EQ(xsimd::utils::make_bit_mask<std::uint8_t>(0), 0x01);
CHECK_EQ(xsimd::utils::make_bit_mask<std::uint8_t>(7), 0x80);
CHECK_EQ(xsimd::utils::make_bit_mask<std::uint32_t>(0), 0x01u);
Expand All @@ -29,6 +31,25 @@ TEST_CASE("[utils::make_bit_mask] multiple bits")
CHECK_EQ(xsimd::utils::make_bit_mask<std::uint8_t>(0, 2, 4), 0b00010101);
}

TEST_CASE("[utils::make_bit_mask_from_bools]")
{
CHECK_EQ(xsimd::utils::make_bit_mask_from_bools<std::uint8_t>(), 0x00);
CHECK_EQ(xsimd::utils::make_bit_mask_from_bools<std::uint8_t>(true), 0x01);
CHECK_EQ(xsimd::utils::make_bit_mask_from_bools<std::uint8_t>(false), 0x00);
// First argument goes in the lowest bit
CHECK_EQ(xsimd::utils::make_bit_mask_from_bools<std::uint8_t>(true, false, false), 0b001);
CHECK_EQ(xsimd::utils::make_bit_mask_from_bools<std::uint8_t>(false, false, true), 0b100);
// Full width
CHECK_EQ(
xsimd::utils::make_bit_mask_from_bools<std::uint8_t>(true, true, true, true, true, true, true, true),
0xFF);
CHECK_EQ(
xsimd::utils::make_bit_mask_from_bools<std::uint16_t>(
true, false, true, false, true, false, true, false,
true, false, true, false, true, false, true, false),
0x5555);
}

TEST_CASE("[utils::all_bits_set] basic")
{
CHECK(xsimd::utils::all_bits_set<0>(0x01u));
Expand Down
Loading