Skip to content

[SYCL] Added support of rounding modes for floating and integer types #1576

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

Conversation

fadeeval
Copy link
Contributor

Implementing rounding models for cl::sycl::vec type for non host devices.

Signed-off-by: Aleksander Fadeev aleksander.fadeev@intel.com

@fadeeval fadeeval force-pushed the private/fadeeval/vec_convert_API_rounding_mode_consideration branch from 67329a5 to 1cd7097 Compare April 23, 2020 08:21
@bader
Copy link
Contributor

bader commented Apr 23, 2020

+@Naghasan to review SPIRV built-ins tablegen changes.

Comment on lines 763 to 764
if !ne(OutType.ElementSize, InType.ElementSize) then {
def : SPVBuiltin<"SConvert_R" # OutType.Name, [OutType, InType], Attr.Const>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if !ne(OutType.ElementSize, InType.ElementSize) then {
def : SPVBuiltin<"SConvert_R" # OutType.Name, [OutType, InType], Attr.Const>;
if !ne(OutType.ElementSize, InType.ElementSize) then {
def : SPVBuiltin<"SConvert_R" # OutType.Name, [OutType, InType], Attr.Const>;

@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//

// Implements vec and __swizzled_vec__ classes.

#include <typeinfo>
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see why you do need this include.

Copy link
Contributor

@AlexeySachkov AlexeySachkov left a comment

Choose a reason for hiding this comment

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

Part about conversions is getting bigger and bigger. We should probably consider outlining it into a separate header file, just to reduce the size of types.hpp and make it easier to read

@@ -199,6 +199,34 @@ using is_int_to_int =
std::integral_constant<bool, std::is_integral<T>::value &&
std::is_integral<R>::value>;

template <typename T, typename R>
using is_sint_to_sint = std::integral_constant<
bool, std::is_integral<T>::value && !(std::is_unsigned<T>::value) &&
Copy link
Contributor

Choose a reason for hiding this comment

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

!istd::is_unsigned -> std::is_signed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

std::is_signed include floating point types also, is not?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, is_signed includes is_arithmetic, but you already have is_integral here - I guess this should be enough to reject floating-point types, right?

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 will use "is_sigeninteger" in new version any way.

template <typename T, typename R>
using is_sint_to_sint = std::integral_constant<
bool, std::is_integral<T>::value && !(std::is_unsigned<T>::value) &&
std::is_integral<R>::value && !(std::is_unsigned<R>::value)>;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think that you can use the following type trait that we have:

using is_sigeninteger = is_contained<T, gtl::scalar_signed_integer_list>;

Comment on lines 351 to 361
// unsigned to unsigned
#define __SYCL_GENERATE_CONVERT_IMPL(DestType) \
template <typename T, typename R, rounding_mode roundingMode> \
detail::enable_if_t< \
!std::is_same<T, R>::value && is_uint_to_uint<T, R>::value && \
std::is_same<R, DestType>::value && \
std::is_same<cl::sycl::detail::ConvertToOpenCLType_t<T>, R>::value, \
R> \
convertImpl(T Value) { \
return static_cast<R>(Value); \
}
Copy link
Contributor

Choose a reason for hiding this comment

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

You have very similar chunk of code for signed to signed. I suggest you to adjust enable_if a bit so it can be re-used for this unsigned to unsigned as well.

Something like

  detail::enable_if_t<                                                         \
      !std::is_same<T, R>::value && (is_sint_to_sint<T, R>::value || is_uint_to_uint<T, R>::value) &&            \
          std::is_same<R, DestType>::value &&                                  \
          std::is_same<cl::sycl::detail::ConvertToOpenCLType_t<T>, R>::value,  \
      R>    

detail::enable_if_t< \
!std::is_same<T, R>::value && is_sint_to_sint<T, R>::value && \
std::is_same<R, DestType>::value && \
std::is_same<cl::sycl::detail::ConvertToOpenCLType_t<T>, R>::value, \
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks like a lot of work on templates for the compiler. Can we somehow simplify it?

Is it possible to convert SYCL types to OpenCL types somewhere else in the call stack (let's say in a function which calls convertImpl) and re-design convertImpl so it already operates on OpenCL types?

Comment on lines 399 to 390
detail::enable_if_t< \
is_sint_to_float<T, R>::value && std::is_same<R, DestType>::value, R> \
convertImpl(T Value) { \
using OpenCLT = cl::sycl::detail::ConvertToOpenCLType_t<T>; \
OpenCLT OpValue = cl::sycl::detail::convertDataToType<T, OpenCLT>(Value); \
return __spirv_Convert##SPIRVOp##_R##DestType(OpValue); \
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This std::is_same<R, DestType::value doesn't seem like a right thing to do here. Is it possible to avoid adding this check into each enable_if?

What about creating partial specializations of convertImpl?

template <typename T, typename R, rounding_mode roundingMode>
R convertImp(T Value) { 
  // the most generic one
  // static_cast as fallback?
}

template <typename T, rounding_mode roundingMode>
half convertImpl<T, half, roundingMode>(half Value) {
  // actual implementation here
}

// Actual implementations can still be generated by preprocessor:
#define __SYCL_GENERATE_CONVERT_IMPL(SPIRVOp, DestType) \
detail::enable_if_t< is_signed_arithmetic<T>::value, T> \
template <typename T, rounding_mode roundingMode> \
convertImpl<T, DestType, roundingMode>(DestType Value) { \
  // actual implementation here \
}

__SYCL_GENERATE_CONVERT_IMPL(SToF, half)
__SYCL_GENERATE_CONVERT_IMPL(SToF, float)
__SYCL_GENERATE_CONVERT_IMPL(SToF, double)

#undef __SYCL_GENERATE_CONVERT_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.

How about just get name of a type as string and add it to a spirv func name?

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 understand how to implement your idea

Copy link
Contributor Author

Choose a reason for hiding this comment

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

C++ doesn't support function template partial specialization.

test<float, half, 8, rounding_mode::rte>(
float8{+2.3f, +2.5f, +2.7f, -2.3f, -2.5f, -2.7f, 0.f, 0.f},
half8{+2.3f, +2.5f, +2.7f, -2.3f, -2.5f, -2.7f, 0.f, 0.f});
test<double, float, 8, rounding_mode::automatic>(
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
test<double, float, 8, rounding_mode::automatic>(
test<double, float, 8, rounding_mode::rte>(

test<float, half, 8, rounding_mode::automatic>(
float8{+2.3f, +2.5f, +2.7f, -2.3f, -2.5f, -2.7f, 0.f, 0.f},
half8{+2.3f, +2.5f, +2.7f, -2.3f, -2.5f, -2.7f, 0.f, 0.f});
test<double, float, 8, rounding_mode::automatic>(
Copy link
Contributor

Choose a reason for hiding this comment

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

Since you are adding separate tests for particular data types, I suggest you to just remove this test case from here - it is anyway duplicated in vec_convert_f_to_f.cpp

Comment on lines 23 to 48
template <int N>
struct helper;

template <>
struct helper<0> {
template <typename T, int NumElements>
static void compare(const vec<T, NumElements> &x,
const vec<T, NumElements> &y) {
const T xs = x.template swizzle<0>();
const T ys = y.template swizzle<0>();
assert(xs == ys);
}
};

template <int N>
struct helper {
template <typename T, int NumElements>
static void compare(const vec<T, NumElements> &x,
const vec<T, NumElements> &y) {
const T xs = x.template swizzle<N>();
const T ys = y.template swizzle<N>();
helper<N - 1>::compare(x, y);
assert(xs == ys);
}
};

Copy link
Contributor

Choose a reason for hiding this comment

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

Please outline duplicated code into a header file with helpers

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There should I place the header?

half8{+2.3f, +2.5f, +2.7f, -2.3f, -2.5f, -2.7f, 0.f, 0.f});
test<double, float, 8, rounding_mode::automatic>(
double8{+2.3, +2.5, +2.7, -2.3, -2.5, -2.7, 0., 0.},
float8{+2.3f, +2.5f, +2.7f, -2.3f, -2.5f, -2.7f, 0.f, 0.f});

// rte
test<int, int, 8, rounding_mode::rte>(
Copy link
Contributor

Choose a reason for hiding this comment

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

Since you are adding separate files for conversions between different types, I suggest you to leave in this file only float to int conversions - just to avoid testing the same combinations in different files

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe I should rename this file then?

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe I should rename this file then?

Makes sense

@@ -745,7 +745,7 @@ foreach IType = [Char, Short, Int, Long] in {
}
}

foreach InType = TLAll.List in {
foreach InType = TLUnsignedInts.List in {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why this restriction ? It is valid to convert a signed int to an unsigned one.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it is valid, but SatConvertSToU exists for this purpose.

Copy link
Contributor

Choose a reason for hiding this comment

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

UConvert/SConvert does not saturate the result unless decorated...

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 will check it, but I have doubt, that UConvert gets non unsigned arguments.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When I run test that converts int to uint, it writes "call to '__spirv_UConvert_Ruint' is ambiguous", that means it make implicit conversion form signed to unsigned so that push int argument, but compiler have many options for that that's why it writes the error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

I think the document https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpUConvert proves my gusses.

I hardly see what it proves, from the spec This is either a truncate or a zero extend. whether the destination type is bigger or smaller, this is not a saturating operation: Uconvert 0x0F00 to uchar yields 0x0, SatConvertStoU yields 0xFF.

that converts int to uint, it writes "call to '__spirv_UConvert_Ruint' is ambiguous"

This is expected as this operation does not exist in SPIR-V, so the overload does not exist. You are trying to do a 32 to 32 bits conversion (see https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpUConvert: The component width cannot equal the component width in Result Type.). The operation you are looking for in this cast is simply a reinterpret_cast in that case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I will remake

@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//

// Implements vec and __swizzled_vec__ classes.
#include <typeinfo>

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change

#define __SYCL_GENERATE_CONVERT_IMPL(DestType) \
template <typename T, typename R, rounding_mode roundingMode> \
// convert signed and unsigned types with an equal size and diff names
#define __SYCL_GENERATE_CONVERT_IMPL() \
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you need this as macro? The main idea was to auto-generate some code by using pre-processor features. Now you have no arguments to this macro and call it only once - in that case having a macro just doesn't make sense

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok

@fadeeval fadeeval requested a review from Fznamznon April 29, 2020 10:56
@fadeeval
Copy link
Contributor Author

@turinevgeny, @erichkeane, @Fznamznon, @Naghasan, please, make review.

erichkeane
erichkeane previously approved these changes Apr 29, 2020
Copy link
Contributor

@erichkeane erichkeane left a comment

Choose a reason for hiding this comment

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

The CFE changes are fine, but RT reviewers are going to need to do approval for the rest.

@fadeeval fadeeval requested a review from romanovvlad April 29, 2020 12:58
turinevgeny
turinevgeny previously approved these changes Apr 29, 2020
Copy link
Contributor

@turinevgeny turinevgeny left a comment

Choose a reason for hiding this comment

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

types.hpp looks fine.

@fadeeval fadeeval dismissed stale reviews from turinevgeny and erichkeane via da36f2a April 30, 2020 09:41
sergey-semenov
sergey-semenov previously approved these changes Apr 30, 2020
@bader
Copy link
Contributor

bader commented May 1, 2020

@fadeeval, please, resolve merge conflict.

// RUN: %CPU_RUN_PLACEHOLDER %t.out
// RUN: %GPU_RUN_PLACEHOLDER %t.out
// RUN: %ACC_RUN_PLACEHOLDER %t.out
//==------------ vec_convert.cpp - SYCL vec class convert method test ------==//
Copy link
Contributor

Choose a reason for hiding this comment

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

vec_convert.cpp -> vec_convert_f_to_f.cpp

Copy link
Contributor

Choose a reason for hiding this comment

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

Please, fix the comment in a separate PR.

// RUN: %CPU_RUN_PLACEHOLDER %t.out
// RUN: %GPU_RUN_PLACEHOLDER %t.out
// RUN: %ACC_RUN_PLACEHOLDER %t.out
//==------------ vec_convert.cpp - SYCL vec class convert method test ------==//
Copy link
Contributor

Choose a reason for hiding this comment

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

vec_convert.cpp -> vec_convert_f_to_i.cpp

Copy link
Contributor

Choose a reason for hiding this comment

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

Please, fix the comment in a separate PR.

Comment on lines +21 to +23
test<float, int, 8, rounding_mode::automatic>(
float8{+2.3f, +2.5f, +2.7f, -2.3f, -2.5f, -2.7f, 0.f, 0.f},
int8{2, 2, 3, -2, -2, -3, 0, 0});
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
test<float, int, 8, rounding_mode::automatic>(
float8{+2.3f, +2.5f, +2.7f, -2.3f, -2.5f, -2.7f, 0.f, 0.f},
int8{2, 2, 3, -2, -2, -3, 0, 0});
test<float, int, 8, rounding_mode::automatic>(
float8{+2.3f, +2.5f, +2.7f, -2.3f, -2.5f, -2.7f, 0.f, 0.f},
int8{2, 2, 2, -2, -2, -2, 0, 0});

RTZ is the default for conversions to integer

Copy link
Contributor Author

@fadeeval fadeeval May 12, 2020

Choose a reason for hiding this comment

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

I think so too, but in the sycl-1.2.1.pdf spec on the 226 page the automatic description is following: "Default rounding mode for the SYCL vec class element type. rtz (round toward zero) for integer types and rte (round to nearest even) for floating-point types", which sounds confusing. And the person who wrote conversions for HOST implemented so that RTE is automatic mode for converting from floating-point types. That is why I followed the idea that automatic mode is RTE. Should I change it to RTZ?

Copy link
Contributor

Choose a reason for hiding this comment

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

"Default rounding mode for the SYCL vec class element type. rtz (round toward zero) for integer types and rte (round to nearest even) for floating-point types", which sounds confusing

I agree, RTZ for conversions to integer types could be a better wording for this.

Should I change it to RTZ?

Well that's what the spec mandates. But according to what you are saying, changing this will go well out of scope of your patch. The bug is already there anyway and the patch consistent with it, so I would personally lean toward merging as is and do a PR to fully fix the automatic mode in one go after. But that's more a CO decision now.

fadeeval added 3 commits May 12, 2020 11:10
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
fadeeval added 13 commits May 12, 2020 12:07
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
@fadeeval fadeeval force-pushed the private/fadeeval/vec_convert_API_rounding_mode_consideration branch from f834594 to d2c7a22 Compare May 12, 2020 09:13
Signed-off-by: Aleksander Fadeev <aleksander.fadeev@intel.com>
@fadeeval
Copy link
Contributor Author

@turinevgeny, @erichkeane, @Fznamznon, @Naghasan, @sergey-semenov, make review, please,.

Copy link
Contributor

@turinevgeny turinevgeny left a comment

Choose a reason for hiding this comment

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

LGTM in general, but I'd like someone else to approve who knows more details.

@fadeeval
Copy link
Contributor Author

@erichkeane, @Fznamznon, @Naghasan, @sergey-semenov, approve if no objections, please.

@Fznamznon
Copy link
Contributor

I don't see any FE changes, please don't wait for approve from me.

@bader bader requested a review from sergey-semenov May 14, 2020 10:28
Copy link
Contributor

@Naghasan Naghasan left a comment

Choose a reason for hiding this comment

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

Looks ok to me. I think RTZ issue for integers should be handled separately.

Copy link
Contributor

@sergey-semenov sergey-semenov left a comment

Choose a reason for hiding this comment

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

LGTM aside from the unresolved file header comments by @bader, but those can be addressed separately.

@bader bader merged commit 096d0a0 into intel:sycl May 14, 2020
@fadeeval fadeeval deleted the private/fadeeval/vec_convert_API_rounding_mode_consideration branch May 26, 2020 08:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants