Skip to content

[SYCL] Fix vec constructors #17712

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 1, 2025
Merged
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
12 changes: 12 additions & 0 deletions sycl/include/sycl/detail/type_traits/vec_marray_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@

#include <sycl/detail/defines_elementary.hpp>

#ifndef __SYCL_USE_LIBSYCL8_VEC_IMPL
#if defined(__INTEL_PREVIEW_BREAKING_CHANGES)
// Several specification changes need to be implemented together to keep CTS
// passing. We'll switch to `0` once they all land.
// `__SYCL_USE_PLAIN_ARRAY_AS_VEC_STORAGE` needs to be changed to use this
// `__SYCL_USE_LIBSYCL8_VEC_IMPL` at that time as well.
#define __SYCL_USE_LIBSYCL8_VEC_IMPL 1
#else
#define __SYCL_USE_LIBSYCL8_VEC_IMPL 1
#endif
#endif

namespace sycl {
inline namespace _V1 {
template <typename DataT, int NumElements> class __SYCL_EBO vec;
Expand Down
55 changes: 42 additions & 13 deletions sycl/include/sycl/vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,19 +137,11 @@ inline constexpr bool is_fundamental_or_half_or_bfloat16 =
std::is_fundamental_v<T> || std::is_same_v<std::remove_const_t<T>, half> ||
std::is_same_v<std::remove_const_t<T>, ext::oneapi::bfloat16>;

// Proposed SYCL specification changes have sycl::vec having different ctors
// available based on the number of elements. Without C++20's concepts we'll
// have to use partial specialization to represent that. This is a helper to do
// that. An alternative could be to have different specializations of the
// `sycl::vec` itself but then we'd need to outline all the common interfaces to
// re-use them.
//
// Note: the functional changes haven't been implemented yet, we've split
// vec_base in advance as a way to make changes easier to review/verify.
//
// Another note: `vector_t` is going to be removed, so corresponding ctor was
// kept inside `sycl::vec` to have all `vector_t` functionality in a single
// place.
// Per SYCL specification sycl::vec has different ctors available based on the
// number of elements. Without C++20's concepts we'd have to use partial
// specialization to represent that. This is a helper to do that. An alternative
// could be to have different specializations of the `sycl::vec` itself but then
// we'd need to outline all the common interfaces to re-use them.
template <typename DataT, int NumElements> class vec_base {
// https://registry.khronos.org/SYCL/specs/sycl-2020/html/sycl-2020.html#memory-layout-and-alignment
// It is required by the SPEC to align vec<DataT, 3> with vec<DataT, 4>.
Expand Down Expand Up @@ -271,6 +263,43 @@ template <typename DataT, int NumElements> class vec_base {
: vec_base{VecArgArrayCreator<DataT, argTN...>::Create(args...),
std::make_index_sequence<NumElements>()} {}
};

#if !__SYCL_USE_LIBSYCL8_VEC_IMPL
template <typename DataT> class vec_base<DataT, 1> {
using DataType = std::conditional_t<
#if __SYCL_USE_PLAIN_ARRAY_AS_VEC_STORAGE
true,
#else
sizeof(std::array<DataT, 1>) == sizeof(DataT[1]) &&
alignof(std::array<DataT, 1>) == alignof(DataT[1]),
#endif
DataT[1], std::array<DataT, 1>>;

protected:
static constexpr int alignment = (std::min)((size_t)64, sizeof(DataType));
alignas(alignment) DataType m_Data{};

public:
constexpr vec_base() = default;
constexpr vec_base(const vec_base &) = default;
constexpr vec_base(vec_base &&) = default;
constexpr vec_base &operator=(const vec_base &) = default;
constexpr vec_base &operator=(vec_base &&) = default;

// Not `explicit` on purpose, differs from NumElements > 1.
constexpr vec_base(const DataT &arg) : m_Data{{arg}} {}

// FIXME: Temporary workaround because swizzle's `operator DataT` is a
// template.
template <typename Swizzle,
typename = std::enable_if_t<is_swizzle_v<Swizzle>>,
typename = std::enable_if_t<Swizzle::size() == 1>,
typename = std::enable_if<
std::is_convertible_v<typename Swizzle::element_type, DataT>>>
constexpr vec_base(const Swizzle &other)
: vec_base(static_cast<DataT>(other)) {}
};
#endif
} // namespace detail

///////////////////////// class sycl::vec /////////////////////////
Expand Down
24 changes: 16 additions & 8 deletions sycl/test/basic_tests/vectors/assign.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clangxx -fsycl -fsyntax-only %s -fpreview-breaking-changes
// TODO: Remove `__SYCL_USE_LIBSYCL8_VEC_IMPL` once it's auto-set.
// RUN: %clangxx -fsycl -fsyntax-only %s -fpreview-breaking-changes -D__SYCL_USE_LIBSYCL8_VEC_IMPL=0
// RUN: %clangxx -fsycl -fsyntax-only %s

#include <sycl/sycl.hpp>
Expand All @@ -14,20 +15,23 @@ using sw_float_2 = decltype(std::declval<vec<float, 4>>().swizzle<1, 2>());
using sw_double_1 = decltype(std::declval<vec<double, 4>>().swizzle<1>());
using sw_double_2 = decltype(std::declval<vec<double, 4>>().swizzle<1, 2>());

// clang-format off
#if __INTEL_PREVIEW_BREAKING_CHANGES
#define EXCEPT_IN_PREVIEW !
#else
#define EXCEPT_IN_PREVIEW
#endif

// NOTE: Empty space is for the future markup using NOT_IN_PREVIEW/PREVIEW_ONLY
// macros.
// clang-format off

// IN_PREVIEW_ONLY condition<>
// EXCEPT_IN_PREVIEW condition<>

static_assert( std::is_assignable_v<vec<half, 1>, half>);
static_assert( std::is_assignable_v<vec<half, 1>, float>);
static_assert( std::is_assignable_v<vec<half, 1>, double>);
static_assert(EXCEPT_IN_PREVIEW std::is_assignable_v<vec<half, 1>, float>);
static_assert(EXCEPT_IN_PREVIEW std::is_assignable_v<vec<half, 1>, double>);
static_assert( std::is_assignable_v<vec<half, 1>, vec<half, 1>>);
static_assert( std::is_assignable_v<vec<half, 1>, vec<float, 1>>);
static_assert( std::is_assignable_v<vec<half, 1>, vec<double, 1>>);
static_assert(EXCEPT_IN_PREVIEW std::is_assignable_v<vec<half, 1>, vec<float, 1>>);
static_assert(EXCEPT_IN_PREVIEW std::is_assignable_v<vec<half, 1>, vec<double, 1>>);
static_assert( std::is_assignable_v<vec<half, 1>, sw_half_1>);
static_assert( std::is_assignable_v<vec<half, 1>, sw_float_1>);
static_assert( std::is_assignable_v<vec<half, 1>, sw_double_1>);
Expand All @@ -51,7 +55,11 @@ static_assert( !std::is_assignable_v<vec<half, 2>, sw_double_2>)
static_assert( std::is_assignable_v<vec<float, 1>, half>);
static_assert( std::is_assignable_v<vec<float, 1>, float>);
static_assert( std::is_assignable_v<vec<float, 1>, double>);
#if __SYCL_DEVICE_ONLY__
static_assert( std::is_assignable_v<vec<float, 1>, vec<half, 1>>);
#else
static_assert(EXCEPT_IN_PREVIEW std::is_assignable_v<vec<float, 1>, vec<half, 1>>);
#endif
static_assert( std::is_assignable_v<vec<float, 1>, vec<float, 1>>);
static_assert( std::is_assignable_v<vec<float, 1>, vec<double, 1>>);
static_assert( std::is_assignable_v<vec<float, 1>, sw_half_1>);
Expand Down
27 changes: 15 additions & 12 deletions sycl/test/basic_tests/vectors/cxx_conversions.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clangxx -fsycl -fsyntax-only %s -fpreview-breaking-changes
// TODO: Remove `__SYCL_USE_LIBSYCL8_VEC_IMPL` once it's auto-set.
// RUN: %clangxx -fsycl -fsyntax-only %s -fpreview-breaking-changes -D__SYCL_USE_LIBSYCL8_VEC_IMPL=0
// RUN: %clangxx -fsycl -fsyntax-only %s

#include <sycl/sycl.hpp>
Expand Down Expand Up @@ -36,34 +37,36 @@ using sw_float_2 = decltype(std::declval<vec<float, 4>>().swizzle<1, 2>());
using sw_double_1 = decltype(std::declval<vec<double, 4>>().swizzle<1>());
using sw_double_2 = decltype(std::declval<vec<double, 4>>().swizzle<1, 2>());

// clang-format off

// NOTE: Empty space is for the future markup using NOT_IN_PREVIEW/PREVIEW_ONLY
// macros.
#if __INTEL_PREVIEW_BREAKING_CHANGES
#define EXCEPT_IN_PREVIEW !
#else
#define EXCEPT_IN_PREVIEW
#endif

// clang-format off

// IN_PREVIEW_ONLY condition<>
// EXCEPT_IN_PREVIEW condition<>

static_assert( std::is_invocable_v<decltype(f_half_v1), half>);
static_assert( std::is_invocable_v<decltype(f_half_v1), float>);
static_assert( std::is_invocable_v<decltype(f_half_v1), double>);
static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v<decltype(f_half_v1), float>);
static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v<decltype(f_half_v1), double>);
static_assert( std::is_invocable_v<decltype(f_half_v1), sw_half_1>);
static_assert( std::is_invocable_v<decltype(f_half_v1), sw_float_1>);
static_assert( std::is_invocable_v<decltype(f_half_v1), sw_double_1>);
static_assert( std::is_invocable_v<decltype(f_half_v1), vec<half, 1>>);
static_assert( std::is_invocable_v<decltype(f_half_v1), vec<float, 1>>);
static_assert( std::is_invocable_v<decltype(f_half_v1), vec<double, 1>>);
static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v<decltype(f_half_v1), vec<float, 1>>);
static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v<decltype(f_half_v1), vec<double, 1>>);

static_assert( std::is_invocable_v<decltype(f_float_v1), half>);
static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v<decltype(f_float_v1), half>);
static_assert( std::is_invocable_v<decltype(f_float_v1), float>);
static_assert( std::is_invocable_v<decltype(f_float_v1), double>);
static_assert( std::is_invocable_v<decltype(f_float_v1), sw_half_1>);
static_assert( std::is_invocable_v<decltype(f_float_v1), sw_float_1>);
static_assert( std::is_invocable_v<decltype(f_float_v1), sw_double_1>);
static_assert( std::is_invocable_v<decltype(f_float_v1), vec<half, 1>>);
static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v<decltype(f_float_v1), vec<half, 1>>);
static_assert( std::is_invocable_v<decltype(f_float_v1), vec<float, 1>>);
static_assert( std::is_invocable_v<decltype(f_float_v1), vec<double, 1>>);
static_assert(EXCEPT_IN_PREVIEW std::is_invocable_v<decltype(f_float_v1), vec<double, 1>>);

static_assert( !std::is_invocable_v<decltype(f_half_v4), half>);
static_assert( !std::is_invocable_v<decltype(f_half_v4), float>);
Expand Down
Loading