diff --git a/sycl/include/sycl/detail/type_traits.hpp b/sycl/include/sycl/detail/type_traits.hpp index 46856ab03e544..fad5dda896ee7 100644 --- a/sycl/include/sycl/detail/type_traits.hpp +++ b/sycl/include/sycl/detail/type_traits.hpp @@ -24,10 +24,6 @@ template struct is_fixed_size_group : std::false_type {}; template inline constexpr bool is_fixed_size_group_v = is_fixed_size_group::value; - -template class OperationCurrentT, int... Indexes> -class SwizzleOp; } // namespace detail template class group; @@ -154,12 +150,20 @@ template struct get_elem_type_unqual> { template struct get_elem_type_unqual> { using type = T; }; +#if __SYCL_USE_LIBSYCL8_VEC_IMPL template class OperationCurrentT, int... Indexes> struct get_elem_type_unqual> { using type = typename get_elem_type_unqual>::type; }; +#else +template +struct get_elem_type_unqual> { + using type = DataT; +}; +#endif template diff --git a/sycl/include/sycl/detail/type_traits/vec_marray_traits.hpp b/sycl/include/sycl/detail/type_traits/vec_marray_traits.hpp index 7196a7ca4f868..afc2a676023b8 100644 --- a/sycl/include/sycl/detail/type_traits/vec_marray_traits.hpp +++ b/sycl/include/sycl/detail/type_traits/vec_marray_traits.hpp @@ -32,9 +32,16 @@ template class __SYCL_EBO vec; template class marray; namespace detail { +#if __SYCL_USE_LIBSYCL8_VEC_IMPL template class OperationCurrentT, int... Indexes> class SwizzleOp; +#else +namespace hide_swizzle_from_adl { +template +class __SYCL_EBO Swizzle; +} +#endif // Utility for converting a swizzle to a vector or preserve the type if it isn't // a swizzle. @@ -42,12 +49,20 @@ template struct simplify_if_swizzle { using type = T; }; +#if __SYCL_USE_LIBSYCL8_VEC_IMPL template class OperationCurrentT, int... Indexes> struct simplify_if_swizzle> { using type = vec; }; +#else +template +struct simplify_if_swizzle> { + using type = vec; +}; +#endif template using simplify_if_swizzle_t = typename simplify_if_swizzle::type; @@ -79,10 +94,17 @@ inline constexpr bool is_valid_type_for_ext_vector_v = is_valid_type_for_ext_vector::value; template struct is_swizzle : std::false_type {}; +#if __SYCL_USE_LIBSYCL8_VEC_IMPL template class OperationCurrentT, int... Indexes> struct is_swizzle> : std::true_type {}; +#else +template +struct is_swizzle> + : std::true_type {}; +#endif template constexpr bool is_swizzle_v = is_swizzle::value; template @@ -108,11 +130,18 @@ struct num_elements : std::integral_constant {}; #endif #endif +#if __SYCL_USE_LIBSYCL8_VEC_IMPL template class OperationCurrentT, int... Indexes> struct num_elements> : std::integral_constant {}; +#else +template +struct num_elements> + : std::integral_constant {}; +#endif template inline constexpr std::size_t num_elements_v = num_elements::value; diff --git a/sycl/include/sycl/detail/vector_arith.hpp b/sycl/include/sycl/detail/vector_arith.hpp index 6d92213e825e5..377605a391d67 100644 --- a/sycl/include/sycl/detail/vector_arith.hpp +++ b/sycl/include/sycl/detail/vector_arith.hpp @@ -16,11 +16,7 @@ namespace sycl { inline namespace _V1 { - -template class __SYCL_EBO vec; - namespace detail { - template struct from_incomplete; template struct from_incomplete : public from_incomplete {}; @@ -31,6 +27,33 @@ struct from_incomplete> { static constexpr size_t size() { return NumElements; } }; +#if !__SYCL_USE_LIBSYCL8_VEC_IMPL +template +struct from_incomplete< + hide_swizzle_from_adl::Swizzle> { + using element_type = DataT; + static constexpr size_t size() { return sizeof...(Indexes); } + + using vec_ty = std::conditional_t, + vec>; + using result_vec_ty = vec; + static constexpr int vec_size = VecSize; + static constexpr bool is_over_const_vec = IsConstVec; + static constexpr bool has_repeating_indexes = []() constexpr { + int Idxs[] = {Indexes...}; + for (std::size_t i = 1; i < sizeof...(Indexes); ++i) { + for (std::size_t j = 0; j < i; ++j) + if (Idxs[j] == Idxs[i]) + // Repeating index + return true; + } + + return false; + }(); + static constexpr bool is_assignable = !IsConstVec && !has_repeating_indexes; +}; +#endif + template struct ApplyIf {}; template struct ApplyIf : Mixin {}; @@ -477,6 +500,172 @@ template struct VecOperators { OpAssign, IncDec> {}; }; +#if !__SYCL_USE_LIBSYCL8_VEC_IMPL +template struct SwizzleOperators { + using element_type = typename from_incomplete::element_type; + using vec_ty = typename from_incomplete::result_vec_ty; + static constexpr int N = from_incomplete::size(); + + template + static constexpr bool is_compatible_scalar = + std::is_convertible_v::element_type> && + !is_swizzle_v; + + // Can't use partial specialization on constexpr variables because it took too + // long for gcc to fix https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71954 and + // we need to support older versions without the fix. + template + struct is_compatible_swizzle_impl : std::false_type {}; + + template + struct is_compatible_swizzle_impl< + OtherSwizzle, std::enable_if_t>> + : std::bool_constant< + std::is_same_v::element_type, + typename from_incomplete::element_type> && + from_incomplete::size() == + from_incomplete::size()> {}; + + template + static constexpr bool is_compatible_swizzle = + is_compatible_swizzle_impl::value; + + template + struct is_compatible_swizzle_opposite_const_impl : std::false_type {}; + + template + struct is_compatible_swizzle_opposite_const_impl< + OtherSwizzle, std::enable_if_t>> + : std::bool_constant && + from_incomplete::is_over_const_vec != + from_incomplete::is_over_const_vec> {}; + + template + static constexpr bool is_compatible_swizzle_opposite_const = + is_compatible_swizzle_opposite_const_impl::value; + + template + using result_t = std::conditional_t< + is_logical, vec, N>, vec_ty>; + + // Uglier than possible due to + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85282. + template struct OpMixin; + + template + struct OpMixin>> + : public IncDecImpl {}; + +#define __SYCL_SWIZZLE_BINOP_MIXIN(OP, OPERATOR) \ + template \ + struct OpMixin>> { \ + friend result_t operator OPERATOR(const Self & lhs, \ + const vec_ty & rhs) { \ + return OP{}(vec_ty{lhs}, rhs); \ + } \ + friend result_t operator OPERATOR(const vec_ty & lhs, \ + const Self & rhs) { \ + return OP{}(lhs, vec_ty{rhs}); \ + } \ + template \ + friend std::enable_if_t, result_t> \ + operator OPERATOR(const Self & lhs, const T & rhs) { \ + return OP{}(vec_ty{lhs}, vec_ty{rhs}); \ + } \ + template \ + friend std::enable_if_t, result_t> \ + operator OPERATOR(const T & lhs, const Self & rhs) { \ + return OP{}(vec_ty{lhs}, vec_ty{rhs}); \ + } \ + template \ + friend std::enable_if_t, result_t> \ + operator OPERATOR(const Self & lhs, const OtherSwizzle & rhs) { \ + return OP{}(vec_ty{lhs}, vec_ty{rhs}); \ + } \ + template \ + friend std::enable_if_t< \ + is_compatible_swizzle_opposite_const, result_t> \ + operator OPERATOR(const OtherSwizzle & lhs, const Self & rhs) { \ + return OP{}(vec_ty{lhs}, vec_ty{rhs}); \ + } \ + }; + +#define __SYCL_SWIZZLE_OPASSIGN_MIXIN(OP, OPERATOR) \ + template \ + struct OpMixin, std::enable_if_t>> { \ + friend const Self &operator OPERATOR(const Self & lhs, \ + const vec_ty & rhs) { \ + lhs = OP{}(vec_ty{lhs}, rhs); \ + return lhs; \ + } \ + template \ + friend std::enable_if_t, const Self &> \ + operator OPERATOR(const Self & lhs, const T & rhs) { \ + lhs = OP{}(vec_ty{lhs}, vec_ty{rhs}); \ + return lhs; \ + } \ + template \ + friend std::enable_if_t, const Self &> \ + operator OPERATOR(const Self & lhs, const OtherSwizzle & rhs) { \ + lhs = OP{}(vec_ty{lhs}, vec_ty{rhs}); \ + return lhs; \ + } \ + }; + +#define __SYCL_SWIZZLE_UOP_MIXIN(OP, OPERATOR) \ + template \ + struct OpMixin>> { \ + friend result_t operator OPERATOR(const Self & v) { \ + return OP{}(vec_ty{v}); \ + } \ + }; + + __SYCL_INSTANTIATE_OPERATORS(__SYCL_SWIZZLE_BINOP_MIXIN, + __SYCL_SWIZZLE_OPASSIGN_MIXIN, + __SYCL_SWIZZLE_UOP_MIXIN) + +#undef __SYCL_SWIZZLE_UOP_MIXIN +#undef __SYCL_SWIZZLE_OPASSIGN_MIXIN +#undef __SYCL_SWIZZLE_BINOP_MIXIN + + template + struct __SYCL_EBO CombineImpl + : ApplyIf, OpMixin>... {}; + + template + struct CombinedImpl + : CombineImpl, std::minus, std::multiplies, + std::divides, std::modulus, std::bit_and, + std::bit_or, std::bit_xor, std::equal_to, + std::not_equal_to, std::less, + std::greater, std::less_equal, + std::greater_equal, std::logical_and, + std::logical_or, ShiftLeft, ShiftRight, + std::negate, std::logical_not, + std::bit_not, UnaryPlus> {}; + + template + struct CombinedImpl<_Self, + std::enable_if_t::is_assignable>> + : CombineImpl, std::minus, std::multiplies, + std::divides, std::modulus, std::bit_and, + std::bit_or, std::bit_xor, std::equal_to, + std::not_equal_to, std::less, + std::greater, std::less_equal, + std::greater_equal, std::logical_and, + std::logical_or, ShiftLeft, ShiftRight, + std::negate, std::logical_not, + std::bit_not, UnaryPlus, OpAssign>, + OpAssign>, OpAssign>, + OpAssign>, OpAssign>, + OpAssign>, OpAssign>, + OpAssign>, OpAssign, + OpAssign, IncDec> {}; + + using Combined = CombinedImpl; +}; +#endif + #if __SYCL_USE_LIBSYCL8_VEC_IMPL template class vec_arith : public VecOperators>::Combined {}; diff --git a/sycl/include/sycl/vector.hpp b/sycl/include/sycl/vector.hpp index 556e91e7912ef..0f274566ebd91 100644 --- a/sycl/include/sycl/vector.hpp +++ b/sycl/include/sycl/vector.hpp @@ -232,6 +232,7 @@ template class vec_base { template class FlattenVecArg { template static constexpr auto helper(const T &V, std::index_sequence) { +#if __SYCL_USE_LIBSYCL8_VEC_IMPL // FIXME: Swizzle's `operator[]` for expression trees seems to be broken // and returns values of the underlying vector of some of the operands. On // the other hand, `getValue()` gives correct results. This can be changed @@ -239,6 +240,7 @@ template class vec_base { if constexpr (is_swizzle_v) return std::array{static_cast(V.getValue(Is))...}; else +#endif return std::array{static_cast(V[Is])...}; } @@ -300,17 +302,172 @@ template class vec_base { // Not `explicit` on purpose, differs from NumElements > 1. constexpr vec_base(const DataT &arg) : m_Data{{arg}} {} +}; + +template class ConversionToVecMixin { + using vec_ty = typename from_incomplete::result_vec_ty; + +public: + operator vec_ty() const { + vec_ty res{*static_cast(this)}; + return res; + } +}; + +template class SwizzleBase { + using VecT = typename from_incomplete::vec_ty; + +public: + explicit SwizzleBase(VecT &Vec) : Vec(Vec) {} + + const Self &operator=(const Self &) = delete; + +protected: + VecT &Vec; +}; + +template +class SwizzleBase::is_assignable>> { + using VecT = typename from_incomplete::vec_ty; + using ResultVecT = typename from_incomplete::result_vec_ty; + + using DataT = typename from_incomplete::element_type; + static constexpr int N = from_incomplete::size(); + +public: + explicit SwizzleBase(VecT &Vec) : Vec(Vec) {} + + template + void load(size_t offset, + multi_ptr ptr) const { + ResultVecT v; + v.load(offset, ptr); + *static_cast(this) = v; + } + + template + std::enable_if_t + operator=(const detail::hide_swizzle_from_adl::Swizzle< + OtherIsConstVec, DataT, OtherVecSize, OtherIndexes...> &rhs) { + return (*this = static_cast(rhs)); + } + + const Self &operator=(const ResultVecT &rhs) const { + for (int i = 0; i < N; ++i) + (*static_cast(this))[i] = rhs[i]; + + return *static_cast(this); + } + + template && + !is_swizzle_v>> + const Self &operator=(const T &rhs) const { + for (int i = 0; i < N; ++i) + (*static_cast(this))[i] = static_cast(rhs); + + return *static_cast(this); + } + + // Default copy-assignment. Self's implicitly generated copy-assignment uses + // this. + // + // We're templated on "Self", so each swizzle has its own SwizzleBase and the + // following is ok (1-to-1 bidirectional mapping between Self and its + // SwizzleBase instantiation) even if a bit counterintuitive. + const SwizzleBase &operator=(const SwizzleBase &rhs) const { + const Self &self = (*static_cast(this)); + self = static_cast(static_cast(rhs)); + return self; + } + +protected: + VecT &Vec; +}; + +namespace hide_swizzle_from_adl { +// Can't have sycl::vec anywhere in template parameters because that would bring +// its hidden friends into ADL. Put it in a dedicated namespace to avoid +// anything extra via ADL as well. +template +class __SYCL_EBO Swizzle + : public SwizzleBase>, + public SwizzleOperators< + Swizzle>::Combined, + public ApplyIf>>, + public ApplyIf>>, + public NamedSwizzlesMixinBoth< + Swizzle> { + using Base = SwizzleBase>; + + static constexpr int NumElements = sizeof...(Indexes); + using ResultVec = vec; + + // Get underlying vec index for (*this)[idx] access. + static constexpr auto get_vec_idx(int idx) { + int counter = 0; + int result = -1; + ((result = counter++ == idx ? Indexes : result), ...); + return result; + } + +public: + using Base::Base; + using Base::operator=; + + using element_type = DataT; + using value_type = DataT; + +#ifdef __SYCL_DEVICE_ONLY__ + using vector_t = typename vec::vector_t; +#endif // __SYCL_DEVICE_ONLY__ + + Swizzle() = delete; + Swizzle(const Swizzle &) = delete; + + static constexpr size_t byte_size() noexcept { + return ResultVec::byte_size(); + } + static constexpr size_t size() noexcept { return ResultVec::size(); } + + __SYCL2020_DEPRECATED( + "get_size() is deprecated, please use byte_size() instead") + size_t get_size() const { return static_cast(*this).get_size(); } + + __SYCL2020_DEPRECATED("get_count() is deprecated, please use size() instead") + size_t get_count() const { + return static_cast(*this).get_count(); + }; + + template + vec convert() const { + return static_cast(*this) + .template convert(); + } + + template asT as() const { + return static_cast(*this).template as(); + } + + template + void store(size_t offset, + multi_ptr ptr) const { + return static_cast(*this).store(offset, ptr); + } - // FIXME: Temporary workaround because swizzle's `operator DataT` is a - // template. - template >, - typename = std::enable_if_t, - typename = std::enable_if< - std::is_convertible_v>> - constexpr vec_base(const Swizzle &other) - : vec_base(static_cast(other)) {} + template auto swizzle() const { + return this->Vec.template swizzle(); + } + + auto &operator[](int index) const { return this->Vec[get_vec_idx(index)]; } }; +} // namespace hide_swizzle_from_adl #endif } // namespace detail @@ -385,6 +542,7 @@ class __SYCL_EBO vec : private: #endif // __SYCL_DEVICE_ONLY__ +#if __SYCL_USE_LIBSYCL8_VEC_IMPL template using Swizzle = detail::SwizzleOp, detail::GetOp, @@ -394,6 +552,17 @@ class __SYCL_EBO vec : using ConstSwizzle = detail::SwizzleOp, detail::GetOp, detail::GetOp, Indexes...>; +#else + template + using Swizzle = + detail::hide_swizzle_from_adl::Swizzle; + + template + using ConstSwizzle = + detail::hide_swizzle_from_adl::Swizzle; +#endif // Element type for relational operator return value. using rel_t = detail::fixed_width_signed; @@ -479,12 +648,20 @@ class __SYCL_EBO vec : template asT as() const { return sycl::bit_cast(*this); } template Swizzle swizzle() { +#if __SYCL_USE_LIBSYCL8_VEC_IMPL return this; +#else + return Swizzle{*this}; +#endif } template ConstSwizzle swizzle() const { +#if __SYCL_USE_LIBSYCL8_VEC_IMPL return this; +#else + return ConstSwizzle{*this}; +#endif } const DataT &operator[](int i) const { return this->m_Data[i]; } @@ -563,6 +740,7 @@ template vec; #endif +#if __SYCL_USE_LIBSYCL8_VEC_IMPL namespace detail { // Special type for working SwizzleOp with scalars, stores a scalar and gives @@ -1398,5 +1576,6 @@ class SwizzleOp : public detail::NamedSwizzlesMixinBoth< }; ///////////////////////// class SwizzleOp ///////////////////////// } // namespace detail +#endif } // namespace _V1 } // namespace sycl diff --git a/sycl/test/basic_tests/vectors/assign.cpp b/sycl/test/basic_tests/vectors/assign.cpp index 2045eca0303e3..115bb9af9f2dd 100644 --- a/sycl/test/basic_tests/vectors/assign.cpp +++ b/sycl/test/basic_tests/vectors/assign.cpp @@ -33,8 +33,8 @@ static_assert( std::is_assignable_v, vec> static_assert(EXCEPT_IN_PREVIEW std::is_assignable_v, vec>); static_assert(EXCEPT_IN_PREVIEW std::is_assignable_v, vec>); static_assert( std::is_assignable_v, sw_half_1>); -static_assert( std::is_assignable_v, sw_float_1>); -static_assert( std::is_assignable_v, sw_double_1>); +static_assert(EXCEPT_IN_PREVIEW std::is_assignable_v, sw_float_1>); +static_assert(EXCEPT_IN_PREVIEW std::is_assignable_v, sw_double_1>); static_assert( !std::is_assignable_v, sw_half_2>); static_assert( !std::is_assignable_v, sw_float_2>); static_assert( !std::is_assignable_v, sw_double_2>); @@ -46,8 +46,8 @@ static_assert( std::is_assignable_v, vec> static_assert( !std::is_assignable_v, vec>); static_assert( !std::is_assignable_v, vec>); static_assert( std::is_assignable_v, sw_half_1>); -static_assert( std::is_assignable_v, sw_float_1>); -static_assert( std::is_assignable_v, sw_double_1>); +static_assert(EXCEPT_IN_PREVIEW std::is_assignable_v, sw_float_1>); +static_assert(EXCEPT_IN_PREVIEW std::is_assignable_v, sw_double_1>); static_assert( std::is_assignable_v, sw_half_2>); static_assert( !std::is_assignable_v, sw_float_2>); static_assert( !std::is_assignable_v, sw_double_2>); @@ -62,7 +62,7 @@ static_assert(EXCEPT_IN_PREVIEW std::is_assignable_v, vec #endif static_assert( std::is_assignable_v, vec>); static_assert( std::is_assignable_v, vec>); -static_assert( std::is_assignable_v, sw_half_1>); +static_assert(EXCEPT_IN_PREVIEW std::is_assignable_v, sw_half_1>); static_assert( std::is_assignable_v, sw_float_1>); static_assert( std::is_assignable_v, sw_double_1>); static_assert( !std::is_assignable_v, sw_half_2>); @@ -79,7 +79,7 @@ static_assert( !std::is_assignable_v, vec #endif static_assert( std::is_assignable_v, vec>); static_assert( std::is_assignable_v, vec>); -static_assert( std::is_assignable_v, sw_half_1>); +static_assert(EXCEPT_IN_PREVIEW std::is_assignable_v, sw_half_1>); static_assert( std::is_assignable_v, sw_float_1>); static_assert( std::is_assignable_v, sw_double_1>); static_assert( !std::is_assignable_v, sw_half_2>); diff --git a/sycl/test/basic_tests/vectors/cxx_conversions.cpp b/sycl/test/basic_tests/vectors/cxx_conversions.cpp index b59adc718c31f..4973b07cd00db 100644 --- a/sycl/test/basic_tests/vectors/cxx_conversions.cpp +++ b/sycl/test/basic_tests/vectors/cxx_conversions.cpp @@ -53,9 +53,9 @@ using sw_double_2 = decltype(std::declval>().swizzle<1, 2>()); static_assert( std::is_invocable_v); static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v); static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v); -static_assert( std::is_invocable_v); -static_assert( std::is_invocable_v); -static_assert( std::is_invocable_v); +static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v); +static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v); +static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v); static_assert( std::is_invocable_v>); static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v>); static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v>); @@ -63,9 +63,9 @@ static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v); static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); -static_assert( std::is_invocable_v); -static_assert( std::is_invocable_v); -static_assert( std::is_invocable_v); +static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v); +static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v); +static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v); static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v>); static_assert( std::is_invocable_v>); static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v>); diff --git a/sycl/test/basic_tests/vectors/swizzle.cpp b/sycl/test/basic_tests/vectors/swizzle.cpp index 2c6ce60331dc8..4de5fde499c5c 100644 --- a/sycl/test/basic_tests/vectors/swizzle.cpp +++ b/sycl/test/basic_tests/vectors/swizzle.cpp @@ -9,8 +9,12 @@ int main() { assert(sw.lo()[0] == 2); assert(sw.hi()[0] == 3); +#if __SYCL_USE_LIBSYCL8_VEC_IMPL // FIXME: Should be "4": assert((sw + sw).lo()[0] == 2); +#else + assert((sw + sw).lo()[0] == 4); +#endif assert(sw.swizzle<0>()[0] == 2); assert(sw.swizzle<1>()[0] == 3); @@ -24,9 +28,14 @@ int main() { { auto tmp = (sw + sw).swizzle<1, 0>(); +#if __SYCL_USE_LIBSYCL8_VEC_IMPL // FIXME: Should be "6" and "4", respectively. assert(tmp[0] == 3); assert(tmp[1] == 2); +#else + assert(tmp[0] == 6); + assert(tmp[1] == 4); +#endif } return 0;