From 5f22167b8b744bcd862076ef8ad5631e2af3729d Mon Sep 17 00:00:00 2001 From: danieltowner Date: Fri, 9 Oct 2026 12:13:53 +0100 Subject: [PATCH] Removed -flax-vector-conversion command line option from tests gcc used lax vector conversion to provide implicit conversions between vectors of the same size but different types. This has been removed so that there is no requirement for gcc users to provide this flag themselves for their projects. A few minor issues that appeared as a consequence were fixed by inserting extra explicit conversions where needed. --- include/xvec/detail/mask.hpp | 9 ++++++++- include/xvec/detail/operators.hpp | 2 +- include/xvec/generic/generic_impl.hpp | 13 ++++++++----- include/xvec/x86/permute.hpp | 4 ++-- test/CMakeLists.txt | 1 - 5 files changed, 19 insertions(+), 10 deletions(-) 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()