diff --git a/include/xvec/detail/mask.hpp b/include/xvec/detail/mask.hpp index 39955d1..3c84813 100644 --- a/include/xvec/detail/mask.hpp +++ b/include/xvec/detail/mask.hpp @@ -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 auto b) noexcept : @@ -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); } diff --git a/include/xvec/detail/operators.hpp b/include/xvec/detail/operators.hpp index 570f4c3..e22ea9a 100644 --- a/include/xvec/detail/operators.hpp +++ b/include/xvec/detail/operators.hpp @@ -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); } diff --git a/include/xvec/generic/generic_impl.hpp b/include/xvec/generic/generic_impl.hpp index 7f54d4c..0cef8c6 100644 --- a/include/xvec/generic/generic_impl.hpp +++ b/include/xvec/generic/generic_impl.hpp @@ -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()); } } @@ -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()))); diff --git a/include/xvec/x86/permute.hpp b/include/xvec/x86/permute.hpp index 99f6e12..85b01c0 100644 --- a/include/xvec/x86/permute.hpp +++ b/include/xvec/x86/permute.hpp @@ -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 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 584202e..646f3f6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -250,7 +250,6 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") xvec_test_common INTERFACE -Wno-unknown-pragmas - -flax-vector-conversions ) endif()