Add support for the OpenCL vec_step operator, by generalising and
extending the existing support for sizeof and alignof.  Original
patch by Guy Benyei.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127475 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index f421671..b6ab332 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -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)
@@ -1020,7 +1021,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);
@@ -1601,36 +1602,59 @@
 }
 
 
-/// VisitSizeAlignOfExpr - Evaluate a sizeof or alignof with a result as the
-/// expression's type.
-bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
-  // Handle alignof separately.
-  if (!E->isSizeOf()) {
+/// VisitUnaryExprOrTypeTraitExpr - Evaluate a sizeof, alignof or vec_step with
+/// a result as the expression's type.
+bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
+                                    const UnaryExprOrTypeTraitExpr *E) {
+  switch(E->getKind()) {
+  case UETT_AlignOf: {
     if (E->isArgumentType())
       return Success(GetAlignOfType(E->getArgumentType()), E);
     else
       return Success(GetAlignOfExpr(E->getArgumentExpr()), 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."
-  // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
-  //   result shall be the alignment of the referenced type."
-  if (const ReferenceType *Ref = SrcTy->getAs<ReferenceType>())
-    SrcTy = Ref->getPointeeType();
+  case UETT_VecStep: {
+    QualType Ty = E->getTypeOfArgument();
 
-  // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
-  // extension.
-  if (SrcTy->isVoidType() || SrcTy->isFunctionType())
-    return Success(1, E);
+    if (Ty->isVectorType()) {
+      unsigned n = Ty->getAs<VectorType>()->getNumElements();
 
-  // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
-  if (!SrcTy->isConstantSizeType())
-    return false;
+      // 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;
 
-  // Get information about the size.
-  return Success(Info.Ctx.getTypeSizeInChars(SrcTy), E);
+      return Success(n, E);
+    } else
+      return Success(1, E);
+  }
+
+  case UETT_SizeOf: {
+    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."
+    // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
+    //   result shall be the alignment of the referenced type."
+    if (const ReferenceType *Ref = SrcTy->getAs<ReferenceType>())
+      SrcTy = Ref->getPointeeType();
+
+    // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
+    // extension.
+    if (SrcTy->isVoidType() || SrcTy->isFunctionType())
+      return Success(1, E);
+
+    // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
+    if (!SrcTy->isConstantSizeType())
+      return false;
+
+    // Get information about the size.
+    return Success(Info.Ctx.getTypeSizeInChars(SrcTy), E);
+  }
+  }
+
+  llvm_unreachable("unknown expr/type trait");
+  return false;
 }
 
 bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) {
@@ -2884,9 +2908,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() ==  UETT_SizeOf) &&
+        Exp->getTypeOfArgument()->isVariableArrayType())
       return ICEDiag(2, E->getLocStart());
     return NoDiag();
   }