OpenCL vec_step feature implementation - Updated patch

Hello,

Here is another update for our vec_step patch. The changes I did in this patch:

Changed the new expression name that includes sizeof, alignof and vec_step to UnaryExprOrTypeTraitExpr.

Fail compilation on vec_step of derived types.

Added negative test cases.

Fixed some comments.

Please review.

Thanks

Guy Benyei

Intel

SSG – MGP OpenCL Development Center

image001.png

opencl_vec_step.patch (57.6 KB)

Hello,
Here is another update for our vec_step patch. The changes I did in this patch:

Changed the new expression name that includes sizeof, alignof and vec_step to UnaryExprOrTypeTraitExpr.
Fail compilation on vec_step of derived types.
Added negative test cases.
Fixed some comments.

Please review.

Comments are inlined below.

Index: include/clang/AST/Expr.h

--- include/clang/AST/Expr.h (revision 126222)
+++ include/clang/AST/Expr.h (working copy)
@@ -1556,10 +1556,15 @@
   }
};

-/// SizeOfAlignOfExpr - [C99 6.5.3.4] - This is for sizeof/alignof, both of
-/// types and expressions.
-class SizeOfAlignOfExpr : public Expr {
- bool isSizeof : 1; // true if sizeof, false if alignof.
+/// UnaryExprOrTypeTraitExpr - either:
+/// [C99 6.5.3.4] - This is for sizeof/alignof, both of types and expressions.
+/// [OpenCL 1.1 6.11.12] - The vec_step builtin function, which works on both
+/// types and expressions
+class UnaryExprOrTypeTraitExpr : public Expr {
+public:
+ enum Kind_t { SizeOf, AlignOf, VecStep };

This enum should live in include/clang/Basic/TypeTraits.h with the
other type trait kind enums.

+private:
+ Kind_t Kind;

This should be a bit-field so that we share storage space with isType.

   bool isType : 1; // true if operand is a type, false if an expression
   union {
     TypeSourceInfo *Ty;
@@ -1568,36 +1573,36 @@
   SourceLocation OpLoc, RParenLoc;

public:
- SizeOfAlignOfExpr(bool issizeof, TypeSourceInfo *TInfo,
+ UnaryExprOrTypeTraitExpr(Kind_t exprKind, TypeSourceInfo *TInfo,
                     QualType resultType, SourceLocation op,
                     SourceLocation rp) :
- Expr(SizeOfAlignOfExprClass, resultType, VK_RValue, OK_Ordinary,
+ Expr(UnaryExprOrTypeTraitExprClass, resultType, VK_RValue, OK_Ordinary,
            false, // Never type-dependent (C++ [temp.dep.expr]p3).
            // Value-dependent if the argument is type-dependent.
            TInfo->getType()->isDependentType(),
            TInfo->getType()->containsUnexpandedParameterPack()),
- isSizeof(issizeof), isType(true), OpLoc(op), RParenLoc(rp) {
+ Kind(exprKind), isType(true), OpLoc(op), RParenLoc(rp) {
     Argument.Ty = TInfo;
   }

- SizeOfAlignOfExpr(bool issizeof, Expr *E,
+ UnaryExprOrTypeTraitExpr(Kind_t exprKind, Expr *E,
                     QualType resultType, SourceLocation op,
                     SourceLocation rp) :
- Expr(SizeOfAlignOfExprClass, resultType, VK_RValue, OK_Ordinary,
+ Expr(UnaryExprOrTypeTraitExprClass, resultType, VK_RValue, OK_Ordinary,
            false, // Never type-dependent (C++ [temp.dep.expr]p3).
            // Value-dependent if the argument is type-dependent.
            E->isTypeDependent(),
            E->containsUnexpandedParameterPack()),
- isSizeof(issizeof), isType(false), OpLoc(op), RParenLoc(rp) {
+ Kind(exprKind), isType(false), OpLoc(op), RParenLoc(rp) {
     Argument.Ex = E;
   }

   /// \brief Construct an empty sizeof/alignof expression.
- explicit SizeOfAlignOfExpr(EmptyShell Empty)
- : Expr(SizeOfAlignOfExprClass, Empty) { }
+ explicit UnaryExprOrTypeTraitExpr(EmptyShell Empty)
+ : Expr(UnaryExprOrTypeTraitExprClass, Empty) { }

- bool isSizeOf() const { return isSizeof; }
- void setSizeof(bool S) { isSizeof = S; }
+ Kind_t getKind() const { return Kind; }
+ void setKind(Kind_t K) { Kind = K; }

   bool isArgumentType() const { return isType; }
   QualType getArgumentType() const {
@@ -1612,7 +1617,7 @@
     return static_cast<Expr*>(Argument.Ex);
   }
   const Expr *getArgumentExpr() const {
- return const_cast<SizeOfAlignOfExpr*>(this)->getArgumentExpr();
+ return const_cast<UnaryExprOrTypeTraitExpr*>(this)->getArgumentExpr();
   }

   void setArgument(Expr *E) { Argument.Ex = E; isType = false; }
@@ -1638,9 +1643,9 @@
   }

   static bool classof(const Stmt *T) {
- return T->getStmtClass() == SizeOfAlignOfExprClass;
+ return T->getStmtClass() == UnaryExprOrTypeTraitExprClass;
   }
- static bool classof(const SizeOfAlignOfExpr *) { return true; }
+ static bool classof(const UnaryExprOrTypeTraitExpr *) { return true; }

   // Iterators
   child_range children();
Index: include/clang/Basic/TokenKinds.def

--- include/clang/Basic/TokenKinds.def (revision 126222)
+++ include/clang/Basic/TokenKinds.def (working copy)
@@ -345,10 +345,12 @@
KEYWORD(__thiscall , KEYALL)
KEYWORD(__forceinline , KEYALL)

-// OpenCL-specific keywords (see OpenCL 1.1 [6.1.9])
+// OpenCL-specific keywords (see OpenCL 1.1)
KEYWORD(__kernel , KEYOPENCL)
ALIAS("kernel", __kernel , KEYOPENCL)
+KEYWORD(vec_step , KEYOPENCL)

+

You can remove this newline.

// Borland Extensions.
KEYWORD(__pascal , KEYALL)

Index: lib/AST/ExprConstant.cpp

--- lib/AST/ExprConstant.cpp (revision 126222)
+++ lib/AST/ExprConstant.cpp (working copy)
@@ -290,7 +290,8 @@
   bool VisitFloatingLiteral(FloatingLiteral *E) { return false; }
   bool VisitStringLiteral(StringLiteral *E) { return false; }
   bool VisitCharacterLiteral(CharacterLiteral *E) { return false; }
- bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { return false; }
+ bool VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E)
+ { return false; }
   bool VisitArraySubscriptExpr(ArraySubscriptExpr *E)
     { return Visit(E->getLHS()) || Visit(E->getRHS()); }
   bool VisitChooseExpr(ChooseExpr *E)
@@ -1015,7 +1016,7 @@
   bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E);

   bool VisitCastExpr(CastExpr* E);
- bool VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E);
+ bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);

   bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) {
     return Success(E->getValue(), E);
@@ -1598,15 +1599,36 @@

/// VisitSizeAlignOfExpr - Evaluate a sizeof or alignof with a result as the
/// expression's type.
-bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
+bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
+ const UnaryExprOrTypeTraitExpr *E) {
   // Handle alignof separately.
- if (!E->isSizeOf()) {
+ if (E->getKind() == UnaryExprOrTypeTraitExpr::AlignOf) {
     if (E->isArgumentType())
       return Success(GetAlignOfType(E->getArgumentType()).getQuantity(), E);
     else
       return Success(GetAlignOfExpr(E->getArgumentExpr()).getQuantity(), E);
   }

+ if (E->getKind() == UnaryExprOrTypeTraitExpr::VecStep) {
+ clang::QualType Ty;
+ if (E->isArgumentType())
+ Ty = E->getArgumentType();
+ else
+ Ty = E->getArgumentExpr()->getType();
+
+ if (Ty->isVectorType()) {
+ unsigned n = Ty->getAs<clang::VectorType>()->getNumElements();
+
+ // The vec_step built-in functions that take a 3-component
+ // vector return 4. (OpenCL 1.1 spec 6.11.12)
+ if (n == 3)
+ n = 4;
+
+ return Success(n, E);
+ } else
+ return Success(1, E);
+ }
+
   QualType SrcTy = E->getTypeOfArgument();
   // C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
   // the result is the size of the referenced type."

This should use a case statement without a default so that we get a
compiler warning if we add another trait without changing this code.

@@ -2879,9 +2901,10 @@
       // are ICEs, the value of the offsetof must be an integer constant.
       return CheckEvalInICE(E, Ctx);
   }
- case Expr::SizeOfAlignOfExprClass: {
- const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(E);
- if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType())
+ case Expr::UnaryExprOrTypeTraitExprClass: {
+ const UnaryExprOrTypeTraitExpr *Exp = cast<UnaryExprOrTypeTraitExpr>(E);
+ if ((Exp->getKind() == UnaryExprOrTypeTraitExpr::SizeOf) &&
+ Exp->getTypeOfArgument()->isVariableArrayType())
       return ICEDiag(2, E->getLocStart());
     return NoDiag();
   }
Index: lib/AST/ItaniumMangle.cpp

--- lib/AST/ItaniumMangle.cpp (revision 126222)
+++ lib/AST/ItaniumMangle.cpp (working copy)
@@ -1874,10 +1874,11 @@
     break;
   }

- case Expr::SizeOfAlignOfExprClass: {
- const SizeOfAlignOfExpr *SAE = cast<SizeOfAlignOfExpr>(E);
- if (SAE->isSizeOf()) Out << 's';
- else Out << 'a';
+ case Expr::UnaryExprOrTypeTraitExprClass: {
+ const UnaryExprOrTypeTraitExpr *SAE = cast<UnaryExprOrTypeTraitExpr>(E);
+ if (SAE->getKind() == UnaryExprOrTypeTraitExpr::SizeOf) Out << 's';
+ else if (SAE->getKind() == UnaryExprOrTypeTraitExpr::AlignOf) Out << 'a';
+ else Out << 'v';

Case statement here also.

This encoding does not conform with the Itanium ABI (it clashes with
the encoding for 'vendor extended operators'). We should error out
here for vec_step until we have a proper encoding.

     if (SAE->isArgumentType()) {
       Out << 't';
       mangleType(SAE->getArgumentType());
Index: lib/AST/StmtDumper.cpp

--- lib/AST/StmtDumper.cpp (revision 126222)
+++ lib/AST/StmtDumper.cpp (working copy)
@@ -141,7 +141,7 @@
     void VisitFloatingLiteral(FloatingLiteral *Node);
     void VisitStringLiteral(StringLiteral *Str);
     void VisitUnaryOperator(UnaryOperator *Node);
- void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node);
+ void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node);
     void VisitMemberExpr(MemberExpr *Node);
     void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
     void VisitBinaryOperator(BinaryOperator *Node);
@@ -441,9 +441,21 @@
   OS << " " << (Node->isPostfix() ? "postfix" : "prefix")
      << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
}
-void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
+void StmtDumper::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) {
   DumpExpr(Node);
- OS << " " << (Node->isSizeOf() ? "sizeof" : "alignof") << " ";
+ switch(Node->getKind()) {
+ default:
+ assert(false && "Unknown kind for UnaryExprOrTypeTraitExpr");
+ case UnaryExprOrTypeTraitExpr::SizeOf:
+ OS << "sizeof";
+ break;
+ case UnaryExprOrTypeTraitExpr::AlignOf:
+ OS << "__alignof";
+ break;
+ case UnaryExprOrTypeTraitExpr::VecStep:
+ OS << "vec_step";
+ break;
+ }

No default here.

   if (Node->isArgumentType())
     DumpType(Node->getArgumentType());
}
Index: lib/AST/StmtPrinter.cpp

--- lib/AST/StmtPrinter.cpp (revision 126222)
+++ lib/AST/StmtPrinter.cpp (working copy)
@@ -706,8 +706,21 @@
   OS << ")";
}

-void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
- OS << (Node->isSizeOf() ? "sizeof" : "__alignof");
+void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(
+ UnaryExprOrTypeTraitExpr *Node) {
+ switch(Node->getKind()) {
+ default:
+ assert(false && "Unknown kind for UnaryExprOrTypeTraitExpr");
+ case UnaryExprOrTypeTraitExpr::SizeOf:
+ OS << "sizeof";
+ break;
+ case UnaryExprOrTypeTraitExpr::AlignOf:
+ OS << "__alignof";
+ break;
+ case UnaryExprOrTypeTraitExpr::VecStep:
+ OS << "vec_step";
+ break;
+ }

No default.

   if (Node->isArgumentType())
     OS << "(" << Node->getArgumentType().getAsString(Policy) << ")";
   else {
Index: lib/Frontend/StmtXML.cpp

--- lib/Frontend/StmtXML.cpp (revision 126222)
+++ lib/Frontend/StmtXML.cpp (working copy)
@@ -36,7 +36,7 @@
                                              Str->getString().size()));
   }

- void addSpecialAttribute(const char* pName, SizeOfAlignOfExpr* S) {
+ void addSpecialAttribute(const char* pName, UnaryExprOrTypeTraitExpr* S) {
     if (S->isArgumentType())
       Doc.addAttribute(pName, S->getArgumentType());
   }
@@ -126,7 +126,7 @@
     void VisitStringLiteral(StringLiteral *Str);
     void VisitUnaryOperator(UnaryOperator *Node);
     void VisitOffsetOfExpr(OffsetOfExpr *Node);
- void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node);
+ void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node);
     void VisitMemberExpr(MemberExpr *Node);
     void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
     void VisitBinaryOperator(BinaryOperator *Node);
@@ -310,7 +310,7 @@
   DumpExpr(Node);
}

-void StmtXML::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
+void StmtXML::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) {
   DumpExpr(Node);
   Doc.addAttribute("is_sizeof", Node->isSizeOf() ? "sizeof" : "alignof");

This should be changed to use getKind.

Index: lib/Sema/SemaExpr.cpp

--- lib/Sema/SemaExpr.cpp (revision 126222)
+++ lib/Sema/SemaExpr.cpp (working copy)
@@ -2716,10 +2716,10 @@

/// The UsualUnaryConversions() function is *not* called by this routine.
/// See C99 6.3.2.1p[2-4] for more details.
-bool Sema::CheckSizeOfAlignOfOperand(QualType exprType,
- SourceLocation OpLoc,
- SourceRange ExprRange,
- bool isSizeof) {
+bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType exprType,
+ SourceLocation OpLoc,
+ SourceRange ExprRange,
+ UnaryExprOrTypeTraitExpr::Kind_t exprKind) {
   if (exprType->isDependentType())
     return false;

@@ -2733,28 +2733,36 @@
   // C99 6.5.3.4p1:
   if (exprType->isFunctionType()) {
     // alignof(function) is allowed as an extension.
- if (isSizeof)
- Diag(OpLoc, diag::ext_sizeof_function_type) << ExprRange;
- return false;
+ if (exprKind != UnaryExprOrTypeTraitExpr::AlignOf)
+ Diag(OpLoc, diag::ext_sizeof_vecstep_function_type)
+ << exprKind << ExprRange;
+ return false;
   }

   // Allow sizeof(void)/alignof(void) as an extension.
   if (exprType->isVoidType()) {
     Diag(OpLoc, diag::ext_sizeof_void_type)
- << (isSizeof ? "sizeof" : "__alignof") << ExprRange;
+ << exprKind << ExprRange;
     return false;
   }

   if (RequireCompleteType(OpLoc, exprType,
                           PDiag(diag::err_sizeof_alignof_incomplete_type)
- << int(!isSizeof) << ExprRange))
+ << exprKind << ExprRange))
     return true;

+ if(exprType->isDerivedType() && exprKind == UnaryExprOrTypeTraitExpr::VecStep)
+ {
+ Diag(OpLoc, diag::err_vecstep_derived_type) << exprType << ExprRange;
+ return true;
+ }
+
   // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode.
   if (LangOpts.ObjCNonFragileABI && exprType->isObjCObjectType()) {
     Diag(OpLoc, diag::err_sizeof_nonfragile_interface)
- << exprType << isSizeof << ExprRange;
- return true;
+ << exprType << (exprKind == UnaryExprOrTypeTraitExpr::SizeOf)
+ << ExprRange;
+ return true;

"return true;" shouldn't change indentation here.

   }

   return false;
@@ -2783,25 +2791,45 @@
     if (isa<FieldDecl>(ME->getMemberDecl()))
       return false;

- return S.CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false);
+ return S.CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange,
+ UnaryExprOrTypeTraitExpr::AlignOf);
}

+bool Sema::CheckVecStepExpr(Expr *E, SourceLocation OpLoc,
+ SourceRange ExprRange) {
+ if (!getLangOptions().OpenCL) {
+ // vec_step is supported in OpenCL only
+ Diag(OpLoc, diag::err_vecstep_not_in_opencl);
+ return true;
+ }

We shouldn't reach here unless we're in OpenCL mode because the
keyword is OpenCL-only.

Index: lib/StaticAnalyzer/Checkers/ExprEngine.cpp

--- lib/StaticAnalyzer/Checkers/ExprEngine.cpp (revision 126222)
+++ lib/StaticAnalyzer/Checkers/ExprEngine.cpp (working copy)
@@ -1085,8 +1085,9 @@
       VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst);
       break;

- case Stmt::SizeOfAlignOfExprClass:
- VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), Pred, Dst);
+ case Stmt::UnaryExprOrTypeTraitExprClass:
+ VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S),
+ Pred, Dst);
       break;

     case Stmt::StmtExprClass: {
@@ -2816,14 +2817,15 @@
   assert(0 && "unprocessed InitListExpr type");
}

-/// VisitSizeOfAlignOfExpr - Transfer function for sizeof(type).
-void ExprEngine::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex,
+/// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof(type).
+void ExprEngine::VisitUnaryExprOrTypeTraitExpr(
+ const UnaryExprOrTypeTraitExpr* Ex,
                                           ExplodedNode* Pred,
                                           ExplodedNodeSet& Dst) {
   QualType T = Ex->getTypeOfArgument();
   CharUnits amt;

- if (Ex->isSizeOf()) {
+ if (Ex->getKind() == UnaryExprOrTypeTraitExpr::SizeOf) {
     if (T == getContext().VoidTy) {
       // sizeof(void) == 1 byte.
       amt = CharUnits::One();
@@ -2874,9 +2876,26 @@
       amt = getContext().getTypeSizeInChars(T);
     }
   }
- else // Get alignment of the type.
- amt = getContext().getTypeAlignInChars(T);
+ else if (Ex->getKind() == UnaryExprOrTypeTraitExpr::AlignOf) {
+ // Get alignment of the type.
+ amt = getContext().getTypeAlignInChars(T);
+ }
+ else {
+ if (T->isVectorType()) {
+ int n = T->getAs<clang::VectorType>()->getNumElements();

+ // The vec_step built-in functions that take a 3-component
+ // vector return 4. (OpenCL 1.1 spec 6.11.12)
+ if (n == 3)
+ n = 4;
+
+ amt = CharUnits::fromQuantity(n);
+ }
+ else {
+ amt = CharUnits::fromQuantity(1);
+ }
+ }
+

We should be able to replace all non-special cases here with a call
to the constant expression evaluator.

Index: test/CodeGenOpenCL/vec_step.cl

--- test/CodeGenOpenCL/vec_step.cl (revision 0)
+++ test/CodeGenOpenCL/vec_step.cl (revision 0)
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 %s -emit-llvm -D NO_NEGATIVE_CASES -O0 -o - | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef int int2 __attribute__((ext_vector_type(2)));
+typedef int int3 __attribute__((ext_vector_type(3)));
+typedef int int4 __attribute__((ext_vector_type(4)));
+typedef int int8 __attribute__((ext_vector_type(8)));
+typedef int int16 __attribute__((ext_vector_type(16)));
+
+void foo(int3 arg1, int8 arg2) {
+ int4 auto1;
+ int16 *auto2;
+ int auto3;
+ int2 auto4;
+ struct S *incomplete1; // expected-note{{forward declaration of 'struct S'}}
+
+
+ int res1 = vec_step(arg1);
+// CHECK: store i32 4, i32* %res1
+ int res2 = vec_step(arg2);
+// CHECK: store i32 8, i32* %res2
+ int res3 = vec_step(auto1);
+// CHECK: store i32 4, i32* %res3
+ int res4 = vec_step(*auto2);
+// CHECK: store i32 16, i32* %res4
+ int res5 = vec_step(auto3);
+// CHECK: store i32 1, i32* %res5
+ int res6 = vec_step(auto4);
+// CHECK: store i32 2, i32* %res6
+ int res7 = vec_step(int2);
+// CHECK: store i32 2, i32* %res7
+ int res8 = vec_step(int3);
+// CHECK: store i32 4, i32* %res8
+ int res9 = vec_step(int4);
+// CHECK: store i32 4, i32* %res9
+ int res10 = vec_step(int8);
+// CHECK: store i32 8, i32* %res10
+ int res11 = vec_step(int16);
+// CHECK: store i32 16, i32* %res11
+
+#ifndef NO_NEGATIVE_CASES
+ int res12 = vec_step(*incomplete1); // expected-error{{invalid application of 'vec_step' to an incomplete type 'struct S'}}
+ int res13 = vec_step(int16*); // expected-error{{invalid application of vec_step to derived type 'int16 *'}}
+#endif
+}

Normally we test integral constant expressions in the Clang test
suite using the

int array[foo ? 1 : -1];

idiom. See for example the test/Sema/expr-comma.c test case.
You should be able to move this test case to SemaOpenCL and you
shouldn't need to use the NO_NEGATIVE_CASES macro if using this idiom.

Thanks,

Hi Peter,

Thanks for your review, I really appreciate it.

I’ve attached a fixed patch, please review it.

Thanks

Guy Benyei

Intel

SSG – MGP OpenCL Development Center

image001.png

opencl_vec_step.patch (58.5 KB)

Hi Guy,

I think that your patch is almost ready to commit. I made some
final changes to the patch (attached) which I plan to commit some
time after today's branch.

Aside from code style fixes, the most visible change I made was to
change the test for a valid vec_step operand to match that given
in the OpenCL spec (built-in scalar and vector types) and to move the
test earlier. This way we provide the user with what they really
need to know in the diagnostic (i.e. that non-scalar/vector types
are not permitted as a vec_step operand, regardless of whether they
are incomplete, function types etc).

Thanks,

0001-Add-support-for-the-OpenCL-vec_step-operator-by-gene.patch (64.4 KB)

Now committed as r127475.

Thanks,