]> granicus.if.org Git - clang/commitdiff
Add the intrinsic __builtin_convertvector
authorHal Finkel <hfinkel@anl.gov>
Wed, 18 Sep 2013 03:29:45 +0000 (03:29 +0000)
committerHal Finkel <hfinkel@anl.gov>
Wed, 18 Sep 2013 03:29:45 +0000 (03:29 +0000)
LLVM supports applying conversion instructions to vectors of the same number of
elements (fptrunc, fptosi, etc.) but there had been no way for a Clang user to
cause such instructions to be generated when using builtin vector types.

C-style casting on vectors is already defined in terms of bitcasts, and so
cannot be used for these conversions as well (without leading to a very
confusing set of semantics). As a result, this adds a __builtin_convertvector
intrinsic (patterned after the OpenCL __builtin_astype intrinsic). This is
intended to aid the creation of vector intrinsic headers that create generic IR
instead of target-dependent intrinsics (in other words, this is a generic
_mm_cvtepi32_ps). As noted in the documentation, the action of
__builtin_convertvector is defined in terms of the action of a C-style cast on
each vector element.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@190915 91177308-0d34-0410-b5e6-96231b3b80d8

30 files changed:
docs/LanguageExtensions.rst
include/clang/AST/Expr.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/Basic/Builtins.def
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Basic/StmtNodes.td
include/clang/Basic/TokenKinds.def
include/clang/Sema/Sema.h
include/clang/Serialization/ASTBitCodes.h
lib/AST/Expr.cpp
lib/AST/ExprClassification.cpp
lib/AST/ExprConstant.cpp
lib/AST/ItaniumMangle.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/CodeGen/CGExprScalar.cpp
lib/Parse/ParseExpr.cpp
lib/Sema/SemaChecking.cpp
lib/Sema/SemaExceptionSpec.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
test/CodeGen/convertvector.c [new file with mode: 0644]
test/PCH/exprs.h
test/Preprocessor/feature_tests.c
test/Sema/convertvector.c [new file with mode: 0644]
tools/libclang/CXCursor.cpp
tools/libclang/RecursiveASTVisitor.h

index 44f2f8dbeaaea8b301093d2c810d50ce8669e2f0..f6a7a4e4310e6c5d39a8f3bea6360216f8eabb32 100644 (file)
@@ -1473,6 +1473,50 @@ indices specified.
 
 Query for this feature with ``__has_builtin(__builtin_shufflevector)``.
 
+``__builtin_convertvector``
+---------------------------
+
+``__builtin_convertvector`` is used to express generic vector
+type-conversion operations. The input vector and the output vector
+type must have the same number of elements.
+
+**Syntax**:
+
+.. code-block:: c++
+
+  __builtin_convertvector(src_vec, dst_vec_type)
+
+**Examples**:
+
+.. code-block:: c++
+
+  typedef double vector4double __attribute__((__vector_size__(32)));
+  typedef float  vector4float  __attribute__((__vector_size__(16)));
+  typedef short  vector4short  __attribute__((__vector_size__(8)));
+  vector4float vf; vector4short vs;
+
+  // convert from a vector of 4 floats to a vector of 4 doubles.
+  __builtin_convertvector(vf, vector4double)
+  // equivalent to:
+  (vector4double) { (double) vf[0], (double) vf[1], (double) vf[2], (double) vf[3] }
+
+  // convert from a vector of 4 shorts to a vector of 4 floats.
+  __builtin_convertvector(vs, vector4float)
+  // equivalent to:
+  (vector4float) { (float) vf[0], (float) vf[1], (float) vf[2], (float) vf[3] }
+
+**Description**:
+
+The first argument to ``__builtin_convertvector`` is a vector, and the second
+argument is a vector type with the same number of elements as the first
+argument.
+
+The result of ``__builtin_convertvector`` is a vector with the same element
+type as the second argument, with a value defined in terms of the action of a
+C-style cast applied to each element of the first argument.
+
+Query for this feature with ``__has_builtin(__builtin_convertvector)``.
+
 ``__builtin_unreachable``
 -------------------------
 
index e82d6bb05fea5121cb4682f26cf9da7f4db5ec0e..8a884c0b2e5a504f05fa0bb195b4d7004baf0107 100644 (file)
@@ -3468,6 +3468,60 @@ public:
   }
 };
 
+/// ConvertVectorExpr - Clang builtin function __builtin_convertvector
+/// This AST node provides support for converting a vector type to another
+/// vector type of the same arity.
+class ConvertVectorExpr : public Expr {
+private:
+  Stmt *SrcExpr;
+  TypeSourceInfo *TInfo;
+  SourceLocation BuiltinLoc, RParenLoc;
+
+  friend class ASTReader;
+  friend class ASTStmtReader;
+  explicit ConvertVectorExpr(EmptyShell Empty) : Expr(ConvertVectorExprClass, Empty) {}
+
+public:
+  ConvertVectorExpr(Expr* SrcExpr, TypeSourceInfo *TI, QualType DstType,
+             ExprValueKind VK, ExprObjectKind OK,
+             SourceLocation BuiltinLoc, SourceLocation RParenLoc)
+    : Expr(ConvertVectorExprClass, DstType, VK, OK,
+           DstType->isDependentType(),
+           DstType->isDependentType() || SrcExpr->isValueDependent(),
+           (DstType->isInstantiationDependentType() ||
+            SrcExpr->isInstantiationDependent()),
+           (DstType->containsUnexpandedParameterPack() ||
+            SrcExpr->containsUnexpandedParameterPack())),
+  SrcExpr(SrcExpr), TInfo(TI), BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) {}
+
+  /// getSrcExpr - Return the Expr to be converted.
+  Expr *getSrcExpr() const { return cast<Expr>(SrcExpr); }
+
+  /// getTypeSourceInfo - Return the destination type.
+  TypeSourceInfo *getTypeSourceInfo() const {
+    return TInfo;
+  }
+  void setTypeSourceInfo(TypeSourceInfo *ti) {
+    TInfo = ti;
+  }
+
+  /// getBuiltinLoc - Return the location of the __builtin_convertvector token.
+  SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
+
+  /// getRParenLoc - Return the location of final right parenthesis.
+  SourceLocation getRParenLoc() const { return RParenLoc; }
+
+  SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; }
+  SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == ConvertVectorExprClass;
+  }
+
+  // Iterators
+  child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
+};
+
 /// ChooseExpr - GNU builtin-in function __builtin_choose_expr.
 /// This AST node is similar to the conditional operator (?:) in C, with
 /// the following exceptions:
index 46adcda6e0a1a0773a561fd4f7e22523392ac46b..ac6ea6759431d4f6bf4a565c4da1707a1ee8360c 100644 (file)
@@ -2262,6 +2262,7 @@ DEF_TRAVERSE_STMT(ParenExpr, { })
 DEF_TRAVERSE_STMT(ParenListExpr, { })
 DEF_TRAVERSE_STMT(PredefinedExpr, { })
 DEF_TRAVERSE_STMT(ShuffleVectorExpr, { })
+DEF_TRAVERSE_STMT(ConvertVectorExpr, { })
 DEF_TRAVERSE_STMT(StmtExpr, { })
 DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
   TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
index cb7613ce12b2337fe5e8cefb30d48872acdd3d0d..83f00bb1c732d904102a5634749818b4b290905a 100644 (file)
@@ -488,6 +488,7 @@ BUILTIN(__builtin_trap, "v", "nr")
 BUILTIN(__builtin_debugtrap, "v", "n")
 BUILTIN(__builtin_unreachable, "v", "nr")
 BUILTIN(__builtin_shufflevector, "v."   , "nc")
+BUILTIN(__builtin_convertvector, "v."   , "nct")
 BUILTIN(__builtin_alloca, "v*z"   , "n")
 
 // "Overloaded" Atomic operator builtins.  These are overloaded to support data
index af5c6f60993d2abe483a6789448440208d3cc382..f53ca666d55112620f74720d65b821c65296df7d 100644 (file)
@@ -6374,6 +6374,13 @@ def err_shufflevector_argument_too_large : Error<
   "index for __builtin_shufflevector must be less than the total number "
   "of vector elements">;
 
+def err_convertvector_non_vector : Error<
+  "first argument to __builtin_convertvector must be a vector">;
+def err_convertvector_non_vector_type : Error<
+  "second argument to __builtin_convertvector must be a vector type">;
+def err_convertvector_incompatible_vector : Error<
+  "first two arguments to __builtin_convertvector must have the same number of elements">;
+
 def err_vector_incorrect_num_initializers : Error<
   "%select{too many|too few}0 elements in vector initialization (expected %1 elements, have %2)">;
 def err_altivec_empty_initializer : Error<"expected initializer">;
index 0da9b34028801dfbf95002700d00d53b27c56cd1..69851a9d52839cad4f5c9a77988b37435ad9c9e8 100644 (file)
@@ -162,6 +162,7 @@ def CUDAKernelCallExpr : DStmt<CallExpr>;
 
 // Clang Extensions.
 def ShuffleVectorExpr : DStmt<Expr>;
+def ConvertVectorExpr : DStmt<Expr>;
 def BlockExpr : DStmt<Expr>;
 def OpaqueValueExpr : DStmt<Expr>;
 
index 3f156a86a27e1c70c3d4a1e95db7e0c1377c0846..d7636321648a4b89cff1537aefea6d0be558715a 100644 (file)
@@ -542,6 +542,7 @@ ALIAS("_declspec"        , __declspec , KEYMS)
 ALIAS("_pascal"      , __pascal   , KEYBORLAND)
 
 // Clang Extensions.
+KEYWORD(__builtin_convertvector   , KEYALL)
 ALIAS("__char16_t"   , char16_t   , KEYCXX)
 ALIAS("__char32_t"   , char32_t   , KEYCXX)
 
index 573f028019947360632a0975317a645a4f69b06c..5d0f0813910b5ed7b1e174c32052a5d6d53bc9a2 100644 (file)
@@ -3546,6 +3546,13 @@ public:
   ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body,
                                 Scope *CurScope);
 
+  //===---------------------------- Clang Extensions ----------------------===//
+
+  /// __builtin_convertvector(...)
+  ExprResult ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy,
+                                    SourceLocation BuiltinLoc,
+                                    SourceLocation RParenLoc);
+
   //===---------------------------- OpenCL Features -----------------------===//
 
   /// __builtin_astype(...)
@@ -7711,6 +7718,9 @@ private:
 public:
   // Used by C++ template instantiation.
   ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall);
+  ExprResult SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
+                                   SourceLocation BuiltinLoc,
+                                   SourceLocation RParenLoc);
 
 private:
   bool SemaBuiltinPrefetch(CallExpr *TheCall);
index b1e5e72ae5d9d92e9b533fd6e89c506d26c06a3d..03d905054aea1983c504d262acae7a106c2eb55d 100644 (file)
@@ -1186,6 +1186,8 @@ namespace clang {
       EXPR_GNU_NULL,
       /// \brief A ShuffleVectorExpr record.
       EXPR_SHUFFLE_VECTOR,
+      /// \brief A ConvertVectorExpr record.
+      EXPR_CONVERT_VECTOR,
       /// \brief BlockExpr
       EXPR_BLOCK,
       /// \brief A GenericSelectionExpr record.
index ea91fbec4f85833c886bb9aa8bb8569e1e6d4b4c..a3a36da65f43eff7f9883e797c1de02a8d3e5a15 100644 (file)
@@ -2843,6 +2843,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
   case SubstNonTypeTemplateParmExprClass:
   case MaterializeTemporaryExprClass:
   case ShuffleVectorExprClass:
+  case ConvertVectorExprClass:
   case AsTypeExprClass:
     // These have a side-effect if any subexpression does.
     break;
index 1c91af7d47fdaa494b30f677c84869a482639bf1..4640d7d37d61b32f53a5acd9c3f4a377ce3f020b 100644 (file)
@@ -155,6 +155,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
   case Expr::OffsetOfExprClass:
   case Expr::CXXThrowExprClass:
   case Expr::ShuffleVectorExprClass:
+  case Expr::ConvertVectorExprClass:
   case Expr::IntegerLiteralClass:
   case Expr::CharacterLiteralClass:
   case Expr::AddrLabelExprClass:
index 8ca33cbd20c5756ed089f1cf74f49ca92ef04a55..0fb6d4276108d7a1514dcefefca1a48d1e8b50f4 100644 (file)
@@ -8145,6 +8145,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
   case Expr::ObjCSubscriptRefExprClass:
   case Expr::ObjCIsaExprClass:
   case Expr::ShuffleVectorExprClass:
+  case Expr::ConvertVectorExprClass:
   case Expr::BlockExprClass:
   case Expr::NoStmtClass:
   case Expr::OpaqueValueExprClass:
index a87bf1123e8ad8ff9c68ef52133dc63f1bab5fdc..3b32bdfb2ba43ce7cbb36f237a6f6f68be580045 100644 (file)
@@ -2603,6 +2603,7 @@ recurse:
   case Expr::OffsetOfExprClass:
   case Expr::PredefinedExprClass:
   case Expr::ShuffleVectorExprClass:
+  case Expr::ConvertVectorExprClass:
   case Expr::StmtExprClass:
   case Expr::UnaryTypeTraitExprClass:
   case Expr::BinaryTypeTraitExprClass:
index 98b56bcbc7cee99268a8f5631c665ac55f0f48b1..ee3852a3e987e2e4ecee31fd7654356585c25ead 100644 (file)
@@ -1088,6 +1088,14 @@ void StmtPrinter::VisitShuffleVectorExpr(ShuffleVectorExpr *Node) {
   OS << ")";
 }
 
+void StmtPrinter::VisitConvertVectorExpr(ConvertVectorExpr *Node) {
+  OS << "__builtin_convertvector(";
+  PrintExpr(Node->getSrcExpr());
+  OS << ", ";
+  Node->getType().print(OS, Policy);
+  OS << ")";
+}
+
 void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
   if (Node->getSyntacticForm()) {
     Visit(Node->getSyntacticForm());
index 77c34c41aaf3f2a8e3831e789c79cfa980ad8f94..9591127b8af4bdd0ab4fff2c6ecd8010b29f3d49 100644 (file)
@@ -454,6 +454,10 @@ void StmtProfiler::VisitShuffleVectorExpr(const ShuffleVectorExpr *S) {
   VisitExpr(S);
 }
 
+void StmtProfiler::VisitConvertVectorExpr(const ConvertVectorExpr *S) {
+  VisitExpr(S);
+}
+
 void StmtProfiler::VisitChooseExpr(const ChooseExpr *S) {
   VisitExpr(S);
 }
index 287dc6c02315ac04f07ef3ab19cae5f9c0b92499..57f102f2932f47d239fcd74f6369f58e75b1b243 100644 (file)
@@ -257,6 +257,7 @@ public:
 
   Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E);
   Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E);
+  Value *VisitConvertVectorExpr(ConvertVectorExpr *E);
   Value *VisitMemberExpr(MemberExpr *E);
   Value *VisitExtVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); }
   Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
@@ -966,6 +967,81 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
   Value *SV = llvm::ConstantVector::get(indices);
   return Builder.CreateShuffleVector(V1, V2, SV, "shuffle");
 }
+
+Value *ScalarExprEmitter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
+  QualType SrcType = E->getSrcExpr()->getType(),
+           DstType = E->getType();
+
+  Value *Src  = CGF.EmitScalarExpr(E->getSrcExpr());
+
+  SrcType = CGF.getContext().getCanonicalType(SrcType);
+  DstType = CGF.getContext().getCanonicalType(DstType);
+  if (SrcType == DstType) return Src;
+
+  assert(SrcType->isVectorType() &&
+         "ConvertVector source type must be a vector");
+  assert(DstType->isVectorType() &&
+         "ConvertVector destination type must be a vector");
+
+  llvm::Type *SrcTy = Src->getType();
+  llvm::Type *DstTy = ConvertType(DstType);
+
+  // Ignore conversions like int -> uint.
+  if (SrcTy == DstTy)
+    return Src;
+
+  QualType SrcEltType = SrcType->getAs<VectorType>()->getElementType(),
+           DstEltType = DstType->getAs<VectorType>()->getElementType();
+
+  assert(SrcTy->isVectorTy() &&
+         "ConvertVector source IR type must be a vector");
+  assert(DstTy->isVectorTy() &&
+         "ConvertVector destination IR type must be a vector");
+
+  llvm::Type *SrcEltTy = SrcTy->getVectorElementType(),
+             *DstEltTy = DstTy->getVectorElementType();
+
+  if (DstEltType->isBooleanType()) {
+    assert((SrcEltTy->isFloatingPointTy() ||
+            isa<llvm::IntegerType>(SrcEltTy)) && "Unknown boolean conversion");
+
+    llvm::Value *Zero = llvm::Constant::getNullValue(SrcTy);
+    if (SrcEltTy->isFloatingPointTy()) {
+      return Builder.CreateFCmpUNE(Src, Zero, "tobool");
+    } else {
+      return Builder.CreateICmpNE(Src, Zero, "tobool");
+    }
+  }
+
+  // We have the arithmetic types: real int/float.
+  Value *Res = NULL;
+
+  if (isa<llvm::IntegerType>(SrcEltTy)) {
+    bool InputSigned = SrcEltType->isSignedIntegerOrEnumerationType();
+    if (isa<llvm::IntegerType>(DstEltTy))
+      Res = Builder.CreateIntCast(Src, DstTy, InputSigned, "conv");
+    else if (InputSigned)
+      Res = Builder.CreateSIToFP(Src, DstTy, "conv");
+    else
+      Res = Builder.CreateUIToFP(Src, DstTy, "conv");
+  } else if (isa<llvm::IntegerType>(DstEltTy)) {
+    assert(SrcEltTy->isFloatingPointTy() && "Unknown real conversion");
+    if (DstEltType->isSignedIntegerOrEnumerationType())
+      Res = Builder.CreateFPToSI(Src, DstTy, "conv");
+    else
+      Res = Builder.CreateFPToUI(Src, DstTy, "conv");
+  } else {
+    assert(SrcEltTy->isFloatingPointTy() && DstEltTy->isFloatingPointTy() &&
+           "Unknown real conversion");
+    if (DstEltTy->getTypeID() < SrcEltTy->getTypeID())
+      Res = Builder.CreateFPTrunc(Src, DstTy, "conv");
+    else
+      Res = Builder.CreateFPExt(Src, DstTy, "conv");
+  }
+
+  return Res;
+}
+
 Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) {
   llvm::APSInt Value;
   if (E->EvaluateAsInt(Value, CGF.getContext(), Expr::SE_AllowSideEffects)) {
index 07d8ba5a904111bf6bcedd03a7e8e9986538e845..bbc7dadde8f3a2747062f8b148f40f2a7df4bed4 100644 (file)
@@ -888,6 +888,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
   case tok::kw___builtin_offsetof:
   case tok::kw___builtin_choose_expr:
   case tok::kw___builtin_astype: // primary-expression: [OCL] as_type()
+  case tok::kw___builtin_convertvector:
     return ParseBuiltinPrimaryExpression();
   case tok::kw___null:
     return Actions.ActOnGNUNullExpr(ConsumeToken());
@@ -1918,6 +1919,34 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
                                   ConsumeParen());
     break;
   }
+  case tok::kw___builtin_convertvector: {
+    // The first argument is an expression to be converted, followed by a comma.
+    ExprResult Expr(ParseAssignmentExpression());
+    if (Expr.isInvalid()) {
+      SkipUntil(tok::r_paren);
+      return ExprError();
+    }
+    
+    if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", 
+                         tok::r_paren))
+      return ExprError();
+    
+    // Second argument is the type to bitcast to.
+    TypeResult DestTy = ParseTypeName();
+    if (DestTy.isInvalid())
+      return ExprError();
+    
+    // Attempt to consume the r-paren.
+    if (Tok.isNot(tok::r_paren)) {
+      Diag(Tok, diag::err_expected_rparen);
+      SkipUntil(tok::r_paren);
+      return ExprError();
+    }
+    
+    Res = Actions.ActOnConvertVectorExpr(Expr.take(), DestTy.get(), StartLoc, 
+                                         ConsumeParen());
+    break;
+  }
   }
 
   if (Res.isInvalid())
index cba5ffe5fa43d64a649a9fe78a9f7a54857436fe..a4fb3cfa45c0df4b7d6b827be5d70783e3832d7b 100644 (file)
@@ -1818,6 +1818,37 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
                                             TheCall->getRParenLoc()));
 }
 
+/// SemaConvertVectorExpr - Handle __builtin_convertvector
+ExprResult Sema::SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
+                                       SourceLocation BuiltinLoc,
+                                       SourceLocation RParenLoc) {
+  ExprValueKind VK = VK_RValue;
+  ExprObjectKind OK = OK_Ordinary;
+  QualType DstTy = TInfo->getType();
+  QualType SrcTy = E->getType();
+
+  if (!SrcTy->isVectorType() && !SrcTy->isDependentType())
+    return ExprError(Diag(BuiltinLoc,
+                          diag::err_convertvector_non_vector)
+                     << E->getSourceRange());
+  if (!DstTy->isVectorType() && !DstTy->isDependentType())
+    return ExprError(Diag(BuiltinLoc,
+                          diag::err_convertvector_non_vector_type));
+
+  if (!SrcTy->isDependentType() && !DstTy->isDependentType()) {
+    unsigned SrcElts = SrcTy->getAs<VectorType>()->getNumElements();
+    unsigned DstElts = DstTy->getAs<VectorType>()->getNumElements();
+    if (SrcElts != DstElts)
+      return ExprError(Diag(BuiltinLoc,
+                            diag::err_convertvector_incompatible_vector)
+                       << E->getSourceRange());
+  }
+
+  return Owned(new (Context) ConvertVectorExpr(E, TInfo, DstTy, VK, OK,
+               BuiltinLoc, RParenLoc));
+
+}
+
 /// SemaBuiltinPrefetch - Handle __builtin_prefetch.
 // This is declared to take (const void*, ...) and can take two
 // optional constant int args.
index 0d662c8f393bf11e93a4a412f866a634a26371fa..3e8f324027dc924a4e2660cbd4070ea8ca7b0b6e 100644 (file)
@@ -995,6 +995,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
   case Expr::ParenExprClass:
   case Expr::ParenListExprClass:
   case Expr::ShuffleVectorExprClass:
+  case Expr::ConvertVectorExprClass:
   case Expr::VAArgExprClass:
     return canSubExprsThrow(*this, E);
 
index 10d384b8d83e6f4bc8a387ec8bb9d8930766d45e..d68bdbb425c32c760efa6cc647e96ca4bf927bca 100644 (file)
@@ -4463,6 +4463,19 @@ ExprResult Sema::ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy,
                RParenLoc));
 }
 
+/// ActOnConvertVectorExpr - create a new convert-vector expression from the
+/// provided arguments.
+///
+/// __builtin_convertvector( value, dst type )
+///
+ExprResult Sema::ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy,
+                                        SourceLocation BuiltinLoc,
+                                        SourceLocation RParenLoc) {
+  TypeSourceInfo *TInfo;
+  GetTypeFromParser(ParsedDestTy, &TInfo);
+  return SemaConvertVectorExpr(E, TInfo, BuiltinLoc, RParenLoc);
+}
+
 /// BuildResolvedCallExpr - Build a call to a resolved expression,
 /// i.e. an expression not of \p OverloadTy.  The expression should
 /// unary-convert to an expression of function-pointer or
index 008e1eafe44e8f361b5dda8dea96f44bd1accd41..b91c73b075be6466686be09094b8c33d546b4d50 100644 (file)
@@ -2546,6 +2546,14 @@ public:
     return SemaRef.SemaBuiltinShuffleVector(cast<CallExpr>(TheCall.take()));
   }
 
+  /// \brief Build a new convert vector expression.
+  ExprResult RebuildConvertVectorExpr(SourceLocation BuiltinLoc,
+                                      Expr *SrcExpr, TypeSourceInfo *DstTInfo,
+                                      SourceLocation RParenLoc) {
+    return SemaRef.SemaConvertVectorExpr(SrcExpr, DstTInfo,
+                                         BuiltinLoc, RParenLoc);
+  }
+
   /// \brief Build a new template argument pack expansion.
   ///
   /// By default, performs semantic analysis to build a new pack expansion
@@ -9164,6 +9172,27 @@ TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) {
                                                E->getRParenLoc());
 }
 
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformConvertVectorExpr(ConvertVectorExpr *E) {
+  ExprResult SrcExpr = getDerived().TransformExpr(E->getSrcExpr());
+  if (SrcExpr.isInvalid())
+    return ExprError();
+
+  TypeSourceInfo *Type = getDerived().TransformType(E->getTypeSourceInfo());
+  if (!Type)
+    return ExprError();
+
+  if (!getDerived().AlwaysRebuild() &&
+      Type == E->getTypeSourceInfo() &&
+      SrcExpr.get() == E->getSrcExpr())
+    return SemaRef.Owned(E);
+
+  return getDerived().RebuildConvertVectorExpr(E->getBuiltinLoc(),
+                                               SrcExpr.get(), Type,
+                                               E->getRParenLoc());
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
index 35df2521145bbffc5c482dd7050d816544a071bf..23cd9cc726bd699c7e5503dc2946f3cc874eb784 100644 (file)
@@ -854,6 +854,14 @@ void ASTStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
   E->setRParenLoc(ReadSourceLocation(Record, Idx));
 }
 
+void ASTStmtReader::VisitConvertVectorExpr(ConvertVectorExpr *E) {
+  VisitExpr(E);
+  E->BuiltinLoc = ReadSourceLocation(Record, Idx);
+  E->RParenLoc = ReadSourceLocation(Record, Idx);
+  E->TInfo = GetTypeSourceInfo(Record, Idx);
+  E->SrcExpr = Reader.ReadSubExpr();
+}
+
 void ASTStmtReader::VisitBlockExpr(BlockExpr *E) {
   VisitExpr(E);
   E->setBlockDecl(ReadDeclAs<BlockDecl>(Record, Idx));
@@ -2104,6 +2112,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
       S = new (Context) ShuffleVectorExpr(Empty);
       break;
 
+    case EXPR_CONVERT_VECTOR:
+      S = new (Context) ConvertVectorExpr(Empty);
+      break;
+
     case EXPR_BLOCK:
       S = new (Context) BlockExpr(Empty);
       break;
index ee328e2351a60666654a3a14cef444a580621601..d527fcd382d6b8737d8684960fd904cbdf59b0d5 100644 (file)
@@ -794,6 +794,15 @@ void ASTStmtWriter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
   Code = serialization::EXPR_SHUFFLE_VECTOR;
 }
 
+void ASTStmtWriter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
+  VisitExpr(E);
+  Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+  Writer.AddSourceLocation(E->getRParenLoc(), Record);
+  Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record);
+  Writer.AddStmt(E->getSrcExpr());
+  Code = serialization::EXPR_CONVERT_VECTOR;
+}
+
 void ASTStmtWriter::VisitBlockExpr(BlockExpr *E) {
   VisitExpr(E);
   Writer.AddDeclRef(E->getBlockDecl(), Record);
index 16369f0a2b791656451fea87fd5abbb4348b6b9b..52d22edc93e8bd5a8bc2cb6a4f80b4c612ffe8d7 100644 (file)
@@ -726,6 +726,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
     case Stmt::ParenListExprClass:
     case Stmt::PredefinedExprClass:
     case Stmt::ShuffleVectorExprClass:
+    case Stmt::ConvertVectorExprClass:
     case Stmt::VAArgExprClass:
     case Stmt::CUDAKernelCallExprClass:
     case Stmt::OpaqueValueExprClass:
diff --git a/test/CodeGen/convertvector.c b/test/CodeGen/convertvector.c
new file mode 100644 (file)
index 0000000..2b23dd9
--- /dev/null
@@ -0,0 +1,114 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -target-cpu corei7-avx -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -target-cpu corei7-avx -emit-llvm -x c++ %s -o - | FileCheck %s
+
+typedef double vector8double __attribute__((__vector_size__(64)));
+typedef float  vector8float  __attribute__((__vector_size__(32)));
+typedef long   vector8long   __attribute__((__vector_size__(64)));
+typedef short  vector8short  __attribute__((__vector_size__(16)));
+typedef unsigned long   vector8ulong   __attribute__((__vector_size__(64)));
+typedef unsigned short  vector8ushort  __attribute__((__vector_size__(16)));
+
+#ifdef __cplusplus
+#define BOOL bool
+#else
+#define BOOL _Bool
+#endif
+
+typedef BOOL vector8bool __attribute__((__ext_vector_type__(8)));
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+vector8float flt_trunc(vector8double x) {
+  return __builtin_convertvector(x, vector8float);
+  // CHECK-LABEL: @flt_trunc
+  // CHECK: fptrunc <8 x double> %{{[^ ]}} to <8 x float>
+}
+
+vector8double flt_ext(vector8float x) {
+  return __builtin_convertvector(x, vector8double);
+  // CHECK-LABEL: @flt_ext
+  // CHECK: fpext <8 x float> %{{[^ ]}} to <8 x double>
+}
+
+vector8bool flt_tobool(vector8float x) {
+  return __builtin_convertvector(x, vector8bool);
+  // CHECK-LABEL: @flt_tobool
+  // CHECK-NOT: fptoui <8 x float> %{{[^ ]}} to <8 x i1>
+  // CHECK: fcmp une <8 x float> %{{[^ ]}}, zeroinitializer
+}
+
+vector8long flt_tosi(vector8float x) {
+  return __builtin_convertvector(x, vector8long);
+  // CHECK-LABEL: @flt_tosi
+  // CHECK: fptosi <8 x float> %{{[^ ]}} to <8 x i64>
+}
+
+vector8ulong flt_toui(vector8float x) {
+  return __builtin_convertvector(x, vector8ulong);
+  // CHECK-LABEL: @flt_toui
+  // CHECK: fptoui <8 x float> %{{[^ ]}} to <8 x i64>
+}
+
+vector8ulong fltd_toui(vector8double x) {
+  return __builtin_convertvector(x, vector8ulong);
+  // CHECK-LABEL: @fltd_toui
+  // CHECK: fptoui <8 x double> %{{[^ ]}} to <8 x i64>
+}
+
+vector8ulong int_zext(vector8ushort x) {
+  return __builtin_convertvector(x, vector8ulong);
+  // CHECK-LABEL: @int_zext
+  // CHECK: zext <8 x i16> %{{[^ ]}} to <8 x i64>
+}
+
+vector8long int_sext(vector8short x) {
+  return __builtin_convertvector(x, vector8long);
+  // CHECK-LABEL: @int_sext
+  // CHECK: sext <8 x i16> %{{[^ ]}} to <8 x i64>
+}
+
+vector8bool int_tobool(vector8short x) {
+  return __builtin_convertvector(x, vector8bool);
+  // CHECK-LABEL: @int_tobool
+  // CHECK-NOT: trunc <8 x i16> %{{[^ ]}} to <8 x i1>
+  // CHECK: icmp ne <8 x i16> %{{[^ ]}}, zeroinitializer
+}
+
+vector8float int_tofp(vector8short x) {
+  return __builtin_convertvector(x, vector8float);
+  // CHECK-LABEL: @int_tofp
+  // CHECK: sitofp <8 x i16> %{{[^ ]}} to <8 x float>
+}
+
+vector8float uint_tofp(vector8ushort x) {
+  return __builtin_convertvector(x, vector8float);
+  // CHECK-LABEL: @uint_tofp
+  // CHECK: uitofp <8 x i16> %{{[^ ]}} to <8 x float>
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#ifdef __cplusplus
+template<typename T>
+T int_toT(vector8long x) {
+  return __builtin_convertvector(x, T);
+}
+
+extern "C" {
+  vector8double int_toT_fp(vector8long x) {
+    // CHECK-LABEL: @int_toT_fp
+    // CHECK: sitofp <8 x i64> %{{[^ ]}} to <8 x double>
+    return int_toT<vector8double>(x);
+  }
+}
+#else
+vector8double int_toT_fp(vector8long x) {
+  return __builtin_convertvector(x, vector8double);
+}
+#endif
+
index d08b1f64edec82b02315e0d0771f2c5a457380c0..d6735a727a538ddafde79ad2f34d03472f7db2ca 100644 (file)
@@ -102,6 +102,10 @@ typedef typeof(__builtin_choose_expr(17 > 19, d0, 1)) choose_expr;
 // ShuffleVectorExpr
 typedef typeof(__builtin_shufflevector(vec2, vec2b, 2, 1)) shuffle_expr;
 
+// ConvertVectorExpr
+typedef __attribute__(( ext_vector_type(2) )) float float2;
+typedef typeof(__builtin_convertvector(vec2, float2)) convert_expr;
+
 // GenericSelectionExpr
 typedef typeof(_Generic(i, char*: 0, int: 0., default: hello))
   generic_selection_expr;
index 19d80468ab3f624b018093c8f624dce8e70276e4..5a2c300e6ee182e325b099b2c170564cbbf76df6 100644 (file)
@@ -11,6 +11,7 @@
 
 #if  !__has_builtin(__builtin_huge_val) || \
      !__has_builtin(__builtin_shufflevector) || \
+     !__has_builtin(__builtin_convertvector) || \
      !__has_builtin(__builtin_trap) || \
      !__has_builtin(__c11_atomic_init) || \
      !__has_feature(attribute_analyzer_noreturn) || \
diff --git a/test/Sema/convertvector.c b/test/Sema/convertvector.c
new file mode 100644 (file)
index 0000000..ccdd87f
--- /dev/null
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef double vector4double __attribute__((__vector_size__(32)));
+typedef float  vector8float  __attribute__((__vector_size__(32)));
+
+vector8float foo1(vector4double x) {
+  return __builtin_convertvector(x, vector8float);  // expected-error {{same number of elements}}
+}
+
+float foo2(vector4double x) {
+  return __builtin_convertvector(x, float);  // expected-error {{must be a vector type}}
+}
+
+vector8float foo3(double x) {
+  return __builtin_convertvector(x, vector8float);  // expected-error {{must be a vector}}
+}
+
index b80ea4ee4ff1f800a9226c121586af5b675a0db1..5aab94403d4fa5d40f777a5d5528c222b9e0533f 100644 (file)
@@ -233,6 +233,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
   case Stmt::ParenListExprClass:
   case Stmt::PredefinedExprClass:
   case Stmt::ShuffleVectorExprClass:
+  case Stmt::ConvertVectorExprClass:
   case Stmt::UnaryExprOrTypeTraitExprClass:
   case Stmt::UnaryTypeTraitExprClass:
   case Stmt::VAArgExprClass:
index 4d2b3a98409672a3cc57b42b7e1c017be82ab617..b8e66d481b4fefbe95b43adde5e475b37c0d326e 100644 (file)
@@ -2239,6 +2239,7 @@ DEF_TRAVERSE_STMT(ParenExpr, { })
 DEF_TRAVERSE_STMT(ParenListExpr, { })
 DEF_TRAVERSE_STMT(PredefinedExpr, { })
 DEF_TRAVERSE_STMT(ShuffleVectorExpr, { })
+DEF_TRAVERSE_STMT(ConvertVectorExpr, { })
 DEF_TRAVERSE_STMT(StmtExpr, { })
 DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
   TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));