Giving consistent semantics to extended vectors

Hello,

I’ve been investigating how Clang interprets operations on extended vectors
[those declared with attribute((ext_vector_type(n))], in particular with
respect to the OpenCL semantics, since
http://clang.llvm.org/docs/LanguageExtensions.html#vectors implies that
extended vectors have some support for OpenCL constructs.

My conclusion is that Clang’s behaviour with respect to OpenCL considerably
varies from producing wrong diagnostics to accepting invalid statements and
rejecting valid statements to silently producing wrong LLVM code. Couple of
examples (all vector types have obvious definitions):

uchar4 vu = (uchar4) true;
// results in: (0x01, 0x01, 0x01, 0x01)
// must be: (0xff, 0xff, 0xff, 0xff)

int4 vu = (uint4) vi; // disallowed in OpenCL, accepted by Clang

This is intentional.

int4 via, vib, vic;
vic = (via == vib ? via : vib); // allowed in OpenCL, rejected by Clang:
// error: used type ‘int4’ where arithmetic or pointer type is
required

The patch for this has not been submitted back to TOT clang yet.

short2 vs, vr; int i;
vr = vs < i;
// down-conversion and vector widening: disallowed by OpenCL,
rejected by Clang:
// error: can’t convert between vector values of different size
(‘short2’ and ‘int’)
// (clearly, the error message could be more helpful)

Patches welcome.

My question is whether it anyone has objections to making statements
involving extended vectors to have by default semantics consistent with
OpenCL or only have the OpenCL semantics when the LangOpts flag is enabled?

Extended Vectors are meant to support OpenCL-ish operations, but not enforce OpenCL error semantics all the time.

Nate

Hi Nate,

Extended Vectors are meant to support OpenCL-ish operations,
but not enforce OpenCL error semantics all the time.

There are two questions here:

(1) should Extended Vectors have OpenCL semantics by default?
(2) should Extended Vectors have sensible semantics?

The answer to (1) is "no". I understand that providing OpenCL semantics is
not always possible/desirable. For example, OpenCL programs can use extra
as_type() and convert_type() operators which are unavailable in C. Thus,
disallowing e.g.

int4 vi = (int4) -1; // vi = (-1, -1, -1, -1)
uint4 vu = (uint4) vi; // disallowed in OpenCL, accepted by Clang, results
in:
                       // vu = (0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff)

would mean C programs have to do memcpy for reinterpretation and
element-wise copying for conversion.

The answer to (2) is "yes". For example, the type casting operator ()
currently results in reinterpretation e.g.

int4 vi = (int4) 0x1; // vi = ( 0x00000001, 0x00000001, 0x00000001,
0x00000001)
float4 vf = (float4) vi; // disallowed in OpenCL, accepted by Clang, results
in:
         // vf = (1.401298e-45, 1.401298e-45,
1.401298e-45, 1.401298e-45)

but should arguably result in conversion, as reinterpretation can be
achieved by memcpy but conversion would require element-wise copying.

So I suggest to overhaul the implementation of Extended Vectors, making
their semantics sensible (and properly documenting it), whilst achieving
consistency with OpenCL only where possible.

The patch for this has not been submitted back to TOT clang yet.
...
Patches welcome.

It's difficult to work on patches without knowing what's already
implemented/planned and might be committed soon. If you could commit your
patches, then it would avoid duplication of work and/or inconsistencies. Do
you think you could do that?

Best regards,
Anton.

Hi Anton,

Hi Nate,

Extended Vectors are meant to support OpenCL-ish operations,
but not enforce OpenCL error semantics all the time.

There are two questions here:

(1) should Extended Vectors have OpenCL semantics by default?
(2) should Extended Vectors have sensible semantics?

The answer to (1) is "no". I understand that providing OpenCL semantics is
not always possible/desirable. For example, OpenCL programs can use extra
as_type() and convert_type() operators which are unavailable in C. Thus,
disallowing e.g.

int4 vi = (int4) -1; // vi = (-1, -1, -1, -1)
uint4 vu = (uint4) vi; // disallowed in OpenCL, accepted by Clang, results
in:
// vu = (0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff)

would mean C programs have to do memcpy for reinterpretation and
element-wise copying for conversion.

The answer to (2) is "yes". For example, the type casting operator ()
currently results in reinterpretation e.g.

int4 vi = (int4) 0x1; // vi = ( 0x00000001, 0x00000001, 0x00000001,
0x00000001)
float4 vf = (float4) vi; // disallowed in OpenCL, accepted by Clang, results
in:
// vf = (1.401298e-45, 1.401298e-45,
1.401298e-45, 1.401298e-45)

but should arguably result in conversion, as reinterpretation can be
achieved by memcpy but conversion would require element-wise copying.

So I suggest to overhaul the implementation of Extended Vectors, making
their semantics sensible (and properly documenting it), whilst achieving
consistency with OpenCL only where possible.

Overhaul seems a bit strong, as I think the extended vector semantics
probably make sense, by and large. However, I completely agree that
extended vectors should have consistent and well documented semantics.
They were intended to be a "reasonable" implementation of vector
support for C as well as being useful for OpenCL.

Unless you really meant overhaul, I recommend filing concrete bug
reports for places you think the semantics are wrong in C mode.

- Daniel

Hi Nate,

Extended Vectors are meant to support OpenCL-ish operations,
but not enforce OpenCL error semantics all the time.

There are two questions here:

(1) should Extended Vectors have OpenCL semantics by default?
(2) should Extended Vectors have sensible semantics?

The answer to (2) is "yes". For example, the type casting operator ()
currently results in reinterpretation e.g.

int4 vi = (int4) 0x1; // vi = ( 0x00000001, 0x00000001, 0x00000001,
0x00000001)
float4 vf = (float4) vi; // disallowed in OpenCL, accepted by Clang, results
in:
         // vf = (1.401298e-45, 1.401298e-45,
1.401298e-45, 1.401298e-45)

but should arguably result in conversion, as reinterpretation can be
achieved by memcpy but conversion would require element-wise copying.

No, it should not result in conversion. This behavior is specifically intended to allow intermixing of vector and extended vector types, since one of the most common things you want to do is bitconvert an extended vector type for use with an SSE/AltiVec intrinsic. This is not a bug. When compiling with the OpenCL language flag enabled, Sema can easily reject this particular explicit cast, but it should not be an illegal operation on Extended Vectors in general.

So I suggest to overhaul the implementation of Extended Vectors, making
their semantics sensible (and properly documenting it), whilst achieving
consistency with OpenCL only where possible.

Consistency with OpenCL is achieved via the __builtin_astype() and __builtin_convert() functions, as well as C++ code in Sema. The builtin OpenCL type operators may not have been checked in yet, I can follow up on that. I believe Extended Vectors already have sensible semantics and are generally consistent with OpenCL, as they have been used to make a conforming OpenCL implementation. Please file specific bugs for things that are not correct in clang with the OpenCL language enabled.

Nate

Hi Daniel and Nate,

From: daniel.dunbar@gmail.com [mailto:daniel.dunbar@gmail.com] On
Behalf Of Daniel Dunbar
Sent: 04 May 2010 16:33
To: Anton Lokhmotov
Overhaul seems a bit strong, as I think the extended vector semantics
probably make sense, by and large. However, I completely agree that
extended vectors should have consistent and well documented semantics.
They were intended to be a "reasonable" implementation of vector
support for C as well as being useful for OpenCL.
Unless you really meant overhaul, I recommend filing concrete bug
reports for places you think the semantics are wrong in C mode.

That's most sensible. I've been looking at the extended vectors semantics
from the OpenCL perspective but will now try to look from the C perspective
as well. Ideally, code dealing with extended vectors would check the
current mode and output LLVM-IR with the semantics for this mode. For
example, I agree with Nate's explanation that in C mode the casting
operator should generate a bitcast, not a conversion. In some cases,
however, Clang's behaviour is downright incorrect irrespective of mode, for
example:

int4 via; via++;

results in a failed assertion "Cannot create binary operator with two
operands of differing type!" (Failed assertions are always bad, especially
when they are so confusing.)

In other cases, I'm not so sure, for example:

uchar4 vc;
vc = (uchar4) false; // (0x00, 0x00, 0x00, 0x00)
vc = (uchar4) true; // (0x01, 0x01, 0x01, 0x01)
        // [should be (0xff, 0xff, 0xff, 0xff) in
OpenCL]

(The OpenCL semantics is arguably more useful here, as it allows to use vc
as a mask.)

From: Nate Begeman [mailto:natebegeman@me.com]
Sent: 04 May 2010 16:53
To: Anton Lokhmotov
Cc: cfe-dev@cs.uiuc.edu
Subject: Re: [cfe-dev] Giving consistent semantics to extended vectors

Consistency with OpenCL is achieved via the __builtin_astype() and
__builtin_convert() functions, as well as C++ code in Sema. The
builtin OpenCL type operators may not have been checked in yet, I can
follow up on that.

Please do, I can't see these in Clang 2.7 or the trunk. In fact, grep'ing
Clang 2.7 for OpenCL returns only 26 lines.

Please file specific bugs for things that are not correct in clang
with the OpenCL language enabled.

Since I've specifically tested the behaviour of OpenCL constructs in OpenCL
mode, I could probably file a couple of dozen of bugs today. It's clear,
however, that it's just because your changes haven't been merged into the
trunk yet. I understand that merging the changes is probably a low-priority
activity for you but I can't stress enough how useful it would be resulting
in less duplication and inconsistencies and overall more robust
implementation.

Best regards,
Anton L.