I recently came across an OpenCL kernel in which an int vector type was subtracted from the INT_MIN constant, e.g.
int2 v2 = INT_MIN - (int2)(0);
INT_MIN was defined as
#define INT_MIN (-2147483648)
Clang in OpenCL modes (-x cl) produces the following error:
vector_conversion.c:12:42: error: can't convert between vector values of different size ('long' and 'int2' (vector of 2 'int' values))
int2 v_int = INT_MIN - (int2)(0); // Only error long to int2 conversion is not possible
~~~~~~~ ^ ~~~~~~~~
1 error generated.
According to the OpenCL C standard (§6.2.6 and §6.3) I expected that the scalar INT_MIN would be expanded to the vector type and that the operation should be possible. The problem seems to be that INT_MIN is internally represented as long, though it is still a valid signed integer value, and thus long cannot be casted to int and subsequently not to int2.
If on the other hand INT_MIN is defined as
#define INT_MIN (-2147483647 - 1)
it is represented as int, although it is the same number, and clang does not produce an error.
More surprisingly, the expression
int2 t = (int2)(INT_MIN);
works for both versions of INT_MIN. So in this situation long seems to be implicitly casted to int which should not be possible.
Finally, for clang in C mode (-x c) also both version work and no error is produced. I attached a test case in which a summarised all my findings. The behaviour I observed should be reproducible with
$ clang -x cl -S -emit-llvm -O0 -o - vector_conversion.c
$ clang -x c -S -emit-llvm -O0 -o - vector_conversion.c
I would be interested in your thoughts about this behaviour, whether it is correct that -2147483648 is represented as long or whether the behaviour can be considered as bug in the OpenCL frontend of Clang. (Another possibility would be that the representation as long is correct but it is nevertheless a bug that the subtraction is not possible.)
vector_conversion.c (856 Bytes)