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
9 changes: 8 additions & 1 deletion include/xvec/detail/mask.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ class basic_mask
constexpr basic_mask& operator=(const basic_mask&) = default;
constexpr basic_mask& operator=(basic_mask&&) noexcept = default;

/// Allow a mask to be constructed from the compiler's own representation. The
/// compiler may use multiple or partial target registers in its
/// representation. This constructor allows a mask to be built from the output
/// of an overloaded operator, a builtin, and so on.
/// @ingroup simd_constructor
constexpr basic_mask(const builtin_type& m) noexcept : mask(m) {}

/// @brief Build a mask from a boolean value.
/// @param b The boolean value to broadcast to all mask elements.
constexpr explicit basic_mask(std::same_as<value_type> auto b) noexcept :
Expand Down Expand Up @@ -183,7 +190,7 @@ class basic_mask
/// be a type which can be used for a standard constructor (e.g.,
/// integral-like) so the `from_builtin` ensures that the desired effect is
/// achieved directly.
static constexpr basic_mask from_builtin(const auto& m) { basic_mask bm; bm.mask = traits::truncate_to_size(m); return bm; }
static constexpr basic_mask from_builtin(const builtin_type& m) { basic_mask bm; bm.mask = traits::truncate_to_size(m); return bm; }

/// Convert the mask into a register which can be passed to an intrinsic.
constexpr auto to_register() const noexcept { return traits::to_register(mask); }
Expand Down
2 changes: 1 addition & 1 deletion include/xvec/detail/operators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ constexpr auto builtin_operator(generic_tag, _Vp lhs, _Vp rhs, _Op op) {
r = op(lhsd, rhsd);
#endif

if constexpr (mask_operator<_Op>) return _Vp::mask_type::from_builtin(r);
if constexpr (mask_operator<_Op>) return typename _Vp::mask_type(typename _Vp::mask_type::builtin_type(r));
else return _Vp::from_builtin(r);
}

Expand Down
13 changes: 8 additions & 5 deletions include/xvec/generic/generic_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1144,16 +1144,19 @@ constexpr basic_vec<_Tp, _Abi> mask_to_vec(generic_tag, const basic_mask<_Bytes,
static_assert(_Value == 1 || _Value == -1, "Only some values are permitted for mask to vec output");
static_assert(_Bytes == sizeof(_Tp), "Invalid mask or destination - differing sizes");

using _To = basic_vec<_Tp, _Abi>;
using _B = typename _To::builtin_type;

if constexpr (std::integral<_Tp> && _Value == -1)
// The mask is already entirely 0 or 1 bits, so nothing more to do
return basic_vec<_Tp, _Abi>(mask.to_builtin());
return _To(_B(mask.to_builtin()));
else if constexpr (std::integral<_Tp> && _Value == 1)
// The mask is entirely 0 or 1 bits so a logical shift will convert the MSB into an LSB.
return basic_vec<_Tp, _Abi>(mask.to_builtin() >> (sizeof(_Tp) * 8 - 1));
return _To(_B(mask.to_builtin() >> (sizeof(_Tp) * 8 - 1)));
else
{
constexpr auto _vs = basic_vec<_Tp, _Abi>(_Tp(_Value));
return select(mask, _vs, basic_vec<_Tp, _Abi>());
constexpr auto _vs = _To(_Tp(_Value));
return select(mask, _vs, _To());
}
}

Expand Down Expand Up @@ -1359,7 +1362,7 @@ constexpr auto get_n_bit_mask(compact_mask_tag, const _M&, simd_size_type _n)
if constexpr (_M::size <= 64)
{
const auto clamped = std::min(_M::size(), _n);
return _M::from_builtin(clamped == 64 ? ~0ULL : (1ULL << clamped) - 1);
return _M::from_builtin(typename _M::builtin_type(clamped == 64 ? ~0ULL : (1ULL << clamped) - 1));
}
else
return _M::from_builtin(_M(true).to_builtin() >> (_M::size - std::min(_n, _M::size())));
Expand Down
4 changes: 2 additions & 2 deletions include/xvec/x86/permute.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ _mm512_permutex2var_epi8_emulated(__m512i v_data_0,
// for that permutation comes from the upper 5-bits of the incoming index (i.e., discard the LSB). The permute
// instruction masks the index bits itself, so we only need to put the upper 5-bits of the index
// into the correct location.
__v32hi evenPerm = _mm512_permutex2var_epi16(v_data_0, v_shuf_idxs >> 1, v_data_1);
__v32hi oddPerm = _mm512_permutex2var_epi16(v_data_0, v_shuf_idxs >> 9, v_data_1);
auto evenPerm = _mm512_permutex2var_epi16(v_data_0, v_shuf_idxs >> 1, v_data_1);
auto oddPerm = _mm512_permutex2var_epi16(v_data_0, v_shuf_idxs >> 9, v_data_1);

// evenPerm and oddPerm now contain pairs of bytes. We need to select which byte of each pair to use,
// and that selection is driven by the LSB of each index (i.e., LSB == 0 means use the lower byte of the
Expand Down
1 change: 0 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,6 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
xvec_test_common
INTERFACE
-Wno-unknown-pragmas
-flax-vector-conversions
)
endif()

Expand Down
Loading