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/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 357819a..b00c788 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -139,7 +139,7 @@
     Expr *VisitCharacterLiteral(CharacterLiteral *E);
     Expr *VisitParenExpr(ParenExpr *E);
     Expr *VisitUnaryOperator(UnaryOperator *E);
-    Expr *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
+    Expr *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
     Expr *VisitBinaryOperator(BinaryOperator *E);
     Expr *VisitCompoundAssignOperator(CompoundAssignOperator *E);
     Expr *VisitImplicitCastExpr(ImplicitCastExpr *E);
@@ -3799,7 +3799,8 @@
                                          Importer.Import(E->getOperatorLoc()));                                        
 }
 
-Expr *ASTNodeImporter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+Expr *ASTNodeImporter::VisitUnaryExprOrTypeTraitExpr(
+                                            UnaryExprOrTypeTraitExpr *E) {
   QualType ResultType = Importer.Import(E->getType());
   
   if (E->isArgumentType()) {
@@ -3807,8 +3808,8 @@
     if (!TInfo)
       return 0;
     
-    return new (Importer.getToContext()) SizeOfAlignOfExpr(E->isSizeOf(),
-                                                           TInfo, ResultType,
+    return new (Importer.getToContext()) UnaryExprOrTypeTraitExpr(E->getKind(),
+                                           TInfo, ResultType,
                                            Importer.Import(E->getOperatorLoc()),
                                            Importer.Import(E->getRParenLoc()));
   }
@@ -3817,8 +3818,8 @@
   if (!SubExpr)
     return 0;
   
-  return new (Importer.getToContext()) SizeOfAlignOfExpr(E->isSizeOf(),
-                                                         SubExpr, ResultType,
+  return new (Importer.getToContext()) UnaryExprOrTypeTraitExpr(E->getKind(),
+                                          SubExpr, ResultType,
                                           Importer.Import(E->getOperatorLoc()),
                                           Importer.Import(E->getRParenLoc()));
 }
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 99ce611..4793b11 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -2854,8 +2854,8 @@
 //  Child Iterators for iterating over subexpressions/substatements
 //===----------------------------------------------------------------------===//
 
-// SizeOfAlignOfExpr
-Stmt::child_range SizeOfAlignOfExpr::children() {
+// UnaryExprOrTypeTraitExpr
+Stmt::child_range UnaryExprOrTypeTraitExpr::children() {
   // If this is of a type and the type is a VLA type (and not a typedef), the
   // size expression of the VLA needs to be treated as an executable expression.
   // Why isn't this weirdness documented better in StmtIterator?
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index 890898a..3767922 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -128,7 +128,7 @@
     // Expressions that are prvalues.
   case Expr::CXXBoolLiteralExprClass:
   case Expr::CXXPseudoDestructorExprClass:
-  case Expr::SizeOfAlignOfExprClass:
+  case Expr::UnaryExprOrTypeTraitExprClass:
   case Expr::CXXNewExprClass:
   case Expr::CXXThisExprClass:
   case Expr::CXXNullPtrLiteralExprClass:
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();
   }
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 45653e6..bceed08 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -1888,10 +1888,22 @@
     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);
+    switch(SAE->getKind()) {
+    case UETT_SizeOf:
+      Out << 's';
+      break;
+    case UETT_AlignOf:
+      Out << 'a';
+      break;
+    case UETT_VecStep:
+      Diagnostic &Diags = Context.getDiags();
+      unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
+                                     "cannot yet mangle vec_step expression");
+      Diags.Report(DiagID);
+      return;
+    }
     if (SAE->isArgumentType()) {
       Out << 't';
       mangleType(SAE->getArgumentType());
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index 5c7dbb3..21ed848 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -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,19 @@
   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()) {
+  case UETT_SizeOf:
+    OS << " sizeof ";
+    break;
+  case UETT_AlignOf:
+    OS << " __alignof ";
+    break;
+  case UETT_VecStep:
+    OS << " vec_step ";
+    break;
+  }
   if (Node->isArgumentType())
     DumpType(Node->getArgumentType());
 }
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 1cdd220..4f50044 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -706,8 +706,18 @@
   OS << ")";
 }
 
-void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
-  OS << (Node->isSizeOf() ? "sizeof" : "__alignof");
+void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){
+  switch(Node->getKind()) {
+  case UETT_SizeOf:
+    OS << "sizeof";
+    break;
+  case UETT_AlignOf:
+    OS << "__alignof";
+    break;
+  case UETT_VecStep:
+    OS << "vec_step";
+    break;
+  }
   if (Node->isArgumentType())
     OS << "(" << Node->getArgumentType().getAsString(Policy) << ")";
   else {
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index b540011..a506d05 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -290,9 +290,9 @@
   VisitExpr(S);
 }
 
-void StmtProfiler::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *S) {
+void StmtProfiler::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *S) {
   VisitExpr(S);
-  ID.AddBoolean(S->isSizeOf());
+  ID.AddInteger(S->getKind());
   if (S->isArgumentType())
     VisitType(S->getArgumentType());
 }