From 17bf4b68973a2902d07e03791aa3322de8182e78 Mon Sep 17 00:00:00 2001 From: Mariya Podchishchaeva Date: Fri, 5 Apr 2019 13:53:01 +0300 Subject: [PATCH 1/2] [SYCL] Add support for half type Signed-off-by: Mariya Podchishchaeva --- sycl/CMakeLists.txt | 1 + sycl/include/CL/sycl/half_type.hpp | 84 +++++++ sycl/include/CL/sycl/intel/sub_group.hpp | 21 +- sycl/include/CL/sycl/types.hpp | 285 +++++++++++++++++------ sycl/source/half_type.cpp | 189 +++++++++++++++ sycl/test/basic_tests/half_type.cpp | 184 +++++++++++++++ sycl/test/lit.cfg | 1 + sycl/test/sub_group/helper.hpp | 8 + sycl/test/sub_group/load_store.cpp | 15 +- sycl/test/sub_group/shuffle.cpp | 13 +- 10 files changed, 718 insertions(+), 83 deletions(-) create mode 100644 sycl/include/CL/sycl/half_type.hpp create mode 100644 sycl/source/half_type.cpp create mode 100644 sycl/test/basic_tests/half_type.cpp diff --git a/sycl/CMakeLists.txt b/sycl/CMakeLists.txt index 14ac967d233d8..57b66b2185227 100644 --- a/sycl/CMakeLists.txt +++ b/sycl/CMakeLists.txt @@ -99,6 +99,7 @@ add_library("${SYCLLibrary}" SHARED "${sourceRootPath}/device_selector.cpp" "${sourceRootPath}/event.cpp" "${sourceRootPath}/exception.cpp" + "${sourceRootPath}/half_type.cpp" "${sourceRootPath}/kernel.cpp" "${sourceRootPath}/platform.cpp" "${sourceRootPath}/queue.cpp" diff --git a/sycl/include/CL/sycl/half_type.hpp b/sycl/include/CL/sycl/half_type.hpp new file mode 100644 index 0000000000000..f3a6e57b5a66c --- /dev/null +++ b/sycl/include/CL/sycl/half_type.hpp @@ -0,0 +1,84 @@ +//==-------------- half_type.hpp --- SYCL half type ------------------------==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include +#include + +namespace cl { +namespace sycl { +namespace detail { +namespace half_impl { + +class half { +public: + half() = default; + half(const half &) = default; + half(half &&) = default; + + half(const float &rhs); + + half &operator=(const half &rhs) = default; + + // Operator +=, -=, *=, /= + half &operator+=(const half &rhs); + + half &operator-=(const half &rhs); + + half &operator*=(const half &rhs); + + half &operator/=(const half &rhs); + + // Operator ++, -- + half &operator++() { + *this += 1; + return *this; + } + + half operator++(int) { + half ret(*this); + operator++(); + return ret; + } + + half &operator--() { + *this -= 1; + return *this; + } + + half operator--(int) { + half ret(*this); + operator--(); + return ret; + } + + // Operator float + operator float() const; + + template friend struct std::hash; + +private: + uint16_t Buf; +}; +} // namespace half_impl +} // namespace detail + +} // namespace sycl +} // namespace cl + +namespace std { + +template <> struct hash { + size_t operator()(cl::sycl::detail::half_impl::half const &key) const + noexcept { + return hash()(key.Buf); + } +}; + +} // namespace std diff --git a/sycl/include/CL/sycl/intel/sub_group.hpp b/sycl/include/CL/sycl/intel/sub_group.hpp index 6701a1d64e92b..e78e3d0af3bb0 100644 --- a/sycl/include/CL/sycl/intel/sub_group.hpp +++ b/sycl/include/CL/sycl/intel/sub_group.hpp @@ -139,11 +139,18 @@ struct sub_group { return BinaryOperation::template calc(x); } + template + using EnableIfIsArithmeticOrHalf = typename std::enable_if< + (std::is_arithmetic::value || + std::is_same::type, half>::value), + T>::type; + + /* --- one - input shuffles --- */ /* indices in [0 , sub - group size ) */ template - typename std::enable_if::value, T>::type + EnableIfIsArithmeticOrHalf shuffle(T x, id<1> local_id) { return cl::__spirv::OpSubgroupShuffleINTEL(x, local_id.get(0)); } @@ -156,7 +163,7 @@ struct sub_group { } template - typename std::enable_if::value, T>::type + EnableIfIsArithmeticOrHalf shuffle_down(T x, uint32_t delta) { return shuffle_down(x, x, delta); } @@ -168,7 +175,7 @@ struct sub_group { } template - typename std::enable_if::value, T>::type + EnableIfIsArithmeticOrHalf shuffle_up(T x, uint32_t delta) { return shuffle_up(x, x, delta); } @@ -180,7 +187,7 @@ struct sub_group { } template - typename std::enable_if::value, T>::type + EnableIfIsArithmeticOrHalf shuffle_xor(T x, id<1> value) { return cl::__spirv::OpSubgroupShuffleXorINTEL(x, (uint32_t)value.get(0)); } @@ -195,7 +202,7 @@ struct sub_group { /* --- two - input shuffles --- */ /* indices in [0 , 2* sub - group size ) */ template - typename std::enable_if::value, T>::type + EnableIfIsArithmeticOrHalf shuffle(T x, T y, id<1> local_id) { return cl::__spirv::OpSubgroupShuffleDownINTEL( x, y, local_id.get(0) - get_local_id().get(0)); @@ -210,7 +217,7 @@ struct sub_group { } template - typename std::enable_if::value, T>::type + EnableIfIsArithmeticOrHalf shuffle_down(T current, T next, uint32_t delta) { return cl::__spirv::OpSubgroupShuffleDownINTEL(current, next, delta); } @@ -223,7 +230,7 @@ struct sub_group { } template - typename std::enable_if::value, T>::type + EnableIfIsArithmeticOrHalf shuffle_up(T previous, T current, uint32_t delta) { return cl::__spirv::OpSubgroupShuffleUpINTEL(previous, current, delta); } diff --git a/sycl/include/CL/sycl/types.hpp b/sycl/include/CL/sycl/types.hpp index 64f93b8e6f5ea..da5d278c1ede9 100644 --- a/sycl/include/CL/sycl/types.hpp +++ b/sycl/include/CL/sycl/types.hpp @@ -45,11 +45,18 @@ #endif // __HAS_EXT_VECTOR_TYPE__ #include +#include #include // 4.10.1: Scalar data types // 4.10.2: SYCL vector types +#ifdef __SYCL_DEVICE_ONLY__ +using half = _Float16; +#else +using half = cl::sycl::detail::half_impl::half; +#endif + namespace cl { namespace sycl { @@ -373,16 +380,45 @@ template class vec { } #ifdef __SYCL_USE_EXT_VECTOR_TYPE__ - explicit vec(const DataT &arg) { + template + using EnableIfNotHostHalf = typename std::enable_if< + !std::is_same::value, T>::type; + template + using EnableIfHostHalf = typename std::enable_if< + std::is_same::value, T>::type; + + template + explicit vec(const EnableIfNotHostHalf &arg) { m_Data = (DataType)arg; } template - typename std::enable_if::value, vec &>::type - operator=(const DataT &Rhs) { + typename std::enable_if< + std::is_fundamental::value || + std::is_same::type, half>::value, + vec &>::type + operator=(const EnableIfNotHostHalf &Rhs) { m_Data = (DataType)Rhs; return *this; } + + template explicit vec(const EnableIfHostHalf &arg) { + for (int i = 0; i < NumElements; ++i) { + setValue(i, arg); + } + } + + template + typename std::enable_if< + std::is_fundamental::value || + std::is_same::type, half>::value, + vec &>::type + operator=(const EnableIfHostHalf &Rhs) { + for (int i = 0; i < NumElements; ++i) { + setValue(i, Rhs); + } + return *this; + } #else explicit vec(const DataT &arg) { for (int i = 0; i < NumElements; ++i) { @@ -391,7 +427,10 @@ template class vec { } template - typename std::enable_if::value, vec &>::type + typename std::enable_if< + std::is_fundamental::value || + std::is_same::type, half>::value, + vec &>::type operator=(const DataT &Rhs) { for (int i = 0; i < NumElements; ++i) { setValue(i, Rhs); @@ -407,32 +446,32 @@ template class vec { // Helper type to make specific constructors available only for specific // number of elements. template - using EnableIfMultipleElems = - typename std::enable_if::value && - NumElements == IdxNum, - DataT>::type; + using EnableIfMultipleElems = typename std::enable_if< + std::is_convertible::value && NumElements == IdxNum, + DataT>::type; template - vec(const EnableIfMultipleElems<2, Ty> Arg0, const DataT Arg1) + vec(const EnableIfMultipleElems<2, Ty> Arg0, + const EnableIfNotHostHalf Arg1) : m_Data{Arg0, Arg1} {} template - vec(const EnableIfMultipleElems<3, Ty> Arg0, const DataT Arg1, - const DataT Arg2) + vec(const EnableIfMultipleElems<3, Ty> Arg0, + const EnableIfNotHostHalf Arg1, const DataT Arg2) : m_Data{Arg0, Arg1, Arg2} {} template - vec(const EnableIfMultipleElems<4, Ty> Arg0, const DataT Arg1, - const DataT Arg2, const Ty Arg3) + vec(const EnableIfMultipleElems<4, Ty> Arg0, + const EnableIfNotHostHalf Arg1, const DataT Arg2, const Ty Arg3) : m_Data{Arg0, Arg1, Arg2, Arg3} {} template - vec(const EnableIfMultipleElems<8, Ty> Arg0, const DataT Arg1, - const DataT Arg2, const DataT Arg3, const DataT Arg4, const DataT Arg5, - const DataT Arg6, const DataT Arg7) + vec(const EnableIfMultipleElems<8, Ty> Arg0, + const EnableIfNotHostHalf Arg1, const DataT Arg2, const DataT Arg3, + const DataT Arg4, const DataT Arg5, const DataT Arg6, const DataT Arg7) : m_Data{Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7} {} template - vec(const EnableIfMultipleElems<16, Ty> Arg0, const DataT Arg1, - const DataT Arg2, const DataT Arg3, const DataT Arg4, const DataT Arg5, - const DataT Arg6, const DataT Arg7, const DataT Arg8, const DataT Arg9, - const DataT ArgA, const DataT ArgB, const DataT ArgC, const DataT ArgD, - const DataT ArgE, const DataT ArgF) + vec(const EnableIfMultipleElems<16, Ty> Arg0, + const EnableIfNotHostHalf Arg1, const DataT Arg2, const DataT Arg3, + const DataT Arg4, const DataT Arg5, const DataT Arg6, const DataT Arg7, + const DataT Arg8, const DataT Arg9, const DataT ArgA, const DataT ArgB, + const DataT ArgC, const DataT ArgD, const DataT ArgE, const DataT ArgF) : m_Data{Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9, ArgA, ArgB, ArgC, ArgD, ArgE, ArgF} {} #endif @@ -580,15 +619,26 @@ template class vec { #ifdef __SYCL_USE_EXT_VECTOR_TYPE__ #define __SYCL_BINOP(BINOP, OPASSIGN) \ - vec operator BINOP(const vec &Rhs) const { \ + template \ + vec operator BINOP(const EnableIfNotHostHalf &Rhs) const { \ vec Ret; \ Ret.m_Data = m_Data BINOP Rhs.m_Data; \ return Ret; \ } \ + template \ + vec operator BINOP(const EnableIfHostHalf &Rhs) const { \ + vec Ret; \ + for (size_t I = 0; I < NumElements; ++I) { \ + Ret.setValue(I, (getValue(I) BINOP Rhs.getValue(I))); \ + } \ + return Ret; \ + } \ template \ - typename std::enable_if::value && \ - std::is_fundamental::value, \ - vec>::type \ + typename std::enable_if< \ + std::is_convertible::value && \ + (std::is_fundamental::value || \ + std::is_same::type, half>::value), \ + vec>::type \ operator BINOP(const T &Rhs) const { \ return *this BINOP vec(static_cast(Rhs)); \ } \ @@ -597,8 +647,8 @@ template class vec { return *this; \ } \ template \ - typename std::enable_if::type operator OPASSIGN( \ - const DataT &Rhs) { \ + typename std::enable_if::type \ + operator OPASSIGN(const DataT &Rhs) { \ *this = *this BINOP vec(Rhs); \ return *this; \ } @@ -612,9 +662,11 @@ template class vec { return Ret; \ } \ template \ - typename std::enable_if::value && \ - std::is_fundamental::value, \ - vec>::type \ + typename std::enable_if< \ + std::is_convertible::value && \ + (std::is_fundamental::value || \ + std::is_same::type, half>::value), \ + vec>::type \ operator BINOP(const T &Rhs) const { \ return *this BINOP vec(static_cast(Rhs)); \ } \ @@ -666,9 +718,11 @@ template class vec { return Ret; \ } \ template \ - typename std::enable_if::value && \ - std::is_fundamental::value, \ - vec>::type \ + typename std::enable_if< \ + std::is_convertible::value && \ + (std::is_fundamental::value || \ + std::is_same::type, half>::value), \ + vec>::type \ operator RELLOGOP(const T &Rhs) const { \ return *this RELLOGOP vec(static_cast(Rhs)); \ } @@ -729,36 +783,67 @@ template class vec { // vec operatorOP(const DataT &Rhs) const; private: // Generic method that execute "Operation" on underlying values. - template