Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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_PREVIEW_VEC_IMPL
#if defined(__INTEL_PREVIEW_BREAKING_CHANGES)
// Several specification changes need to be implemented together to keep CTS
// passing. We'll switch to `1` once they all land.
// `__SYCL_USE_PLAIN_ARRAY_AS_VEC_STORAGE` needs to be changed to use this
// `__SYCL_USE_PREVIEW_VEC_IMPL` at that time as well.
#define __SYCL_USE_PREVIEW_VEC_IMPL 0
#else
#define __SYCL_USE_PREVIEW_VEC_IMPL 0
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AlexeySachkov , any better suggestions for the naming here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One issue is that we want to preserve current/"old" version after next major release, when the meaning of "preview" would change. On the other hand, we can rename the macro at that time, maybe.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One issue is that we want to preserve current/"old" version after next major release, when the meaning of "preview" would change. On the other hand, we can rename the macro at that time, maybe.

If we plan to expose the macro to users so that they could do a switch back (for whichever reason), then it is better not to rename it later, but agree on a name from the beginning - otherwise renaming would be an API change by itself.

What about something like __SYCL_USE_SYCL2020_CONFORMANT_IMPL? I.e. indicate the intent instead of old/new where the meaning of old/new changes in time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SYCL2020 has had several different specifications for vec. I've come up with __SYCL_USE_LEGACY_VEC_IMPL (meaning the current default). Alternatively, we can use the current major version (__SYCL_USE_SYCL8_VEC_IMPL).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AlexeySachkov , can you take another look?

#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_PREVIEW_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
84 changes: 84 additions & 0 deletions sycl/test/basic_tests/vectors/assign.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// TODO: Remove `__SYCL_USE_PREVIEW_VEC_IMPL` once it's auto-set.
// RUN: %clangxx -fsycl -fsyntax-only %s -fpreview-breaking-changes -D__SYCL_USE_PREVIEW_VEC_IMPL=1
// RUN: %clangxx -fsycl -fsyntax-only %s

#include <sycl/sycl.hpp>

using sycl::half;
using sycl::vec;
using sw_half_1 = decltype(std::declval<vec<half, 4>>().swizzle<1>());
using sw_half_2 = decltype(std::declval<vec<half, 4>>().swizzle<1, 2>());

using sw_float_1 = decltype(std::declval<vec<float, 4>>().swizzle<1>());
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>());

#if __INTEL_PREVIEW_BREAKING_CHANGES
#define NOT_IN_PREVIEW !
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT; how about we rename this macro to something like NEGATE_IF_NOT_IN_PREVIEW ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how it would help, honestly. This isn't "! in preview", but rather simply English, like "hey this holds, except not in preview".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't "! in preview", but rather simply English, like "hey this holds, except not in preview".

Initially, I had the same confusion. That's why I'd have renamed this macro to NEGATE_IF_NOT_IN_PREVIEW or something. Anyway, I don't have strong opinion on this.

#else
#define NOT_IN_PREVIEW
#endif

// clang-format off

static_assert( std::is_assignable_v<vec<half, 1>, half>);
static_assert(NOT_IN_PREVIEW std::is_assignable_v<vec<half, 1>, float>);
static_assert(NOT_IN_PREVIEW std::is_assignable_v<vec<half, 1>, double>);
static_assert( std::is_assignable_v<vec<half, 1>, vec<half, 1>>);
static_assert(NOT_IN_PREVIEW std::is_assignable_v<vec<half, 1>, vec<float, 1>>);
static_assert(NOT_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>);
static_assert( !std::is_assignable_v<vec<half, 1>, sw_half_2>);
static_assert( !std::is_assignable_v<vec<half, 1>, sw_float_2>);
static_assert( !std::is_assignable_v<vec<half, 1>, sw_double_2>);

static_assert( std::is_assignable_v<vec<half, 2>, half>);
static_assert( std::is_assignable_v<vec<half, 2>, float>);
static_assert( std::is_assignable_v<vec<half, 2>, double>);
static_assert( std::is_assignable_v<vec<half, 2>, vec<half, 1>>);
static_assert( !std::is_assignable_v<vec<half, 2>, vec<float, 1>>);
static_assert( !std::is_assignable_v<vec<half, 2>, vec<double, 1>>);
static_assert( std::is_assignable_v<vec<half, 2>, sw_half_1>);
static_assert( std::is_assignable_v<vec<half, 2>, sw_float_1>);
static_assert( std::is_assignable_v<vec<half, 2>, sw_double_1>);
static_assert( std::is_assignable_v<vec<half, 2>, sw_half_2>);
static_assert( !std::is_assignable_v<vec<half, 2>, sw_float_2>);
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(NOT_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>);
static_assert( std::is_assignable_v<vec<float, 1>, sw_float_1>);
static_assert( std::is_assignable_v<vec<float, 1>, sw_double_1>);
static_assert( !std::is_assignable_v<vec<float, 1>, sw_half_2>);
static_assert( !std::is_assignable_v<vec<float, 1>, sw_float_2>);
static_assert( !std::is_assignable_v<vec<float, 1>, sw_double_2>);

static_assert( std::is_assignable_v<vec<float, 2>, half>);
static_assert( std::is_assignable_v<vec<float, 2>, float>);
static_assert( std::is_assignable_v<vec<float, 2>, double>);
#if __SYCL_DEVICE_ONLY__
static_assert( std::is_assignable_v<vec<float, 2>, vec<half, 1>>);
#else
static_assert( !std::is_assignable_v<vec<float, 2>, vec<half, 1>>);
#endif
static_assert( std::is_assignable_v<vec<float, 2>, vec<float, 1>>);
static_assert( std::is_assignable_v<vec<float, 2>, vec<double, 1>>);
static_assert( std::is_assignable_v<vec<float, 2>, sw_half_1>);
static_assert( std::is_assignable_v<vec<float, 2>, sw_float_1>);
static_assert( std::is_assignable_v<vec<float, 2>, sw_double_1>);
static_assert( !std::is_assignable_v<vec<float, 2>, sw_half_2>);
static_assert( std::is_assignable_v<vec<float, 2>, sw_float_2>);
static_assert( !std::is_assignable_v<vec<float, 2>, sw_double_2>);
134 changes: 134 additions & 0 deletions sycl/test/basic_tests/vectors/cxx_conversions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// TODO: Remove `__SYCL_USE_PREVIEW_VEC_IMPL` once it's auto-set.
// RUN: %clangxx -fsycl -fsyntax-only %s -fpreview-breaking-changes -D__SYCL_USE_PREVIEW_VEC_IMPL=1
// RUN: %clangxx -fsycl -fsyntax-only %s

#include <sycl/sycl.hpp>

template <class From, class To, class = void>
struct is_explicitly_convertible_to_impl : std::false_type {};

template <class From, class To>
struct is_explicitly_convertible_to_impl<
From, To, std::void_t<decltype(static_cast<To>(std::declval<From>()))>>
: std::true_type {};

template <class From, class To>
struct is_explicitly_convertible_to
: is_explicitly_convertible_to_impl<From, To> {};

template <class From, class To>
inline constexpr bool is_explicitly_convertible_to_v =
is_explicitly_convertible_to<From, To>::value;

using sycl::half;
using sycl::vec;

void f_half_v1(vec<half, 1>);
void f_half_v4(vec<half, 4>);
void f_float_v1(vec<float, 1>);
void f_float_v4(vec<float, 4>);

using sw_half_1 = decltype(std::declval<vec<half, 4>>().swizzle<1>());
using sw_half_2 = decltype(std::declval<vec<half, 4>>().swizzle<1, 2>());

using sw_float_1 = decltype(std::declval<vec<float, 4>>().swizzle<1>());
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>());

#if __INTEL_PREVIEW_BREAKING_CHANGES
#define NOT_IN_PREVIEW !
#else
#define NOT_IN_PREVIEW
#endif

// clang-format off

static_assert( std::is_invocable_v<decltype(f_half_v1), half>);
static_assert(NOT_IN_PREVIEW std::is_invocable_v<decltype(f_half_v1), float>);
static_assert(NOT_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(NOT_IN_PREVIEW std::is_invocable_v<decltype(f_half_v1), vec<float, 1>>);
static_assert(NOT_IN_PREVIEW std::is_invocable_v<decltype(f_half_v1), vec<double, 1>>);

static_assert(NOT_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(NOT_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(NOT_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>);
static_assert( !std::is_invocable_v<decltype(f_half_v4), double>);
static_assert( !std::is_invocable_v<decltype(f_half_v4), sw_half_1>);
static_assert( !std::is_invocable_v<decltype(f_half_v4), sw_float_1>);
static_assert( !std::is_invocable_v<decltype(f_half_v4), sw_double_1>);
static_assert( !std::is_invocable_v<decltype(f_half_v4), sw_half_2, sw_half_2>);
static_assert( !std::is_invocable_v<decltype(f_half_v4), sw_float_2, sw_float_2>);
static_assert( !std::is_invocable_v<decltype(f_half_v4), sw_double_2, sw_double_2>);
static_assert( !std::is_invocable_v<decltype(f_half_v4), sw_half_2, sw_float_2>);
static_assert( !std::is_invocable_v<decltype(f_half_v4), sw_half_2, sw_double_2>);

static_assert( !std::is_invocable_v<decltype(f_float_v4), half>);
static_assert( !std::is_invocable_v<decltype(f_float_v4), float>);
static_assert( !std::is_invocable_v<decltype(f_float_v4), double>);
static_assert( !std::is_invocable_v<decltype(f_float_v4), sw_half_1>);
static_assert( !std::is_invocable_v<decltype(f_float_v4), sw_float_1>);
static_assert( !std::is_invocable_v<decltype(f_float_v4), sw_double_1>);
static_assert( !std::is_invocable_v<decltype(f_float_v4), sw_half_2, sw_half_2>);
static_assert( !std::is_invocable_v<decltype(f_float_v4), sw_float_2, sw_float_2>);
static_assert( !std::is_invocable_v<decltype(f_float_v4), sw_double_2, sw_double_2>);
static_assert( !std::is_invocable_v<decltype(f_float_v4), sw_float_2, sw_float_2>);
static_assert( !std::is_invocable_v<decltype(f_float_v4), sw_float_2, sw_double_2>);

static_assert( is_explicitly_convertible_to_v<half, vec<half, 1>>);
static_assert( is_explicitly_convertible_to_v<float, vec<half, 1>>);
static_assert( is_explicitly_convertible_to_v<double, vec<half, 1>>);
static_assert( is_explicitly_convertible_to_v<sw_half_1, vec<half, 1>>);
static_assert( is_explicitly_convertible_to_v<sw_float_1, vec<half, 1>>);
static_assert( is_explicitly_convertible_to_v<sw_double_1, vec<half, 1>>);

static_assert( is_explicitly_convertible_to_v<half, vec<float, 1>>);
static_assert( is_explicitly_convertible_to_v<float, vec<float, 1>>);
static_assert( is_explicitly_convertible_to_v<double, vec<float, 1>>);
static_assert( is_explicitly_convertible_to_v<sw_half_1, vec<float, 1>>);
static_assert( is_explicitly_convertible_to_v<sw_float_1, vec<float, 1>>);
static_assert( is_explicitly_convertible_to_v<sw_double_1, vec<float, 1>>);

static_assert( is_explicitly_convertible_to_v<half, vec<half, 4>>);
static_assert( is_explicitly_convertible_to_v<float, vec<half, 4>>);
static_assert( is_explicitly_convertible_to_v<double, vec<half, 4>>);
static_assert( is_explicitly_convertible_to_v<sw_half_1, vec<half, 4>>);
static_assert( is_explicitly_convertible_to_v<sw_float_1, vec<half, 4>>);
static_assert( is_explicitly_convertible_to_v<sw_double_1, vec<half, 4>>);
static_assert( !is_explicitly_convertible_to_v<sw_half_2, vec<half, 4>>);
static_assert( !is_explicitly_convertible_to_v<sw_float_2, vec<half, 4>>);
static_assert( !is_explicitly_convertible_to_v<sw_double_2, vec<half, 4>>);
static_assert( !is_explicitly_convertible_to_v<sw_half_2, vec<half, 4>>);
static_assert( !is_explicitly_convertible_to_v<sw_half_2, vec<half, 4>>);
static_assert( is_explicitly_convertible_to_v<sw_half_2, vec<half, 2>>);
static_assert( !is_explicitly_convertible_to_v<sw_float_2, vec<half, 2>>);
static_assert( !is_explicitly_convertible_to_v<sw_double_2, vec<half, 2>>);
static_assert( is_explicitly_convertible_to_v<sw_half_2, vec<half, 2>>);
static_assert( is_explicitly_convertible_to_v<sw_half_2, vec<half, 2>>);

static_assert( is_explicitly_convertible_to_v<vec<half, 1>, half>);
#if __SYCL_DEVICE_ONLY__
static_assert( is_explicitly_convertible_to_v<vec<half, 1>, float>);
static_assert( is_explicitly_convertible_to_v<vec<half, 1>, double>);
#else
static_assert( !is_explicitly_convertible_to_v<vec<half, 1>, float>);
static_assert( !is_explicitly_convertible_to_v<vec<half, 1>, double>);
#endif

static_assert( is_explicitly_convertible_to_v<vec<float, 1>, half>);
static_assert( is_explicitly_convertible_to_v<vec<float, 1>, float>);
static_assert( is_explicitly_convertible_to_v<vec<float, 1>, double>);