KhronosGroup/SYCL-Docs

`vec::convert` is underspecified

Opened this issue · 1 comments

Table 142 of the SYCL 2020 specification defines vec::convert as follows:

Converts this SYCL vec to a SYCL vec of a different element type specified by ConvertT using the rounding mode specified by RoundingMode. The new SYCL vec type must have the same number of elements as this SYCL vec. The different rounding modes are described in Table 144.

Which raises a number of questions:

There are no restrictions about using different rounding modes even for integer to integer conversions. What is the meaning of them in that case? Note that there are cases when source value is not representable in destination type, like narrowing conversion, signed to unsigned conversion for negative values. Should rounding modes affect the result in those cases?

How "converts" is defined, exactly? Does it follow C++ standard or some other rules? If it follows C++, then which one?
The latest C++ spec draft defines integer conversions in conv.integral.3 as:

the result is the unique value of the destination type that is congruent to the source integer modulo 2^N
, where N is the width of the destination type.

However, if you take a look at C++17 draft (document N4713) 7.8 Integer conversions, you will find the following:

If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2^n where n is the number of bits used to represent the unsigned type). [ Note: In a two’s complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). — end note ]
If the destination type is signed, the value is unchanged if it can be represented in the destination type; otherwise, the value is implementation-defined

SYCL-CTS is using C-style cast to compute reference value for integer conversions: tests/common/common_vec.h:132, which means that reference selected in CTS is technically implementation-defined if it is compiled with C++17-based toolchain and it is well-defined it it is compiled with C++20-based toolchain, which doesn't sound right.

Note: signed-to-unsigned (and vice-versa) conversions defined in SPIR-V do not follow C++20 rules: they clamp input value to a nearest representable value in the destination type instead of doing modulo arithmetic, see OpSatConvertSToU for example.

SYCL WG call:

  • Original specification was based on OpenCL, but should be considered in light of C++17
  • @nliber will take a look at this