summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/LanguageExtensions.rst44
-rw-r--r--include/clang/AST/Expr.h54
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h1
-rw-r--r--include/clang/Basic/Builtins.def1
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td7
-rw-r--r--include/clang/Basic/StmtNodes.td1
-rw-r--r--include/clang/Basic/TokenKinds.def1
-rw-r--r--include/clang/Sema/Sema.h10
-rw-r--r--include/clang/Serialization/ASTBitCodes.h2
-rw-r--r--lib/AST/Expr.cpp1
-rw-r--r--lib/AST/ExprClassification.cpp1
-rw-r--r--lib/AST/ExprConstant.cpp1
-rw-r--r--lib/AST/ItaniumMangle.cpp1
-rw-r--r--lib/AST/StmtPrinter.cpp8
-rw-r--r--lib/AST/StmtProfile.cpp4
-rw-r--r--lib/CodeGen/CGExprScalar.cpp76
-rw-r--r--lib/Parse/ParseExpr.cpp29
-rw-r--r--lib/Sema/SemaChecking.cpp31
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp1
-rw-r--r--lib/Sema/SemaExpr.cpp13
-rw-r--r--lib/Sema/TreeTransform.h29
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp12
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp9
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp1
-rw-r--r--test/CodeGen/convertvector.c114
-rw-r--r--test/PCH/exprs.h4
-rw-r--r--test/Preprocessor/feature_tests.c1
-rw-r--r--test/Sema/convertvector.c17
-rw-r--r--tools/libclang/CXCursor.cpp1
-rw-r--r--tools/libclang/RecursiveASTVisitor.h1
30 files changed, 476 insertions, 0 deletions
diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst
index 44f2f8dbea..f6a7a4e431 100644
--- a/docs/LanguageExtensions.rst
+++ b/docs/LanguageExtensions.rst
@@ -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``
-------------------------
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index e82d6bb05f..8a884c0b2e 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -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:
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 46adcda6e0..ac6ea67594 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -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()));
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index cb7613ce12..83f00bb1c7 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -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
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index af5c6f6099..f53ca666d5 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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">;
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index 0da9b34028..69851a9d52 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -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>;
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 3f156a86a2..d763632164 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -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)
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 573f028019..5d0f081391 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -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);
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index b1e5e72ae5..03d905054a 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -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.
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index ea91fbec4f..a3a36da65f 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -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;
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index 1c91af7d47..4640d7d37d 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -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:
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 8ca33cbd20..0fb6d42761 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -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:
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index a87bf1123e..3b32bdfb2b 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -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:
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 98b56bcbc7..ee3852a3e9 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -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());
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 77c34c41aa..9591127b8a 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -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);
}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 287dc6c023..57f102f293 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -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)) {
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 07d8ba5a90..bbc7dadde8 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -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())
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index cba5ffe5fa..a4fb3cfa45 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -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.
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 0d662c8f39..3e8f324027 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -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);
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 10d384b8d8..d68bdbb425 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -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
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 008e1eafe4..b91c73b075 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -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
@@ -9166,6 +9174,27 @@ TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) {
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) {
BlockDecl *oldBlock = E->getBlockDecl();
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 35df252114..23cd9cc726 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -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;
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index ee328e2351..d527fcd382 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -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);
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 16369f0a2b..52d22edc93 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -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
index 0000000000..2b23dd96e1
--- /dev/null
+++ b/test/CodeGen/convertvector.c
@@ -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
+
diff --git a/test/PCH/exprs.h b/test/PCH/exprs.h
index d08b1f64ed..d6735a727a 100644
--- a/test/PCH/exprs.h
+++ b/test/PCH/exprs.h
@@ -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;
diff --git a/test/Preprocessor/feature_tests.c b/test/Preprocessor/feature_tests.c
index 19d80468ab..5a2c300e6e 100644
--- a/test/Preprocessor/feature_tests.c
+++ b/test/Preprocessor/feature_tests.c
@@ -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
index 0000000000..ccdd87f9e4
--- /dev/null
+++ b/test/Sema/convertvector.c
@@ -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}}
+}
+
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index b80ea4ee4f..5aab94403d 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -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:
diff --git a/tools/libclang/RecursiveASTVisitor.h b/tools/libclang/RecursiveASTVisitor.h
index 4d2b3a9840..b8e66d481b 100644
--- a/tools/libclang/RecursiveASTVisitor.h
+++ b/tools/libclang/RecursiveASTVisitor.h
@@ -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()));